mirror of
https://activitypub.software/TransFem-org/Sharkey
synced 2024-12-22 16:30:13 +00:00
refactor: introduce bindThis decorator to bind this automaticaly
This commit is contained in:
parent
e73581f715
commit
bbb49457f9
199 changed files with 969 additions and 96 deletions
|
@ -7,6 +7,7 @@ import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
||||||
import { RelayService } from '@/core/RelayService.js';
|
import { RelayService } from '@/core/RelayService.js';
|
||||||
import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerService.js';
|
import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerService.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AccountUpdateService {
|
export class AccountUpdateService {
|
||||||
|
@ -24,6 +25,7 @@ export class AccountUpdateService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async publishToFollowers(userId: User['id']) {
|
public async publishToFollowers(userId: User['id']) {
|
||||||
const user = await this.usersRepository.findOneBy({ id: userId });
|
const user = await this.usersRepository.findOneBy({ id: userId });
|
||||||
if (user == null) throw new Error('user not found');
|
if (user == null) throw new Error('user not found');
|
||||||
|
|
|
@ -12,6 +12,7 @@ const _dirname = dirname(_filename);
|
||||||
|
|
||||||
const REQUIRED_CPU_FLAGS = ['avx2', 'fma'];
|
const REQUIRED_CPU_FLAGS = ['avx2', 'fma'];
|
||||||
let isSupportedCpu: undefined | boolean = undefined;
|
let isSupportedCpu: undefined | boolean = undefined;
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AiService {
|
export class AiService {
|
||||||
|
@ -23,6 +24,7 @@ export class AiService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async detectSensitive(path: string): Promise<nsfw.predictionType[] | null> {
|
public async detectSensitive(path: string): Promise<nsfw.predictionType[] | null> {
|
||||||
try {
|
try {
|
||||||
if (isSupportedCpu === undefined) {
|
if (isSupportedCpu === undefined) {
|
||||||
|
@ -53,6 +55,7 @@ export class AiService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async getCpuFlags(): Promise<string[]> {
|
private async getCpuFlags(): Promise<string[]> {
|
||||||
const str = await si.cpuFlags();
|
const str = await si.cpuFlags();
|
||||||
return str.split(/\s+/);
|
return str.split(/\s+/);
|
||||||
|
|
|
@ -13,6 +13,7 @@ import { DI } from '@/di-symbols.js';
|
||||||
import type { MutingsRepository, BlockingsRepository, NotesRepository, AntennaNotesRepository, AntennasRepository, UserGroupJoiningsRepository, UserListJoiningsRepository } from '@/models/index.js';
|
import type { MutingsRepository, BlockingsRepository, NotesRepository, AntennaNotesRepository, AntennasRepository, UserGroupJoiningsRepository, UserListJoiningsRepository } from '@/models/index.js';
|
||||||
import { UtilityService } from '@/core/UtilityService.js';
|
import { UtilityService } from '@/core/UtilityService.js';
|
||||||
import type { OnApplicationShutdown } from '@nestjs/common';
|
import type { OnApplicationShutdown } from '@nestjs/common';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AntennaService implements OnApplicationShutdown {
|
export class AntennaService implements OnApplicationShutdown {
|
||||||
|
@ -56,10 +57,12 @@ export class AntennaService implements OnApplicationShutdown {
|
||||||
this.redisSubscriber.on('message', this.onRedisMessage);
|
this.redisSubscriber.on('message', this.onRedisMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public onApplicationShutdown(signal?: string | undefined) {
|
public onApplicationShutdown(signal?: string | undefined) {
|
||||||
this.redisSubscriber.off('message', this.onRedisMessage);
|
this.redisSubscriber.off('message', this.onRedisMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async onRedisMessage(_: string, data: string): Promise<void> {
|
private async onRedisMessage(_: string, data: string): Promise<void> {
|
||||||
const obj = JSON.parse(data);
|
const obj = JSON.parse(data);
|
||||||
|
|
||||||
|
@ -81,6 +84,7 @@ export class AntennaService implements OnApplicationShutdown {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async addNoteToAntenna(antenna: Antenna, note: Note, noteUser: { id: User['id']; }): Promise<void> {
|
public async addNoteToAntenna(antenna: Antenna, note: Note, noteUser: { id: User['id']; }): Promise<void> {
|
||||||
// 通知しない設定になっているか、自分自身の投稿なら既読にする
|
// 通知しない設定になっているか、自分自身の投稿なら既読にする
|
||||||
const read = !antenna.notify || (antenna.userId === noteUser.id);
|
const read = !antenna.notify || (antenna.userId === noteUser.id);
|
||||||
|
@ -133,6 +137,7 @@ export class AntennaService implements OnApplicationShutdown {
|
||||||
/**
|
/**
|
||||||
* noteUserFollowers / antennaUserFollowing はどちらか一方が指定されていればよい
|
* noteUserFollowers / antennaUserFollowing はどちらか一方が指定されていればよい
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async checkHitAntenna(antenna: Antenna, note: (Note | Packed<'Note'>), noteUser: { id: User['id']; username: string; host: string | null; }, noteUserFollowers?: User['id'][], antennaUserFollowing?: User['id'][]): Promise<boolean> {
|
public async checkHitAntenna(antenna: Antenna, note: (Note | Packed<'Note'>), noteUser: { id: User['id']; username: string; host: string | null; }, noteUserFollowers?: User['id'][], antennaUserFollowing?: User['id'][]): Promise<boolean> {
|
||||||
if (note.visibility === 'specified') return false;
|
if (note.visibility === 'specified') return false;
|
||||||
|
|
||||||
|
@ -217,6 +222,7 @@ export class AntennaService implements OnApplicationShutdown {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async getAntennas() {
|
public async getAntennas() {
|
||||||
if (!this.antennasFetched) {
|
if (!this.antennasFetched) {
|
||||||
this.antennas = await this.antennasRepository.find();
|
this.antennas = await this.antennasRepository.find();
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { DI } from '@/di-symbols.js';
|
||||||
* Retry delay (ms) for lock acquisition
|
* Retry delay (ms) for lock acquisition
|
||||||
*/
|
*/
|
||||||
const retryDelay = 100;
|
const retryDelay = 100;
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AppLockService {
|
export class AppLockService {
|
||||||
|
@ -26,14 +27,17 @@ export class AppLockService {
|
||||||
* @param timeout Lock timeout (ms), The timeout releases previous lock.
|
* @param timeout Lock timeout (ms), The timeout releases previous lock.
|
||||||
* @returns Unlock function
|
* @returns Unlock function
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public getApLock(uri: string, timeout = 30 * 1000): Promise<() => void> {
|
public getApLock(uri: string, timeout = 30 * 1000): Promise<() => void> {
|
||||||
return this.lock(`ap-object:${uri}`, timeout);
|
return this.lock(`ap-object:${uri}`, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public getFetchInstanceMetadataLock(host: string, timeout = 30 * 1000): Promise<() => void> {
|
public getFetchInstanceMetadataLock(host: string, timeout = 30 * 1000): Promise<() => void> {
|
||||||
return this.lock(`instance:${host}`, timeout);
|
return this.lock(`instance:${host}`, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public getChartInsertLock(lockKey: string, timeout = 30 * 1000): Promise<() => void> {
|
public getChartInsertLock(lockKey: string, timeout = 30 * 1000): Promise<() => void> {
|
||||||
return this.lock(`chart-insert:${lockKey}`, timeout);
|
return this.lock(`chart-insert:${lockKey}`, timeout);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { DI } from '@/di-symbols.js';
|
||||||
import type { UsersRepository } from '@/models/index.js';
|
import type { UsersRepository } from '@/models/index.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
type CaptchaResponse = {
|
type CaptchaResponse = {
|
||||||
success: boolean;
|
success: boolean;
|
||||||
|
@ -19,6 +20,7 @@ export class CaptchaService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async getCaptchaResponse(url: string, secret: string, response: string): Promise<CaptchaResponse> {
|
private async getCaptchaResponse(url: string, secret: string, response: string): Promise<CaptchaResponse> {
|
||||||
const params = new URLSearchParams({
|
const params = new URLSearchParams({
|
||||||
secret,
|
secret,
|
||||||
|
@ -45,6 +47,7 @@ export class CaptchaService {
|
||||||
return await res.json() as CaptchaResponse;
|
return await res.json() as CaptchaResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async verifyRecaptcha(secret: string, response: string | null | undefined): Promise<void> {
|
public async verifyRecaptcha(secret: string, response: string | null | undefined): Promise<void> {
|
||||||
if (response == null) {
|
if (response == null) {
|
||||||
throw 'recaptcha-failed: no response provided';
|
throw 'recaptcha-failed: no response provided';
|
||||||
|
@ -60,6 +63,7 @@ export class CaptchaService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async verifyHcaptcha(secret: string, response: string | null | undefined): Promise<void> {
|
public async verifyHcaptcha(secret: string, response: string | null | undefined): Promise<void> {
|
||||||
if (response == null) {
|
if (response == null) {
|
||||||
throw 'hcaptcha-failed: no response provided';
|
throw 'hcaptcha-failed: no response provided';
|
||||||
|
@ -75,6 +79,7 @@ export class CaptchaService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async verifyTurnstile(secret: string, response: string | null | undefined): Promise<void> {
|
public async verifyTurnstile(secret: string, response: string | null | undefined): Promise<void> {
|
||||||
if (response == null) {
|
if (response == null) {
|
||||||
throw 'turnstile-failed: no response provided';
|
throw 'turnstile-failed: no response provided';
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { IdService } from '@/core/IdService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { NotificationEntityService } from '@/core/entities/NotificationEntityService.js';
|
import { NotificationEntityService } from '@/core/entities/NotificationEntityService.js';
|
||||||
import { PushNotificationService } from '@/core/PushNotificationService.js';
|
import { PushNotificationService } from '@/core/PushNotificationService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CreateNotificationService {
|
export class CreateNotificationService {
|
||||||
|
@ -30,6 +31,7 @@ export class CreateNotificationService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async createNotification(
|
public async createNotification(
|
||||||
notifieeId: User['id'],
|
notifieeId: User['id'],
|
||||||
type: Notification['type'],
|
type: Notification['type'],
|
||||||
|
@ -90,6 +92,7 @@ export class CreateNotificationService {
|
||||||
|
|
||||||
// TODO: locale ファイルをクライアント用とサーバー用で分けたい
|
// TODO: locale ファイルをクライアント用とサーバー用で分けたい
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async emailNotificationFollow(userId: User['id'], follower: User) {
|
private async emailNotificationFollow(userId: User['id'], follower: User) {
|
||||||
/*
|
/*
|
||||||
const userProfile = await UserProfiles.findOneByOrFail({ userId: userId });
|
const userProfile = await UserProfiles.findOneByOrFail({ userId: userId });
|
||||||
|
@ -101,6 +104,7 @@ export class CreateNotificationService {
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async emailNotificationReceiveFollowRequest(userId: User['id'], follower: User) {
|
private async emailNotificationReceiveFollowRequest(userId: User['id'], follower: User) {
|
||||||
/*
|
/*
|
||||||
const userProfile = await UserProfiles.findOneByOrFail({ userId: userId });
|
const userProfile = await UserProfiles.findOneByOrFail({ userId: userId });
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { UserKeypair } from '@/models/entities/UserKeypair.js';
|
||||||
import { UsedUsername } from '@/models/entities/UsedUsername.js';
|
import { UsedUsername } from '@/models/entities/UsedUsername.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import generateNativeUserToken from '@/misc/generate-native-user-token.js';
|
import generateNativeUserToken from '@/misc/generate-native-user-token.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CreateSystemUserService {
|
export class CreateSystemUserService {
|
||||||
|
@ -21,6 +22,7 @@ export class CreateSystemUserService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async createSystemUser(username: string): Promise<User> {
|
public async createSystemUser(username: string): Promise<User> {
|
||||||
const password = uuid();
|
const password = uuid();
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ type PopulatedEmoji = {
|
||||||
name: string;
|
name: string;
|
||||||
url: string;
|
url: string;
|
||||||
};
|
};
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CustomEmojiService {
|
export class CustomEmojiService {
|
||||||
|
@ -43,6 +44,7 @@ export class CustomEmojiService {
|
||||||
this.cache = new Cache<Emoji | null>(1000 * 60 * 60 * 12);
|
this.cache = new Cache<Emoji | null>(1000 * 60 * 60 * 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async add(data: {
|
public async add(data: {
|
||||||
driveFile: DriveFile;
|
driveFile: DriveFile;
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -67,6 +69,7 @@ export class CustomEmojiService {
|
||||||
return emoji;
|
return emoji;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private normalizeHost(src: string | undefined, noteUserHost: string | null): string | null {
|
private normalizeHost(src: string | undefined, noteUserHost: string | null): string | null {
|
||||||
// クエリに使うホスト
|
// クエリに使うホスト
|
||||||
let host = src === '.' ? null // .はローカルホスト (ここがマッチするのはリアクションのみ)
|
let host = src === '.' ? null // .はローカルホスト (ここがマッチするのはリアクションのみ)
|
||||||
|
@ -79,6 +82,7 @@ export class CustomEmojiService {
|
||||||
return host;
|
return host;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private parseEmojiStr(emojiName: string, noteUserHost: string | null) {
|
private parseEmojiStr(emojiName: string, noteUserHost: string | null) {
|
||||||
const match = emojiName.match(/^(\w+)(?:@([\w.-]+))?$/);
|
const match = emojiName.match(/^(\w+)(?:@([\w.-]+))?$/);
|
||||||
if (!match) return { name: null, host: null };
|
if (!match) return { name: null, host: null };
|
||||||
|
@ -97,6 +101,7 @@ export class CustomEmojiService {
|
||||||
* @param noteUserHost ノートやユーザープロフィールの所有者のホスト
|
* @param noteUserHost ノートやユーザープロフィールの所有者のホスト
|
||||||
* @returns 絵文字情報, nullは未マッチを意味する
|
* @returns 絵文字情報, nullは未マッチを意味する
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async populateEmoji(emojiName: string, noteUserHost: string | null): Promise<PopulatedEmoji | null> {
|
public async populateEmoji(emojiName: string, noteUserHost: string | null): Promise<PopulatedEmoji | null> {
|
||||||
const { name, host } = this.parseEmojiStr(emojiName, noteUserHost);
|
const { name, host } = this.parseEmojiStr(emojiName, noteUserHost);
|
||||||
if (name == null) return null;
|
if (name == null) return null;
|
||||||
|
@ -123,11 +128,13 @@ export class CustomEmojiService {
|
||||||
/**
|
/**
|
||||||
* 複数の添付用絵文字情報を解決する (キャシュ付き, 存在しないものは結果から除外される)
|
* 複数の添付用絵文字情報を解決する (キャシュ付き, 存在しないものは結果から除外される)
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async populateEmojis(emojiNames: string[], noteUserHost: string | null): Promise<PopulatedEmoji[]> {
|
public async populateEmojis(emojiNames: string[], noteUserHost: string | null): Promise<PopulatedEmoji[]> {
|
||||||
const emojis = await Promise.all(emojiNames.map(x => this.populateEmoji(x, noteUserHost)));
|
const emojis = await Promise.all(emojiNames.map(x => this.populateEmoji(x, noteUserHost)));
|
||||||
return emojis.filter((x): x is PopulatedEmoji => x != null);
|
return emojis.filter((x): x is PopulatedEmoji => x != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public aggregateNoteEmojis(notes: Note[]) {
|
public aggregateNoteEmojis(notes: Note[]) {
|
||||||
let emojis: { name: string | null; host: string | null; }[] = [];
|
let emojis: { name: string | null; host: string | null; }[] = [];
|
||||||
for (const note of notes) {
|
for (const note of notes) {
|
||||||
|
@ -154,6 +161,7 @@ export class CustomEmojiService {
|
||||||
/**
|
/**
|
||||||
* 与えられた絵文字のリストをデータベースから取得し、キャッシュに追加します
|
* 与えられた絵文字のリストをデータベースから取得し、キャッシュに追加します
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async prefetchEmojis(emojis: { name: string; host: string | null; }[]): Promise<void> {
|
public async prefetchEmojis(emojis: { name: string; host: string | null; }[]): Promise<void> {
|
||||||
const notCachedEmojis = emojis.filter(emoji => this.cache.get(`${emoji.name} ${emoji.host}`) == null);
|
const notCachedEmojis = emojis.filter(emoji => this.cache.get(`${emoji.name} ${emoji.host}`) == null);
|
||||||
const emojisQuery: any[] = [];
|
const emojisQuery: any[] = [];
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { QueueService } from '@/core/QueueService.js';
|
||||||
import { UserSuspendService } from '@/core/UserSuspendService.js';
|
import { UserSuspendService } from '@/core/UserSuspendService.js';
|
||||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DeleteAccountService {
|
export class DeleteAccountService {
|
||||||
|
@ -17,6 +18,7 @@ export class DeleteAccountService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async deleteAccount(user: {
|
public async deleteAccount(user: {
|
||||||
id: string;
|
id: string;
|
||||||
host: string | null;
|
host: string | null;
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { LoggerService } from '@/core/LoggerService.js';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
|
|
||||||
const pipeline = util.promisify(stream.pipeline);
|
const pipeline = util.promisify(stream.pipeline);
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DownloadService {
|
export class DownloadService {
|
||||||
|
@ -30,6 +31,7 @@ export class DownloadService {
|
||||||
this.logger = this.loggerService.getLogger('download');
|
this.logger = this.loggerService.getLogger('download');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async downloadUrl(url: string, path: string): Promise<void> {
|
public async downloadUrl(url: string, path: string): Promise<void> {
|
||||||
this.logger.info(`Downloading ${chalk.cyan(url)} ...`);
|
this.logger.info(`Downloading ${chalk.cyan(url)} ...`);
|
||||||
|
|
||||||
|
@ -94,6 +96,7 @@ export class DownloadService {
|
||||||
this.logger.succ(`Download finished: ${chalk.cyan(url)}`);
|
this.logger.succ(`Download finished: ${chalk.cyan(url)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async downloadTextFile(url: string): Promise<string> {
|
public async downloadTextFile(url: string): Promise<string> {
|
||||||
// Create temp file
|
// Create temp file
|
||||||
const [path, cleanup] = await createTemp();
|
const [path, cleanup] = await createTemp();
|
||||||
|
@ -112,6 +115,7 @@ export class DownloadService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private isPrivateIp(ip: string): boolean {
|
private isPrivateIp(ip: string): boolean {
|
||||||
for (const net of this.config.allowedPrivateNetworks ?? []) {
|
for (const net of this.config.allowedPrivateNetworks ?? []) {
|
||||||
const cidr = new IPCIDR(net);
|
const cidr = new IPCIDR(net);
|
||||||
|
|
|
@ -71,6 +71,7 @@ type UploadFromUrlArgs = {
|
||||||
requestIp?: string | null;
|
requestIp?: string | null;
|
||||||
requestHeaders?: Record<string, string> | null;
|
requestHeaders?: Record<string, string> | null;
|
||||||
};
|
};
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DriveService {
|
export class DriveService {
|
||||||
|
@ -122,6 +123,7 @@ export class DriveService {
|
||||||
* @param hash Hash for original
|
* @param hash Hash for original
|
||||||
* @param size Size for original
|
* @param size Size for original
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
private async save(file: DriveFile, path: string, name: string, type: string, hash: string, size: number): Promise<DriveFile> {
|
private async save(file: DriveFile, path: string, name: string, type: string, hash: string, size: number): Promise<DriveFile> {
|
||||||
// thunbnail, webpublic を必要なら生成
|
// thunbnail, webpublic を必要なら生成
|
||||||
const alts = await this.generateAlts(path, type, !file.uri);
|
const alts = await this.generateAlts(path, type, !file.uri);
|
||||||
|
@ -242,6 +244,7 @@ export class DriveService {
|
||||||
* @param type Content-Type for original
|
* @param type Content-Type for original
|
||||||
* @param generateWeb Generate webpublic or not
|
* @param generateWeb Generate webpublic or not
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async generateAlts(path: string, type: string, generateWeb: boolean) {
|
public async generateAlts(path: string, type: string, generateWeb: boolean) {
|
||||||
if (type.startsWith('video/')) {
|
if (type.startsWith('video/')) {
|
||||||
try {
|
try {
|
||||||
|
@ -345,6 +348,7 @@ export class DriveService {
|
||||||
/**
|
/**
|
||||||
* Upload to ObjectStorage
|
* Upload to ObjectStorage
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
private async upload(key: string, stream: fs.ReadStream | Buffer, type: string, filename?: string) {
|
private async upload(key: string, stream: fs.ReadStream | Buffer, type: string, filename?: string) {
|
||||||
if (type === 'image/apng') type = 'image/png';
|
if (type === 'image/apng') type = 'image/png';
|
||||||
if (!FILE_TYPE_BROWSERSAFE.includes(type)) type = 'application/octet-stream';
|
if (!FILE_TYPE_BROWSERSAFE.includes(type)) type = 'application/octet-stream';
|
||||||
|
@ -372,6 +376,7 @@ export class DriveService {
|
||||||
if (result) this.registerLogger.debug(`Uploaded: ${result.Bucket}/${result.Key} => ${result.Location}`);
|
if (result) this.registerLogger.debug(`Uploaded: ${result.Bucket}/${result.Key} => ${result.Location}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async deleteOldFile(user: IRemoteUser) {
|
private async deleteOldFile(user: IRemoteUser) {
|
||||||
const q = this.driveFilesRepository.createQueryBuilder('file')
|
const q = this.driveFilesRepository.createQueryBuilder('file')
|
||||||
.where('file.userId = :userId', { userId: user.id })
|
.where('file.userId = :userId', { userId: user.id })
|
||||||
|
@ -398,6 +403,7 @@ export class DriveService {
|
||||||
* Add file to drive
|
* Add file to drive
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async addFile({
|
public async addFile({
|
||||||
user,
|
user,
|
||||||
path,
|
path,
|
||||||
|
@ -601,6 +607,7 @@ export class DriveService {
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async deleteFile(file: DriveFile, isExpired = false) {
|
public async deleteFile(file: DriveFile, isExpired = false) {
|
||||||
if (file.storedInternal) {
|
if (file.storedInternal) {
|
||||||
this.internalStorageService.del(file.accessKey!);
|
this.internalStorageService.del(file.accessKey!);
|
||||||
|
@ -627,6 +634,7 @@ export class DriveService {
|
||||||
this.deletePostProcess(file, isExpired);
|
this.deletePostProcess(file, isExpired);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async deleteFileSync(file: DriveFile, isExpired = false) {
|
public async deleteFileSync(file: DriveFile, isExpired = false) {
|
||||||
if (file.storedInternal) {
|
if (file.storedInternal) {
|
||||||
this.internalStorageService.del(file.accessKey!);
|
this.internalStorageService.del(file.accessKey!);
|
||||||
|
@ -657,6 +665,7 @@ export class DriveService {
|
||||||
this.deletePostProcess(file, isExpired);
|
this.deletePostProcess(file, isExpired);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async deletePostProcess(file: DriveFile, isExpired = false) {
|
private async deletePostProcess(file: DriveFile, isExpired = false) {
|
||||||
// リモートファイル期限切れ削除後は直リンクにする
|
// リモートファイル期限切れ削除後は直リンクにする
|
||||||
if (isExpired && file.userHost !== null && file.uri != null) {
|
if (isExpired && file.userHost !== null && file.uri != null) {
|
||||||
|
@ -683,6 +692,7 @@ export class DriveService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async deleteObjectStorageFile(key: string) {
|
public async deleteObjectStorageFile(key: string) {
|
||||||
const meta = await this.metaService.fetch();
|
const meta = await this.metaService.fetch();
|
||||||
|
|
||||||
|
@ -694,6 +704,7 @@ export class DriveService {
|
||||||
}).promise();
|
}).promise();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async uploadFromUrl({
|
public async uploadFromUrl({
|
||||||
url,
|
url,
|
||||||
user,
|
user,
|
||||||
|
|
|
@ -7,6 +7,7 @@ import type { Config } from '@/config.js';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
import type { UserProfilesRepository } from '@/models/index.js';
|
import type { UserProfilesRepository } from '@/models/index.js';
|
||||||
import { LoggerService } from '@/core/LoggerService.js';
|
import { LoggerService } from '@/core/LoggerService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class EmailService {
|
export class EmailService {
|
||||||
|
@ -25,6 +26,7 @@ export class EmailService {
|
||||||
this.logger = this.loggerService.getLogger('email');
|
this.logger = this.loggerService.getLogger('email');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async sendEmail(to: string, subject: string, html: string, text: string) {
|
public async sendEmail(to: string, subject: string, html: string, text: string) {
|
||||||
const meta = await this.metaService.fetch(true);
|
const meta = await this.metaService.fetch(true);
|
||||||
|
|
||||||
|
@ -141,6 +143,7 @@ export class EmailService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async validateEmailForAccount(emailAddress: string): Promise<{
|
public async validateEmailForAccount(emailAddress: string): Promise<{
|
||||||
available: boolean;
|
available: boolean;
|
||||||
reason: null | 'used' | 'format' | 'disposable' | 'mx' | 'smtp';
|
reason: null | 'used' | 'format' | 'disposable' | 'mx' | 'smtp';
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { Cache } from '@/misc/cache.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { UtilityService } from '@/core/UtilityService.js';
|
import { UtilityService } from '@/core/UtilityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FederatedInstanceService {
|
export class FederatedInstanceService {
|
||||||
|
@ -20,6 +21,7 @@ export class FederatedInstanceService {
|
||||||
this.cache = new Cache<Instance>(1000 * 60 * 60);
|
this.cache = new Cache<Instance>(1000 * 60 * 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async registerOrFetchInstanceDoc(host: string): Promise<Instance> {
|
public async registerOrFetchInstanceDoc(host: string): Promise<Instance> {
|
||||||
host = this.utilityService.toPuny(host);
|
host = this.utilityService.toPuny(host);
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ type NodeInfo = {
|
||||||
themeColor?: unknown;
|
themeColor?: unknown;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FetchInstanceMetadataService {
|
export class FetchInstanceMetadataService {
|
||||||
|
@ -46,6 +47,7 @@ export class FetchInstanceMetadataService {
|
||||||
this.logger = this.loggerService.getLogger('metadata', 'cyan');
|
this.logger = this.loggerService.getLogger('metadata', 'cyan');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async fetchInstanceMetadata(instance: Instance, force = false): Promise<void> {
|
public async fetchInstanceMetadata(instance: Instance, force = false): Promise<void> {
|
||||||
const unlock = await this.appLockService.getFetchInstanceMetadataLock(instance.host);
|
const unlock = await this.appLockService.getFetchInstanceMetadataLock(instance.host);
|
||||||
|
|
||||||
|
@ -105,6 +107,7 @@ export class FetchInstanceMetadataService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async fetchNodeinfo(instance: Instance): Promise<NodeInfo> {
|
private async fetchNodeinfo(instance: Instance): Promise<NodeInfo> {
|
||||||
this.logger.info(`Fetching nodeinfo of ${instance.host} ...`);
|
this.logger.info(`Fetching nodeinfo of ${instance.host} ...`);
|
||||||
|
|
||||||
|
@ -148,6 +151,7 @@ export class FetchInstanceMetadataService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async fetchDom(instance: Instance): Promise<DOMWindow['document']> {
|
private async fetchDom(instance: Instance): Promise<DOMWindow['document']> {
|
||||||
this.logger.info(`Fetching HTML of ${instance.host} ...`);
|
this.logger.info(`Fetching HTML of ${instance.host} ...`);
|
||||||
|
|
||||||
|
@ -161,6 +165,7 @@ export class FetchInstanceMetadataService {
|
||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async fetchManifest(instance: Instance): Promise<Record<string, unknown> | null> {
|
private async fetchManifest(instance: Instance): Promise<Record<string, unknown> | null> {
|
||||||
const url = 'https://' + instance.host;
|
const url = 'https://' + instance.host;
|
||||||
|
|
||||||
|
@ -171,6 +176,7 @@ export class FetchInstanceMetadataService {
|
||||||
return manifest;
|
return manifest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async fetchFaviconUrl(instance: Instance, doc: DOMWindow['document'] | null): Promise<string | null> {
|
private async fetchFaviconUrl(instance: Instance, doc: DOMWindow['document'] | null): Promise<string | null> {
|
||||||
const url = 'https://' + instance.host;
|
const url = 'https://' + instance.host;
|
||||||
|
|
||||||
|
@ -198,6 +204,7 @@ export class FetchInstanceMetadataService {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async fetchIconUrl(instance: Instance, doc: DOMWindow['document'] | null, manifest: Record<string, any> | null): Promise<string | null> {
|
private async fetchIconUrl(instance: Instance, doc: DOMWindow['document'] | null, manifest: Record<string, any> | null): Promise<string | null> {
|
||||||
if (manifest && manifest.icons && manifest.icons.length > 0 && manifest.icons[0].src) {
|
if (manifest && manifest.icons && manifest.icons.length > 0 && manifest.icons[0].src) {
|
||||||
const url = 'https://' + instance.host;
|
const url = 'https://' + instance.host;
|
||||||
|
@ -226,6 +233,7 @@ export class FetchInstanceMetadataService {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async getThemeColor(info: NodeInfo | null, doc: DOMWindow['document'] | null, manifest: Record<string, any> | null): Promise<string | null> {
|
private async getThemeColor(info: NodeInfo | null, doc: DOMWindow['document'] | null, manifest: Record<string, any> | null): Promise<string | null> {
|
||||||
const themeColor = info?.metadata?.themeColor ?? doc?.querySelector('meta[name="theme-color"]')?.getAttribute('content') ?? manifest?.theme_color;
|
const themeColor = info?.metadata?.themeColor ?? doc?.querySelector('meta[name="theme-color"]')?.getAttribute('content') ?? manifest?.theme_color;
|
||||||
|
|
||||||
|
@ -237,6 +245,7 @@ export class FetchInstanceMetadataService {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async getSiteName(info: NodeInfo | null, doc: DOMWindow['document'] | null, manifest: Record<string, any> | null): Promise<string | null> {
|
private async getSiteName(info: NodeInfo | null, doc: DOMWindow['document'] | null, manifest: Record<string, any> | null): Promise<string | null> {
|
||||||
if (info && info.metadata) {
|
if (info && info.metadata) {
|
||||||
if (typeof info.metadata.nodeName === 'string') {
|
if (typeof info.metadata.nodeName === 'string') {
|
||||||
|
@ -261,6 +270,7 @@ export class FetchInstanceMetadataService {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async getDescription(info: NodeInfo | null, doc: DOMWindow['document'] | null, manifest: Record<string, any> | null): Promise<string | null> {
|
private async getDescription(info: NodeInfo | null, doc: DOMWindow['document'] | null, manifest: Record<string, any> | null): Promise<string | null> {
|
||||||
if (info && info.metadata) {
|
if (info && info.metadata) {
|
||||||
if (typeof info.metadata.nodeDescription === 'string') {
|
if (typeof info.metadata.nodeDescription === 'string') {
|
||||||
|
|
|
@ -14,6 +14,7 @@ import sharp from 'sharp';
|
||||||
import { encode } from 'blurhash';
|
import { encode } from 'blurhash';
|
||||||
import { createTempDir } from '@/misc/create-temp.js';
|
import { createTempDir } from '@/misc/create-temp.js';
|
||||||
import { AiService } from '@/core/AiService.js';
|
import { AiService } from '@/core/AiService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
const pipeline = util.promisify(stream.pipeline);
|
const pipeline = util.promisify(stream.pipeline);
|
||||||
|
|
||||||
|
@ -42,6 +43,7 @@ const TYPE_SVG = {
|
||||||
mime: 'image/svg+xml',
|
mime: 'image/svg+xml',
|
||||||
ext: 'svg',
|
ext: 'svg',
|
||||||
};
|
};
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FileInfoService {
|
export class FileInfoService {
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -52,6 +54,7 @@ export class FileInfoService {
|
||||||
/**
|
/**
|
||||||
* Get file information
|
* Get file information
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async getFileInfo(path: string, opts: {
|
public async getFileInfo(path: string, opts: {
|
||||||
skipSensitiveDetection: boolean;
|
skipSensitiveDetection: boolean;
|
||||||
sensitiveThreshold?: number;
|
sensitiveThreshold?: number;
|
||||||
|
@ -135,6 +138,7 @@ export class FileInfoService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async detectSensitivity(source: string, mime: string, sensitiveThreshold: number, sensitiveThresholdForPorn: number, analyzeVideo: boolean): Promise<[sensitive: boolean, porn: boolean]> {
|
private async detectSensitivity(source: string, mime: string, sensitiveThreshold: number, sensitiveThresholdForPorn: number, analyzeVideo: boolean): Promise<[sensitive: boolean, porn: boolean]> {
|
||||||
let sensitive = false;
|
let sensitive = false;
|
||||||
let porn = false;
|
let porn = false;
|
||||||
|
@ -269,6 +273,7 @@ export class FileInfoService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private exists(path: string): Promise<boolean> {
|
private exists(path: string): Promise<boolean> {
|
||||||
return fs.promises.access(path).then(() => true, () => false);
|
return fs.promises.access(path).then(() => true, () => false);
|
||||||
}
|
}
|
||||||
|
@ -276,6 +281,7 @@ export class FileInfoService {
|
||||||
/**
|
/**
|
||||||
* Detect MIME Type and extension
|
* Detect MIME Type and extension
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async detectType(path: string): Promise<{
|
public async detectType(path: string): Promise<{
|
||||||
mime: string;
|
mime: string;
|
||||||
ext: string | null;
|
ext: string | null;
|
||||||
|
@ -312,6 +318,7 @@ export class FileInfoService {
|
||||||
/**
|
/**
|
||||||
* Check the file is SVG or not
|
* Check the file is SVG or not
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async checkSvg(path: string) {
|
public async checkSvg(path: string) {
|
||||||
try {
|
try {
|
||||||
const size = await this.getFileSize(path);
|
const size = await this.getFileSize(path);
|
||||||
|
@ -325,6 +332,7 @@ export class FileInfoService {
|
||||||
/**
|
/**
|
||||||
* Get file size
|
* Get file size
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async getFileSize(path: string): Promise<number> {
|
public async getFileSize(path: string): Promise<number> {
|
||||||
const getStat = util.promisify(fs.stat);
|
const getStat = util.promisify(fs.stat);
|
||||||
return (await getStat(path)).size;
|
return (await getStat(path)).size;
|
||||||
|
@ -333,6 +341,7 @@ export class FileInfoService {
|
||||||
/**
|
/**
|
||||||
* Calculate MD5 hash
|
* Calculate MD5 hash
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
private async calcHash(path: string): Promise<string> {
|
private async calcHash(path: string): Promise<string> {
|
||||||
const hash = crypto.createHash('md5').setEncoding('hex');
|
const hash = crypto.createHash('md5').setEncoding('hex');
|
||||||
await pipeline(fs.createReadStream(path), hash);
|
await pipeline(fs.createReadStream(path), hash);
|
||||||
|
@ -342,6 +351,7 @@ export class FileInfoService {
|
||||||
/**
|
/**
|
||||||
* Detect dimensions of image
|
* Detect dimensions of image
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
private async detectImageSize(path: string): Promise<{
|
private async detectImageSize(path: string): Promise<{
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
|
@ -358,6 +368,7 @@ export class FileInfoService {
|
||||||
/**
|
/**
|
||||||
* Calculate average color of image
|
* Calculate average color of image
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
private getBlurhash(path: string): Promise<string> {
|
private getBlurhash(path: string): Promise<string> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
sharp(path)
|
sharp(path)
|
||||||
|
|
|
@ -25,6 +25,7 @@ import type {
|
||||||
import type { Packed } from '@/misc/schema.js';
|
import type { Packed } from '@/misc/schema.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class GlobalEventService {
|
export class GlobalEventService {
|
||||||
|
@ -37,6 +38,7 @@ export class GlobalEventService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private publish(channel: StreamChannels, type: string | null, value?: any): void {
|
private publish(channel: StreamChannels, type: string | null, value?: any): void {
|
||||||
const message = type == null ? value : value == null ?
|
const message = type == null ? value : value == null ?
|
||||||
{ type: type, body: null } :
|
{ type: type, body: null } :
|
||||||
|
@ -99,6 +101,7 @@ export class GlobalEventService {
|
||||||
this.publish(`messagingIndexStream:${userId}`, type, typeof value === 'undefined' ? null : value);
|
this.publish(`messagingIndexStream:${userId}`, type, typeof value === 'undefined' ? null : value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public publishNotesStream(note: Packed<'Note'>): void {
|
public publishNotesStream(note: Packed<'Note'>): void {
|
||||||
this.publish('notesStream', null, note);
|
this.publish('notesStream', null, note);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import type { Hashtag } from '@/models/entities/Hashtag.js';
|
||||||
import HashtagChart from '@/core/chart/charts/hashtag.js';
|
import HashtagChart from '@/core/chart/charts/hashtag.js';
|
||||||
import type { HashtagsRepository, UsersRepository } from '@/models/index.js';
|
import type { HashtagsRepository, UsersRepository } from '@/models/index.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class HashtagService {
|
export class HashtagService {
|
||||||
|
@ -23,12 +24,14 @@ export class HashtagService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async updateHashtags(user: { id: User['id']; host: User['host']; }, tags: string[]) {
|
public async updateHashtags(user: { id: User['id']; host: User['host']; }, tags: string[]) {
|
||||||
for (const tag of tags) {
|
for (const tag of tags) {
|
||||||
await this.updateHashtag(user, tag);
|
await this.updateHashtag(user, tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async updateUsertags(user: User, tags: string[]) {
|
public async updateUsertags(user: User, tags: string[]) {
|
||||||
for (const tag of tags) {
|
for (const tag of tags) {
|
||||||
await this.updateHashtag(user, tag, true, true);
|
await this.updateHashtag(user, tag, true, true);
|
||||||
|
@ -39,6 +42,7 @@ export class HashtagService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async updateHashtag(user: { id: User['id']; host: User['host']; }, tag: string, isUserAttached = false, inc = true) {
|
public async updateHashtag(user: { id: User['id']; host: User['host']; }, tag: string, isUserAttached = false, inc = true) {
|
||||||
tag = normalizeForSearch(tag);
|
tag = normalizeForSearch(tag);
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import { StatusError } from '@/misc/status-error.js';
|
import { StatusError } from '@/misc/status-error.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import type { Response } from 'node-fetch';
|
import type { Response } from 'node-fetch';
|
||||||
import type { URL } from 'node:url';
|
import type { URL } from 'node:url';
|
||||||
|
|
||||||
|
@ -84,6 +85,7 @@ export class HttpRequestService {
|
||||||
* @param url URL
|
* @param url URL
|
||||||
* @param bypassProxy Allways bypass proxy
|
* @param bypassProxy Allways bypass proxy
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public getAgentByUrl(url: URL, bypassProxy = false): http.Agent | https.Agent {
|
public getAgentByUrl(url: URL, bypassProxy = false): http.Agent | https.Agent {
|
||||||
if (bypassProxy || (this.config.proxyBypassHosts || []).includes(url.hostname)) {
|
if (bypassProxy || (this.config.proxyBypassHosts || []).includes(url.hostname)) {
|
||||||
return url.protocol === 'http:' ? this.http : this.https;
|
return url.protocol === 'http:' ? this.http : this.https;
|
||||||
|
@ -92,6 +94,7 @@ export class HttpRequestService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async getJson(url: string, accept = 'application/json, */*', timeout = 10000, headers?: Record<string, string>): Promise<unknown> {
|
public async getJson(url: string, accept = 'application/json, */*', timeout = 10000, headers?: Record<string, string>): Promise<unknown> {
|
||||||
const res = await this.getResponse({
|
const res = await this.getResponse({
|
||||||
url,
|
url,
|
||||||
|
@ -106,6 +109,7 @@ export class HttpRequestService {
|
||||||
return await res.json();
|
return await res.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async getHtml(url: string, accept = 'text/html, */*', timeout = 10000, headers?: Record<string, string>): Promise<string> {
|
public async getHtml(url: string, accept = 'text/html, */*', timeout = 10000, headers?: Record<string, string>): Promise<string> {
|
||||||
const res = await this.getResponse({
|
const res = await this.getResponse({
|
||||||
url,
|
url,
|
||||||
|
@ -120,6 +124,7 @@ export class HttpRequestService {
|
||||||
return await res.text();
|
return await res.text();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async getResponse(args: {
|
public async getResponse(args: {
|
||||||
url: string,
|
url: string,
|
||||||
method: string,
|
method: string,
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { genAid } from '@/misc/id/aid.js';
|
||||||
import { genMeid } from '@/misc/id/meid.js';
|
import { genMeid } from '@/misc/id/meid.js';
|
||||||
import { genMeidg } from '@/misc/id/meidg.js';
|
import { genMeidg } from '@/misc/id/meidg.js';
|
||||||
import { genObjectId } from '@/misc/id/object-id.js';
|
import { genObjectId } from '@/misc/id/object-id.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class IdService {
|
export class IdService {
|
||||||
|
@ -18,6 +19,7 @@ export class IdService {
|
||||||
this.metohd = config.id.toLowerCase();
|
this.metohd = config.id.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public genId(date?: Date): string {
|
public genId(date?: Date): string {
|
||||||
if (!date || (date > new Date())) date = new Date();
|
if (!date || (date > new Date())) date = new Date();
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ export type IImage = {
|
||||||
ext: string | null;
|
ext: string | null;
|
||||||
type: string;
|
type: string;
|
||||||
};
|
};
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ImageProcessingService {
|
export class ImageProcessingService {
|
||||||
|
@ -21,10 +22,12 @@ export class ImageProcessingService {
|
||||||
* Convert to JPEG
|
* Convert to JPEG
|
||||||
* with resize, remove metadata, resolve orientation, stop animation
|
* with resize, remove metadata, resolve orientation, stop animation
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async convertToJpeg(path: string, width: number, height: number): Promise<IImage> {
|
public async convertToJpeg(path: string, width: number, height: number): Promise<IImage> {
|
||||||
return this.convertSharpToJpeg(await sharp(path), width, height);
|
return this.convertSharpToJpeg(await sharp(path), width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async convertSharpToJpeg(sharp: sharp.Sharp, width: number, height: number): Promise<IImage> {
|
public async convertSharpToJpeg(sharp: sharp.Sharp, width: number, height: number): Promise<IImage> {
|
||||||
const data = await sharp
|
const data = await sharp
|
||||||
.resize(width, height, {
|
.resize(width, height, {
|
||||||
|
@ -49,10 +52,12 @@ export class ImageProcessingService {
|
||||||
* Convert to WebP
|
* Convert to WebP
|
||||||
* with resize, remove metadata, resolve orientation, stop animation
|
* with resize, remove metadata, resolve orientation, stop animation
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async convertToWebp(path: string, width: number, height: number, quality = 85): Promise<IImage> {
|
public async convertToWebp(path: string, width: number, height: number, quality = 85): Promise<IImage> {
|
||||||
return this.convertSharpToWebp(await sharp(path), width, height, quality);
|
return this.convertSharpToWebp(await sharp(path), width, height, quality);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async convertSharpToWebp(sharp: sharp.Sharp, width: number, height: number, quality = 85): Promise<IImage> {
|
public async convertSharpToWebp(sharp: sharp.Sharp, width: number, height: number, quality = 85): Promise<IImage> {
|
||||||
const data = await sharp
|
const data = await sharp
|
||||||
.resize(width, height, {
|
.resize(width, height, {
|
||||||
|
@ -76,10 +81,12 @@ export class ImageProcessingService {
|
||||||
* Convert to PNG
|
* Convert to PNG
|
||||||
* with resize, remove metadata, resolve orientation, stop animation
|
* with resize, remove metadata, resolve orientation, stop animation
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async convertToPng(path: string, width: number, height: number): Promise<IImage> {
|
public async convertToPng(path: string, width: number, height: number): Promise<IImage> {
|
||||||
return this.convertSharpToPng(await sharp(path), width, height);
|
return this.convertSharpToPng(await sharp(path), width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async convertSharpToPng(sharp: sharp.Sharp, width: number, height: number): Promise<IImage> {
|
public async convertSharpToPng(sharp: sharp.Sharp, width: number, height: number): Promise<IImage> {
|
||||||
const data = await sharp
|
const data = await sharp
|
||||||
.resize(width, height, {
|
.resize(width, height, {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { DI } from '@/di-symbols.js';
|
||||||
import { CreateSystemUserService } from '@/core/CreateSystemUserService.js';
|
import { CreateSystemUserService } from '@/core/CreateSystemUserService.js';
|
||||||
|
|
||||||
const ACTOR_USERNAME = 'instance.actor' as const;
|
const ACTOR_USERNAME = 'instance.actor' as const;
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class InstanceActorService {
|
export class InstanceActorService {
|
||||||
|
@ -21,6 +22,7 @@ export class InstanceActorService {
|
||||||
this.cache = new Cache<ILocalUser>(Infinity);
|
this.cache = new Cache<ILocalUser>(Infinity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async getInstanceActor(): Promise<ILocalUser> {
|
public async getInstanceActor(): Promise<ILocalUser> {
|
||||||
const cached = this.cache.get(null);
|
const cached = this.cache.get(null);
|
||||||
if (cached) return cached;
|
if (cached) return cached;
|
||||||
|
|
|
@ -10,6 +10,7 @@ const _filename = fileURLToPath(import.meta.url);
|
||||||
const _dirname = dirname(_filename);
|
const _dirname = dirname(_filename);
|
||||||
|
|
||||||
const path = Path.resolve(_dirname, '../../../../files');
|
const path = Path.resolve(_dirname, '../../../../files');
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class InternalStorageService {
|
export class InternalStorageService {
|
||||||
|
@ -19,26 +20,31 @@ export class InternalStorageService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public resolvePath(key: string) {
|
public resolvePath(key: string) {
|
||||||
return Path.resolve(path, key);
|
return Path.resolve(path, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public read(key: string) {
|
public read(key: string) {
|
||||||
return fs.createReadStream(this.resolvePath(key));
|
return fs.createReadStream(this.resolvePath(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public saveFromPath(key: string, srcPath: string) {
|
public saveFromPath(key: string, srcPath: string) {
|
||||||
fs.mkdirSync(path, { recursive: true });
|
fs.mkdirSync(path, { recursive: true });
|
||||||
fs.copyFileSync(srcPath, this.resolvePath(key));
|
fs.copyFileSync(srcPath, this.resolvePath(key));
|
||||||
return `${this.config.url}/files/${key}`;
|
return `${this.config.url}/files/${key}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public saveFromBuffer(key: string, data: Buffer) {
|
public saveFromBuffer(key: string, data: Buffer) {
|
||||||
fs.mkdirSync(path, { recursive: true });
|
fs.mkdirSync(path, { recursive: true });
|
||||||
fs.writeFileSync(this.resolvePath(key), data);
|
fs.writeFileSync(this.resolvePath(key), data);
|
||||||
return `${this.config.url}/files/${key}`;
|
return `${this.config.url}/files/${key}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public del(key: string) {
|
public del(key: string) {
|
||||||
fs.unlink(this.resolvePath(key), () => {});
|
fs.unlink(this.resolvePath(key), () => {});
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import * as SyslogPro from 'syslog-pro';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import Logger from '@/logger.js';
|
import Logger from '@/logger.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class LoggerService {
|
export class LoggerService {
|
||||||
|
@ -27,6 +28,7 @@ export class LoggerService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public getLogger(domain: string, color?: string | undefined, store?: boolean) {
|
public getLogger(domain: string, color?: string | undefined, store?: boolean) {
|
||||||
return new Logger(domain, color, store, this.syslogClient);
|
return new Logger(domain, color, store, this.syslogClient);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
||||||
import { MessagingMessageEntityService } from '@/core/entities/MessagingMessageEntityService.js';
|
import { MessagingMessageEntityService } from '@/core/entities/MessagingMessageEntityService.js';
|
||||||
import { PushNotificationService } from '@/core/PushNotificationService.js';
|
import { PushNotificationService } from '@/core/PushNotificationService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MessagingService {
|
export class MessagingService {
|
||||||
|
@ -46,6 +47,7 @@ export class MessagingService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async createMessage(user: { id: User['id']; host: User['host']; }, recipientUser: CacheableUser | undefined, recipientGroup: UserGroup | undefined, text: string | null | undefined, file: DriveFile | null, uri?: string) {
|
public async createMessage(user: { id: User['id']; host: User['host']; }, recipientUser: CacheableUser | undefined, recipientGroup: UserGroup | undefined, text: string | null | undefined, file: DriveFile | null, uri?: string) {
|
||||||
const message = {
|
const message = {
|
||||||
id: this.idService.genId(),
|
id: this.idService.genId(),
|
||||||
|
@ -140,11 +142,13 @@ export class MessagingService {
|
||||||
return messageObj;
|
return messageObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async deleteMessage(message: MessagingMessage) {
|
public async deleteMessage(message: MessagingMessage) {
|
||||||
await this.messagingMessagesRepository.delete(message.id);
|
await this.messagingMessagesRepository.delete(message.id);
|
||||||
this.postDeleteMessage(message);
|
this.postDeleteMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async postDeleteMessage(message: MessagingMessage) {
|
private async postDeleteMessage(message: MessagingMessage) {
|
||||||
if (message.recipientId) {
|
if (message.recipientId) {
|
||||||
const user = await this.usersRepository.findOneByOrFail({ id: message.userId });
|
const user = await this.usersRepository.findOneByOrFail({ id: message.userId });
|
||||||
|
@ -165,6 +169,7 @@ export class MessagingService {
|
||||||
/**
|
/**
|
||||||
* Mark messages as read
|
* Mark messages as read
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async readUserMessagingMessage(
|
public async readUserMessagingMessage(
|
||||||
userId: User['id'],
|
userId: User['id'],
|
||||||
otherpartyId: User['id'],
|
otherpartyId: User['id'],
|
||||||
|
@ -220,6 +225,7 @@ export class MessagingService {
|
||||||
/**
|
/**
|
||||||
* Mark messages as read
|
* Mark messages as read
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async readGroupMessagingMessage(
|
public async readGroupMessagingMessage(
|
||||||
userId: User['id'],
|
userId: User['id'],
|
||||||
groupId: UserGroup['id'],
|
groupId: UserGroup['id'],
|
||||||
|
@ -284,6 +290,7 @@ export class MessagingService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async deliverReadActivity(user: { id: User['id']; host: null; }, recipient: IRemoteUser, messages: MessagingMessage | MessagingMessage[]) {
|
public async deliverReadActivity(user: { id: User['id']; host: null; }, recipient: IRemoteUser, messages: MessagingMessage | MessagingMessage[]) {
|
||||||
messages = toArray(messages).filter(x => x.uri);
|
messages = toArray(messages).filter(x => x.uri);
|
||||||
const contents = messages.map(x => this.apRendererService.renderRead(user, x));
|
const contents = messages.map(x => this.apRendererService.renderRead(user, x));
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { DI } from '@/di-symbols.js';
|
||||||
import { Meta } from '@/models/entities/Meta.js';
|
import { Meta } from '@/models/entities/Meta.js';
|
||||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||||
import type { OnApplicationShutdown } from '@nestjs/common';
|
import type { OnApplicationShutdown } from '@nestjs/common';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MetaService implements OnApplicationShutdown {
|
export class MetaService implements OnApplicationShutdown {
|
||||||
|
@ -20,7 +21,7 @@ export class MetaService implements OnApplicationShutdown {
|
||||||
|
|
||||||
private globalEventService: GlobalEventService,
|
private globalEventService: GlobalEventService,
|
||||||
) {
|
) {
|
||||||
this.onMessage = this.onMessage.bind(this);
|
//this.onMessage = this.onMessage.bind(this);
|
||||||
|
|
||||||
if (process.env.NODE_ENV !== 'test') {
|
if (process.env.NODE_ENV !== 'test') {
|
||||||
this.intervalId = setInterval(() => {
|
this.intervalId = setInterval(() => {
|
||||||
|
@ -34,6 +35,7 @@ export class MetaService implements OnApplicationShutdown {
|
||||||
this.redisSubscriber.on('message', this.onMessage);
|
this.redisSubscriber.on('message', this.onMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async onMessage(_: string, data: string): Promise<void> {
|
private async onMessage(_: string, data: string): Promise<void> {
|
||||||
const obj = JSON.parse(data);
|
const obj = JSON.parse(data);
|
||||||
|
|
||||||
|
@ -50,6 +52,7 @@ export class MetaService implements OnApplicationShutdown {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async fetch(noCache = false): Promise<Meta> {
|
public async fetch(noCache = false): Promise<Meta> {
|
||||||
if (!noCache && this.cache) return this.cache;
|
if (!noCache && this.cache) return this.cache;
|
||||||
|
|
||||||
|
@ -84,6 +87,7 @@ export class MetaService implements OnApplicationShutdown {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async update(data: Partial<Meta>): Promise<Meta> {
|
public async update(data: Partial<Meta>): Promise<Meta> {
|
||||||
const updated = await this.db.transaction(async transactionalEntityManager => {
|
const updated = await this.db.transaction(async transactionalEntityManager => {
|
||||||
const metas = await transactionalEntityManager.find(Meta, {
|
const metas = await transactionalEntityManager.find(Meta, {
|
||||||
|
@ -114,6 +118,7 @@ export class MetaService implements OnApplicationShutdown {
|
||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public onApplicationShutdown(signal?: string | undefined) {
|
public onApplicationShutdown(signal?: string | undefined) {
|
||||||
clearInterval(this.intervalId);
|
clearInterval(this.intervalId);
|
||||||
this.redisSubscriber.off('message', this.onMessage);
|
this.redisSubscriber.off('message', this.onMessage);
|
||||||
|
|
|
@ -14,6 +14,7 @@ const treeAdapter = TreeAdapter.defaultTreeAdapter;
|
||||||
|
|
||||||
const urlRegex = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+/;
|
const urlRegex = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+/;
|
||||||
const urlRegexFull = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+$/;
|
const urlRegexFull = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+$/;
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MfmService {
|
export class MfmService {
|
||||||
|
@ -23,6 +24,7 @@ export class MfmService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public fromHtml(html: string, hashtagNames?: string[]): string {
|
public fromHtml(html: string, hashtagNames?: string[]): string {
|
||||||
// some AP servers like Pixelfed use br tags as well as newlines
|
// some AP servers like Pixelfed use br tags as well as newlines
|
||||||
html = html.replace(/<br\s?\/?>\r?\n/gi, '\n');
|
html = html.replace(/<br\s?\/?>\r?\n/gi, '\n');
|
||||||
|
@ -228,6 +230,7 @@ export class MfmService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public toHtml(nodes: mfm.MfmNode[] | null, mentionedRemoteUsers: IMentionedRemoteUsers = []) {
|
public toHtml(nodes: mfm.MfmNode[] | null, mentionedRemoteUsers: IMentionedRemoteUsers = []) {
|
||||||
if (nodes == null) {
|
if (nodes == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { DI } from '@/di-symbols.js';
|
||||||
import type { ModerationLogsRepository } from '@/models/index.js';
|
import type { ModerationLogsRepository } from '@/models/index.js';
|
||||||
import type { User } from '@/models/entities/User.js';
|
import type { User } from '@/models/entities/User.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ModerationLogService {
|
export class ModerationLogService {
|
||||||
|
@ -14,6 +15,7 @@ export class ModerationLogService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async insertModerationLog(moderator: { id: User['id'] }, type: string, info?: Record<string, any>) {
|
public async insertModerationLog(moderator: { id: User['id'] }, type: string, info?: Record<string, any>) {
|
||||||
await this.moderationLogsRepository.insert({
|
await this.moderationLogsRepository.insert({
|
||||||
id: this.idService.genId(),
|
id: this.idService.genId(),
|
||||||
|
|
|
@ -64,6 +64,7 @@ class NotificationManager {
|
||||||
this.queue = [];
|
this.queue = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public push(notifiee: ILocalUser['id'], reason: NotificationType) {
|
public push(notifiee: ILocalUser['id'], reason: NotificationType) {
|
||||||
// 自分自身へは通知しない
|
// 自分自身へは通知しない
|
||||||
if (this.notifier.id === notifiee) return;
|
if (this.notifier.id === notifiee) return;
|
||||||
|
@ -83,6 +84,7 @@ class NotificationManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async deliver() {
|
public async deliver() {
|
||||||
for (const x of this.queue) {
|
for (const x of this.queue) {
|
||||||
// ミュート情報を取得
|
// ミュート情報を取得
|
||||||
|
@ -130,6 +132,7 @@ type Option = {
|
||||||
url?: string | null;
|
url?: string | null;
|
||||||
app?: App | null;
|
app?: App | null;
|
||||||
};
|
};
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class NoteCreateService {
|
export class NoteCreateService {
|
||||||
|
@ -188,6 +191,7 @@ export class NoteCreateService {
|
||||||
private instanceChart: InstanceChart,
|
private instanceChart: InstanceChart,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async create(user: {
|
public async create(user: {
|
||||||
id: User['id'];
|
id: User['id'];
|
||||||
username: User['username'];
|
username: User['username'];
|
||||||
|
@ -307,6 +311,7 @@ export class NoteCreateService {
|
||||||
return note;
|
return note;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async insertNote(user: { id: User['id']; host: User['host']; }, data: Option, tags: string[], emojis: string[], mentionedUsers: MinimumUser[]) {
|
private async insertNote(user: { id: User['id']; host: User['host']; }, data: Option, tags: string[], emojis: string[], mentionedUsers: MinimumUser[]) {
|
||||||
const insert = new Note({
|
const insert = new Note({
|
||||||
id: this.idService.genId(data.createdAt!),
|
id: this.idService.genId(data.createdAt!),
|
||||||
|
@ -403,6 +408,7 @@ export class NoteCreateService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async postNoteCreated(note: Note, user: {
|
private async postNoteCreated(note: Note, user: {
|
||||||
id: User['id'];
|
id: User['id'];
|
||||||
username: User['username'];
|
username: User['username'];
|
||||||
|
@ -644,6 +650,7 @@ export class NoteCreateService {
|
||||||
this.index(note);
|
this.index(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private incRenoteCount(renote: Note) {
|
private incRenoteCount(renote: Note) {
|
||||||
this.notesRepository.createQueryBuilder().update()
|
this.notesRepository.createQueryBuilder().update()
|
||||||
.set({
|
.set({
|
||||||
|
@ -654,6 +661,7 @@ export class NoteCreateService {
|
||||||
.execute();
|
.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async createMentionedEvents(mentionedUsers: MinimumUser[], note: Note, nm: NotificationManager) {
|
private async createMentionedEvents(mentionedUsers: MinimumUser[], note: Note, nm: NotificationManager) {
|
||||||
for (const u of mentionedUsers.filter(u => this.userEntityService.isLocalUser(u))) {
|
for (const u of mentionedUsers.filter(u => this.userEntityService.isLocalUser(u))) {
|
||||||
const threadMuted = await this.noteThreadMutingsRepository.findOneBy({
|
const threadMuted = await this.noteThreadMutingsRepository.findOneBy({
|
||||||
|
@ -683,10 +691,12 @@ export class NoteCreateService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private saveReply(reply: Note, note: Note) {
|
private saveReply(reply: Note, note: Note) {
|
||||||
this.notesRepository.increment({ id: reply.id }, 'repliesCount', 1);
|
this.notesRepository.increment({ id: reply.id }, 'repliesCount', 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async renderNoteOrRenoteActivity(data: Option, note: Note) {
|
private async renderNoteOrRenoteActivity(data: Option, note: Note) {
|
||||||
if (data.localOnly) return null;
|
if (data.localOnly) return null;
|
||||||
|
|
||||||
|
@ -697,6 +707,7 @@ export class NoteCreateService {
|
||||||
return this.apRendererService.renderActivity(content);
|
return this.apRendererService.renderActivity(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private index(note: Note) {
|
private index(note: Note) {
|
||||||
if (note.text == null || this.config.elasticsearch == null) return;
|
if (note.text == null || this.config.elasticsearch == null) return;
|
||||||
/*
|
/*
|
||||||
|
@ -711,6 +722,7 @@ export class NoteCreateService {
|
||||||
});*/
|
});*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private incNotesCountOfUser(user: { id: User['id']; }) {
|
private incNotesCountOfUser(user: { id: User['id']; }) {
|
||||||
this.usersRepository.createQueryBuilder().update()
|
this.usersRepository.createQueryBuilder().update()
|
||||||
.set({
|
.set({
|
||||||
|
@ -721,6 +733,7 @@ export class NoteCreateService {
|
||||||
.execute();
|
.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async extractMentionedUsers(user: { host: User['host']; }, tokens: mfm.MfmNode[]): Promise<User[]> {
|
private async extractMentionedUsers(user: { host: User['host']; }, tokens: mfm.MfmNode[]): Promise<User[]> {
|
||||||
if (tokens == null) return [];
|
if (tokens == null) return [];
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
||||||
import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerService.js';
|
import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerService.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class NoteDeleteService {
|
export class NoteDeleteService {
|
||||||
|
@ -112,6 +113,7 @@ export class NoteDeleteService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async findCascadingNotes(note: Note) {
|
private async findCascadingNotes(note: Note) {
|
||||||
const cascadingNotes: Note[] = [];
|
const cascadingNotes: Note[] = [];
|
||||||
|
|
||||||
|
@ -134,6 +136,7 @@ export class NoteDeleteService {
|
||||||
return cascadingNotes.filter(note => note.userHost === null); // filter out non-local users
|
return cascadingNotes.filter(note => note.userHost === null); // filter out non-local users
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async getMentionedRemoteUsers(note: Note) {
|
private async getMentionedRemoteUsers(note: Note) {
|
||||||
const where = [] as any[];
|
const where = [] as any[];
|
||||||
|
|
||||||
|
@ -159,6 +162,7 @@ export class NoteDeleteService {
|
||||||
}) as IRemoteUser[];
|
}) as IRemoteUser[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async deliverToConcerned(user: { id: ILocalUser['id']; host: null; }, note: Note, content: any) {
|
private async deliverToConcerned(user: { id: ILocalUser['id']; host: null; }, note: Note, content: any) {
|
||||||
this.apDeliverManagerService.deliverToFollowers(user, content);
|
this.apDeliverManagerService.deliverToFollowers(user, content);
|
||||||
this.relayService.deliverToRelays(user, content);
|
this.relayService.deliverToRelays(user, content);
|
||||||
|
|
|
@ -11,6 +11,7 @@ import type { Config } from '@/config.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerService.js';
|
import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerService.js';
|
||||||
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class NotePiningService {
|
export class NotePiningService {
|
||||||
|
@ -40,6 +41,7 @@ export class NotePiningService {
|
||||||
* @param user
|
* @param user
|
||||||
* @param noteId
|
* @param noteId
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async addPinned(user: { id: User['id']; host: User['host']; }, noteId: Note['id']) {
|
public async addPinned(user: { id: User['id']; host: User['host']; }, noteId: Note['id']) {
|
||||||
// Fetch pinee
|
// Fetch pinee
|
||||||
const note = await this.notesRepository.findOneBy({
|
const note = await this.notesRepository.findOneBy({
|
||||||
|
@ -79,6 +81,7 @@ export class NotePiningService {
|
||||||
* @param user
|
* @param user
|
||||||
* @param noteId
|
* @param noteId
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async removePinned(user: { id: User['id']; host: User['host']; }, noteId: Note['id']) {
|
public async removePinned(user: { id: User['id']; host: User['host']; }, noteId: Note['id']) {
|
||||||
// Fetch unpinee
|
// Fetch unpinee
|
||||||
const note = await this.notesRepository.findOneBy({
|
const note = await this.notesRepository.findOneBy({
|
||||||
|
@ -101,6 +104,7 @@ export class NotePiningService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async deliverPinnedChange(userId: User['id'], noteId: Note['id'], isAddition: boolean) {
|
public async deliverPinnedChange(userId: User['id'], noteId: Note['id'], isAddition: boolean) {
|
||||||
const user = await this.usersRepository.findOneBy({ id: userId });
|
const user = await this.usersRepository.findOneBy({ id: userId });
|
||||||
if (user == null) throw new Error('user not found');
|
if (user == null) throw new Error('user not found');
|
||||||
|
|
|
@ -11,6 +11,7 @@ import type { UsersRepository, NoteUnreadsRepository, MutingsRepository, NoteThr
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { NotificationService } from './NotificationService.js';
|
import { NotificationService } from './NotificationService.js';
|
||||||
import { AntennaService } from './AntennaService.js';
|
import { AntennaService } from './AntennaService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class NoteReadService {
|
export class NoteReadService {
|
||||||
|
@ -44,6 +45,7 @@ export class NoteReadService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async insertNoteUnread(userId: User['id'], note: Note, params: {
|
public async insertNoteUnread(userId: User['id'], note: Note, params: {
|
||||||
// NOTE: isSpecifiedがtrueならisMentionedは必ずfalse
|
// NOTE: isSpecifiedがtrueならisMentionedは必ずfalse
|
||||||
isSpecified: boolean;
|
isSpecified: boolean;
|
||||||
|
@ -94,6 +96,7 @@ export class NoteReadService {
|
||||||
}, 2000);
|
}, 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async read(
|
public async read(
|
||||||
userId: User['id'],
|
userId: User['id'],
|
||||||
notes: (Note | Packed<'Note'>)[],
|
notes: (Note | Packed<'Note'>)[],
|
||||||
|
|
|
@ -8,6 +8,7 @@ import type { Notification } from '@/models/entities/Notification.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { GlobalEventService } from './GlobalEventService.js';
|
import { GlobalEventService } from './GlobalEventService.js';
|
||||||
import { PushNotificationService } from './PushNotificationService.js';
|
import { PushNotificationService } from './PushNotificationService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class NotificationService {
|
export class NotificationService {
|
||||||
|
@ -21,6 +22,7 @@ export class NotificationService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async readNotification(
|
public async readNotification(
|
||||||
userId: User['id'],
|
userId: User['id'],
|
||||||
notificationIds: Notification['id'][],
|
notificationIds: Notification['id'][],
|
||||||
|
@ -42,6 +44,7 @@ export class NotificationService {
|
||||||
else return this.postReadNotifications(userId, notificationIds);
|
else return this.postReadNotifications(userId, notificationIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async readNotificationByQuery(
|
public async readNotificationByQuery(
|
||||||
userId: User['id'],
|
userId: User['id'],
|
||||||
query: Record<string, any>,
|
query: Record<string, any>,
|
||||||
|
@ -55,11 +58,13 @@ export class NotificationService {
|
||||||
return this.readNotification(userId, notificationIds);
|
return this.readNotification(userId, notificationIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private postReadAllNotifications(userId: User['id']) {
|
private postReadAllNotifications(userId: User['id']) {
|
||||||
this.globalEventService.publishMainStream(userId, 'readAllNotifications');
|
this.globalEventService.publishMainStream(userId, 'readAllNotifications');
|
||||||
return this.pushNotificationService.pushNotification(userId, 'readAllNotifications', undefined);
|
return this.pushNotificationService.pushNotification(userId, 'readAllNotifications', undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private postReadNotifications(userId: User['id'], notificationIds: Notification['id'][]) {
|
private postReadNotifications(userId: User['id'], notificationIds: Notification['id'][]) {
|
||||||
this.globalEventService.publishMainStream(userId, 'readNotifications', notificationIds);
|
this.globalEventService.publishMainStream(userId, 'readNotifications', notificationIds);
|
||||||
return this.pushNotificationService.pushNotification(userId, 'readNotifications', { notificationIds });
|
return this.pushNotificationService.pushNotification(userId, 'readNotifications', { notificationIds });
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { CreateNotificationService } from '@/core/CreateNotificationService.js';
|
||||||
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerService.js';
|
import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PollService {
|
export class PollService {
|
||||||
|
@ -40,6 +41,7 @@ export class PollService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async vote(user: CacheableUser, note: Note, choice: number) {
|
public async vote(user: CacheableUser, note: Note, choice: number) {
|
||||||
const poll = await this.pollsRepository.findOneBy({ noteId: note.id });
|
const poll = await this.pollsRepository.findOneBy({ noteId: note.id });
|
||||||
|
|
||||||
|
@ -99,6 +101,7 @@ export class PollService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async deliverQuestionUpdate(noteId: Note['id']) {
|
public async deliverQuestionUpdate(noteId: Note['id']) {
|
||||||
const note = await this.notesRepository.findOneBy({ id: noteId });
|
const note = await this.notesRepository.findOneBy({ id: noteId });
|
||||||
if (note == null) throw new Error('note not found');
|
if (note == null) throw new Error('note not found');
|
||||||
|
|
|
@ -3,6 +3,7 @@ import type { UsersRepository } from '@/models/index.js';
|
||||||
import type { ILocalUser, User } from '@/models/entities/User.js';
|
import type { ILocalUser, User } from '@/models/entities/User.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { MetaService } from '@/core/MetaService.js';
|
import { MetaService } from '@/core/MetaService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ProxyAccountService {
|
export class ProxyAccountService {
|
||||||
|
@ -14,6 +15,7 @@ export class ProxyAccountService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async fetch(): Promise<ILocalUser | null> {
|
public async fetch(): Promise<ILocalUser | null> {
|
||||||
const meta = await this.metaService.fetch();
|
const meta = await this.metaService.fetch();
|
||||||
if (meta.proxyAccountId == null) return null;
|
if (meta.proxyAccountId == null) return null;
|
||||||
|
|
|
@ -37,6 +37,7 @@ function truncateNotification(notification: Packed<'Notification'>): any {
|
||||||
|
|
||||||
return notification;
|
return notification;
|
||||||
}
|
}
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PushNotificationService {
|
export class PushNotificationService {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { DI } from '@/di-symbols.js';
|
||||||
import type { User } from '@/models/entities/User.js';
|
import type { User } from '@/models/entities/User.js';
|
||||||
import type { UserProfilesRepository, FollowingsRepository, ChannelFollowingsRepository, MutedNotesRepository, BlockingsRepository, NoteThreadMutingsRepository, MutingsRepository } from '@/models/index.js';
|
import type { UserProfilesRepository, FollowingsRepository, ChannelFollowingsRepository, MutedNotesRepository, BlockingsRepository, NoteThreadMutingsRepository, MutingsRepository } from '@/models/index.js';
|
||||||
import type { SelectQueryBuilder } from 'typeorm';
|
import type { SelectQueryBuilder } from 'typeorm';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class QueryService {
|
export class QueryService {
|
||||||
|
@ -59,6 +60,7 @@ export class QueryService {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ここでいうBlockedは被Blockedの意
|
// ここでいうBlockedは被Blockedの意
|
||||||
|
@bindThis
|
||||||
public generateBlockedUserQuery(q: SelectQueryBuilder<any>, me: { id: User['id'] }): void {
|
public generateBlockedUserQuery(q: SelectQueryBuilder<any>, me: { id: User['id'] }): void {
|
||||||
const blockingQuery = this.blockingsRepository.createQueryBuilder('blocking')
|
const blockingQuery = this.blockingsRepository.createQueryBuilder('blocking')
|
||||||
.select('blocking.blockerId')
|
.select('blocking.blockerId')
|
||||||
|
@ -81,6 +83,7 @@ export class QueryService {
|
||||||
q.setParameters(blockingQuery.getParameters());
|
q.setParameters(blockingQuery.getParameters());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public generateBlockQueryForUsers(q: SelectQueryBuilder<any>, me: { id: User['id'] }): void {
|
public generateBlockQueryForUsers(q: SelectQueryBuilder<any>, me: { id: User['id'] }): void {
|
||||||
const blockingQuery = this.blockingsRepository.createQueryBuilder('blocking')
|
const blockingQuery = this.blockingsRepository.createQueryBuilder('blocking')
|
||||||
.select('blocking.blockeeId')
|
.select('blocking.blockeeId')
|
||||||
|
@ -97,6 +100,7 @@ export class QueryService {
|
||||||
q.setParameters(blockedQuery.getParameters());
|
q.setParameters(blockedQuery.getParameters());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public generateChannelQuery(q: SelectQueryBuilder<any>, me?: { id: User['id'] } | null): void {
|
public generateChannelQuery(q: SelectQueryBuilder<any>, me?: { id: User['id'] } | null): void {
|
||||||
if (me == null) {
|
if (me == null) {
|
||||||
q.andWhere('note.channelId IS NULL');
|
q.andWhere('note.channelId IS NULL');
|
||||||
|
@ -118,6 +122,7 @@ export class QueryService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public generateMutedNoteQuery(q: SelectQueryBuilder<any>, me: { id: User['id'] }): void {
|
public generateMutedNoteQuery(q: SelectQueryBuilder<any>, me: { id: User['id'] }): void {
|
||||||
const mutedQuery = this.mutedNotesRepository.createQueryBuilder('muted')
|
const mutedQuery = this.mutedNotesRepository.createQueryBuilder('muted')
|
||||||
.select('muted.noteId')
|
.select('muted.noteId')
|
||||||
|
@ -128,6 +133,7 @@ export class QueryService {
|
||||||
q.setParameters(mutedQuery.getParameters());
|
q.setParameters(mutedQuery.getParameters());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public generateMutedNoteThreadQuery(q: SelectQueryBuilder<any>, me: { id: User['id'] }): void {
|
public generateMutedNoteThreadQuery(q: SelectQueryBuilder<any>, me: { id: User['id'] }): void {
|
||||||
const mutedQuery = this.noteThreadMutingsRepository.createQueryBuilder('threadMuted')
|
const mutedQuery = this.noteThreadMutingsRepository.createQueryBuilder('threadMuted')
|
||||||
.select('threadMuted.threadId')
|
.select('threadMuted.threadId')
|
||||||
|
@ -142,6 +148,7 @@ export class QueryService {
|
||||||
q.setParameters(mutedQuery.getParameters());
|
q.setParameters(mutedQuery.getParameters());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public generateMutedUserQuery(q: SelectQueryBuilder<any>, me: { id: User['id'] }, exclude?: User): void {
|
public generateMutedUserQuery(q: SelectQueryBuilder<any>, me: { id: User['id'] }, exclude?: User): void {
|
||||||
const mutingQuery = this.mutingsRepository.createQueryBuilder('muting')
|
const mutingQuery = this.mutingsRepository.createQueryBuilder('muting')
|
||||||
.select('muting.muteeId')
|
.select('muting.muteeId')
|
||||||
|
@ -186,6 +193,7 @@ export class QueryService {
|
||||||
q.setParameters(mutingInstanceQuery.getParameters());
|
q.setParameters(mutingInstanceQuery.getParameters());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public generateMutedUserQueryForUsers(q: SelectQueryBuilder<any>, me: { id: User['id'] }): void {
|
public generateMutedUserQueryForUsers(q: SelectQueryBuilder<any>, me: { id: User['id'] }): void {
|
||||||
const mutingQuery = this.mutingsRepository.createQueryBuilder('muting')
|
const mutingQuery = this.mutingsRepository.createQueryBuilder('muting')
|
||||||
.select('muting.muteeId')
|
.select('muting.muteeId')
|
||||||
|
@ -196,6 +204,7 @@ export class QueryService {
|
||||||
q.setParameters(mutingQuery.getParameters());
|
q.setParameters(mutingQuery.getParameters());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public generateRepliesQuery(q: SelectQueryBuilder<any>, me?: Pick<User, 'id' | 'showTimelineReplies'> | null): void {
|
public generateRepliesQuery(q: SelectQueryBuilder<any>, me?: Pick<User, 'id' | 'showTimelineReplies'> | null): void {
|
||||||
if (me == null) {
|
if (me == null) {
|
||||||
q.andWhere(new Brackets(qb => { qb
|
q.andWhere(new Brackets(qb => { qb
|
||||||
|
@ -221,6 +230,7 @@ export class QueryService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public generateVisibilityQuery(q: SelectQueryBuilder<any>, me?: { id: User['id'] } | null): void {
|
public generateVisibilityQuery(q: SelectQueryBuilder<any>, me?: { id: User['id'] } | null): void {
|
||||||
// This code must always be synchronized with the checks in Notes.isVisibleForMe.
|
// This code must always be synchronized with the checks in Notes.isVisibleForMe.
|
||||||
if (me == null) {
|
if (me == null) {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { DI } from '@/di-symbols.js';
|
||||||
import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, ObjectStorageQueue, SystemQueue, WebhookDeliverQueue } from './QueueModule.js';
|
import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, ObjectStorageQueue, SystemQueue, WebhookDeliverQueue } from './QueueModule.js';
|
||||||
import type { ThinUser } from '../queue/types.js';
|
import type { ThinUser } from '../queue/types.js';
|
||||||
import type httpSignature from '@peertube/http-signature';
|
import type httpSignature from '@peertube/http-signature';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class QueueService {
|
export class QueueService {
|
||||||
|
@ -24,6 +25,7 @@ export class QueueService {
|
||||||
@Inject('queue:webhookDeliver') public webhookDeliverQueue: WebhookDeliverQueue,
|
@Inject('queue:webhookDeliver') public webhookDeliverQueue: WebhookDeliverQueue,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public deliver(user: ThinUser, content: IActivity | null, to: string | null) {
|
public deliver(user: ThinUser, content: IActivity | null, to: string | null) {
|
||||||
if (content == null) return null;
|
if (content == null) return null;
|
||||||
if (to == null) return null;
|
if (to == null) return null;
|
||||||
|
@ -47,6 +49,7 @@ export class QueueService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public inbox(activity: IActivity, signature: httpSignature.IParsedSignature) {
|
public inbox(activity: IActivity, signature: httpSignature.IParsedSignature) {
|
||||||
const data = {
|
const data = {
|
||||||
activity: activity,
|
activity: activity,
|
||||||
|
@ -64,6 +67,7 @@ export class QueueService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public createDeleteDriveFilesJob(user: ThinUser) {
|
public createDeleteDriveFilesJob(user: ThinUser) {
|
||||||
return this.dbQueue.add('deleteDriveFiles', {
|
return this.dbQueue.add('deleteDriveFiles', {
|
||||||
user: user,
|
user: user,
|
||||||
|
@ -73,6 +77,7 @@ export class QueueService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public createExportCustomEmojisJob(user: ThinUser) {
|
public createExportCustomEmojisJob(user: ThinUser) {
|
||||||
return this.dbQueue.add('exportCustomEmojis', {
|
return this.dbQueue.add('exportCustomEmojis', {
|
||||||
user: user,
|
user: user,
|
||||||
|
@ -82,6 +87,7 @@ export class QueueService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public createExportNotesJob(user: ThinUser) {
|
public createExportNotesJob(user: ThinUser) {
|
||||||
return this.dbQueue.add('exportNotes', {
|
return this.dbQueue.add('exportNotes', {
|
||||||
user: user,
|
user: user,
|
||||||
|
@ -91,6 +97,7 @@ export class QueueService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public createExportFollowingJob(user: ThinUser, excludeMuting = false, excludeInactive = false) {
|
public createExportFollowingJob(user: ThinUser, excludeMuting = false, excludeInactive = false) {
|
||||||
return this.dbQueue.add('exportFollowing', {
|
return this.dbQueue.add('exportFollowing', {
|
||||||
user: user,
|
user: user,
|
||||||
|
@ -102,6 +109,7 @@ export class QueueService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public createExportMuteJob(user: ThinUser) {
|
public createExportMuteJob(user: ThinUser) {
|
||||||
return this.dbQueue.add('exportMuting', {
|
return this.dbQueue.add('exportMuting', {
|
||||||
user: user,
|
user: user,
|
||||||
|
@ -111,6 +119,7 @@ export class QueueService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public createExportBlockingJob(user: ThinUser) {
|
public createExportBlockingJob(user: ThinUser) {
|
||||||
return this.dbQueue.add('exportBlocking', {
|
return this.dbQueue.add('exportBlocking', {
|
||||||
user: user,
|
user: user,
|
||||||
|
@ -120,6 +129,7 @@ export class QueueService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public createExportUserListsJob(user: ThinUser) {
|
public createExportUserListsJob(user: ThinUser) {
|
||||||
return this.dbQueue.add('exportUserLists', {
|
return this.dbQueue.add('exportUserLists', {
|
||||||
user: user,
|
user: user,
|
||||||
|
@ -129,6 +139,7 @@ export class QueueService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public createImportFollowingJob(user: ThinUser, fileId: DriveFile['id']) {
|
public createImportFollowingJob(user: ThinUser, fileId: DriveFile['id']) {
|
||||||
return this.dbQueue.add('importFollowing', {
|
return this.dbQueue.add('importFollowing', {
|
||||||
user: user,
|
user: user,
|
||||||
|
@ -139,6 +150,7 @@ export class QueueService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public createImportMutingJob(user: ThinUser, fileId: DriveFile['id']) {
|
public createImportMutingJob(user: ThinUser, fileId: DriveFile['id']) {
|
||||||
return this.dbQueue.add('importMuting', {
|
return this.dbQueue.add('importMuting', {
|
||||||
user: user,
|
user: user,
|
||||||
|
@ -149,6 +161,7 @@ export class QueueService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public createImportBlockingJob(user: ThinUser, fileId: DriveFile['id']) {
|
public createImportBlockingJob(user: ThinUser, fileId: DriveFile['id']) {
|
||||||
return this.dbQueue.add('importBlocking', {
|
return this.dbQueue.add('importBlocking', {
|
||||||
user: user,
|
user: user,
|
||||||
|
@ -159,6 +172,7 @@ export class QueueService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public createImportUserListsJob(user: ThinUser, fileId: DriveFile['id']) {
|
public createImportUserListsJob(user: ThinUser, fileId: DriveFile['id']) {
|
||||||
return this.dbQueue.add('importUserLists', {
|
return this.dbQueue.add('importUserLists', {
|
||||||
user: user,
|
user: user,
|
||||||
|
@ -169,6 +183,7 @@ export class QueueService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public createImportCustomEmojisJob(user: ThinUser, fileId: DriveFile['id']) {
|
public createImportCustomEmojisJob(user: ThinUser, fileId: DriveFile['id']) {
|
||||||
return this.dbQueue.add('importCustomEmojis', {
|
return this.dbQueue.add('importCustomEmojis', {
|
||||||
user: user,
|
user: user,
|
||||||
|
@ -179,6 +194,7 @@ export class QueueService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public createDeleteAccountJob(user: ThinUser, opts: { soft?: boolean; } = {}) {
|
public createDeleteAccountJob(user: ThinUser, opts: { soft?: boolean; } = {}) {
|
||||||
return this.dbQueue.add('deleteAccount', {
|
return this.dbQueue.add('deleteAccount', {
|
||||||
user: user,
|
user: user,
|
||||||
|
@ -189,6 +205,7 @@ export class QueueService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public createDeleteObjectStorageFileJob(key: string) {
|
public createDeleteObjectStorageFileJob(key: string) {
|
||||||
return this.objectStorageQueue.add('deleteFile', {
|
return this.objectStorageQueue.add('deleteFile', {
|
||||||
key: key,
|
key: key,
|
||||||
|
@ -198,6 +215,7 @@ export class QueueService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public createCleanRemoteFilesJob() {
|
public createCleanRemoteFilesJob() {
|
||||||
return this.objectStorageQueue.add('cleanRemoteFiles', {}, {
|
return this.objectStorageQueue.add('cleanRemoteFiles', {}, {
|
||||||
removeOnComplete: true,
|
removeOnComplete: true,
|
||||||
|
@ -205,6 +223,7 @@ export class QueueService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public webhookDeliver(webhook: Webhook, type: typeof webhookEventTypes[number], content: unknown) {
|
public webhookDeliver(webhook: Webhook, type: typeof webhookEventTypes[number], content: unknown) {
|
||||||
const data = {
|
const data = {
|
||||||
type,
|
type,
|
||||||
|
@ -228,6 +247,7 @@ export class QueueService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public destroy() {
|
public destroy() {
|
||||||
this.deliverQueue.once('cleaned', (jobs, status) => {
|
this.deliverQueue.once('cleaned', (jobs, status) => {
|
||||||
//deliverLogger.succ(`Cleaned ${jobs.length} ${status} jobs`);
|
//deliverLogger.succ(`Cleaned ${jobs.length} ${status} jobs`);
|
||||||
|
|
|
@ -49,6 +49,7 @@ type DecodedReaction = {
|
||||||
*/
|
*/
|
||||||
host?: string | null;
|
host?: string | null;
|
||||||
};
|
};
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ReactionService {
|
export class ReactionService {
|
||||||
|
@ -81,6 +82,7 @@ export class ReactionService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async create(user: { id: User['id']; host: User['host']; }, note: Note, reaction?: string) {
|
public async create(user: { id: User['id']; host: User['host']; }, note: Note, reaction?: string) {
|
||||||
// Check blocking
|
// Check blocking
|
||||||
if (note.userId !== user.id) {
|
if (note.userId !== user.id) {
|
||||||
|
@ -196,6 +198,7 @@ export class ReactionService {
|
||||||
//#endregion
|
//#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async delete(user: { id: User['id']; host: User['host']; }, note: Note) {
|
public async delete(user: { id: User['id']; host: User['host']; }, note: Note) {
|
||||||
// if already unreacted
|
// if already unreacted
|
||||||
const exist = await this.noteReactionsRepository.findOneBy({
|
const exist = await this.noteReactionsRepository.findOneBy({
|
||||||
|
@ -244,11 +247,13 @@ export class ReactionService {
|
||||||
//#endregion
|
//#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async getFallbackReaction(): Promise<string> {
|
public async getFallbackReaction(): Promise<string> {
|
||||||
const meta = await this.metaService.fetch();
|
const meta = await this.metaService.fetch();
|
||||||
return meta.useStarForReactionFallback ? '⭐' : '👍';
|
return meta.useStarForReactionFallback ? '⭐' : '👍';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public convertLegacyReactions(reactions: Record<string, number>) {
|
public convertLegacyReactions(reactions: Record<string, number>) {
|
||||||
const _reactions = {} as Record<string, number>;
|
const _reactions = {} as Record<string, number>;
|
||||||
|
|
||||||
|
@ -279,6 +284,7 @@ export class ReactionService {
|
||||||
return _reactions2;
|
return _reactions2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async toDbReaction(reaction?: string | null, reacterHost?: string | null): Promise<string> {
|
public async toDbReaction(reaction?: string | null, reacterHost?: string | null): Promise<string> {
|
||||||
if (reaction == null) return await this.getFallbackReaction();
|
if (reaction == null) return await this.getFallbackReaction();
|
||||||
|
|
||||||
|
@ -311,6 +317,7 @@ export class ReactionService {
|
||||||
return await this.getFallbackReaction();
|
return await this.getFallbackReaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public decodeReaction(str: string): DecodedReaction {
|
public decodeReaction(str: string): DecodedReaction {
|
||||||
const custom = str.match(/^:([\w+-]+)(?:@([\w.-]+))?:$/);
|
const custom = str.match(/^:([\w+-]+)(?:@([\w.-]+))?:$/);
|
||||||
|
|
||||||
|
@ -332,6 +339,7 @@ export class ReactionService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public convertLegacyReaction(reaction: string): string {
|
public convertLegacyReaction(reaction: string): string {
|
||||||
reaction = this.decodeReaction(reaction).reaction;
|
reaction = this.decodeReaction(reaction).reaction;
|
||||||
if (Object.keys(legacies).includes(reaction)) return legacies[reaction];
|
if (Object.keys(legacies).includes(reaction)) return legacies[reaction];
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { DI } from '@/di-symbols.js';
|
||||||
import { deepClone } from '@/misc/clone.js';
|
import { deepClone } from '@/misc/clone.js';
|
||||||
|
|
||||||
const ACTOR_USERNAME = 'relay.actor' as const;
|
const ACTOR_USERNAME = 'relay.actor' as const;
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RelayService {
|
export class RelayService {
|
||||||
|
@ -32,6 +33,7 @@ export class RelayService {
|
||||||
this.relaysCache = new Cache<Relay[]>(1000 * 60 * 10);
|
this.relaysCache = new Cache<Relay[]>(1000 * 60 * 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async getRelayActor(): Promise<ILocalUser> {
|
private async getRelayActor(): Promise<ILocalUser> {
|
||||||
const user = await this.usersRepository.findOneBy({
|
const user = await this.usersRepository.findOneBy({
|
||||||
host: IsNull(),
|
host: IsNull(),
|
||||||
|
@ -44,6 +46,7 @@ export class RelayService {
|
||||||
return created as ILocalUser;
|
return created as ILocalUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async addRelay(inbox: string): Promise<Relay> {
|
public async addRelay(inbox: string): Promise<Relay> {
|
||||||
const relay = await this.relaysRepository.insert({
|
const relay = await this.relaysRepository.insert({
|
||||||
id: this.idService.genId(),
|
id: this.idService.genId(),
|
||||||
|
@ -59,6 +62,7 @@ export class RelayService {
|
||||||
return relay;
|
return relay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async removeRelay(inbox: string): Promise<void> {
|
public async removeRelay(inbox: string): Promise<void> {
|
||||||
const relay = await this.relaysRepository.findOneBy({
|
const relay = await this.relaysRepository.findOneBy({
|
||||||
inbox,
|
inbox,
|
||||||
|
@ -77,11 +81,13 @@ export class RelayService {
|
||||||
await this.relaysRepository.delete(relay.id);
|
await this.relaysRepository.delete(relay.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async listRelay(): Promise<Relay[]> {
|
public async listRelay(): Promise<Relay[]> {
|
||||||
const relays = await this.relaysRepository.find();
|
const relays = await this.relaysRepository.find();
|
||||||
return relays;
|
return relays;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async relayAccepted(id: string): Promise<string> {
|
public async relayAccepted(id: string): Promise<string> {
|
||||||
const result = await this.relaysRepository.update(id, {
|
const result = await this.relaysRepository.update(id, {
|
||||||
status: 'accepted',
|
status: 'accepted',
|
||||||
|
@ -90,6 +96,7 @@ export class RelayService {
|
||||||
return JSON.stringify(result);
|
return JSON.stringify(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async relayRejected(id: string): Promise<string> {
|
public async relayRejected(id: string): Promise<string> {
|
||||||
const result = await this.relaysRepository.update(id, {
|
const result = await this.relaysRepository.update(id, {
|
||||||
status: 'rejected',
|
status: 'rejected',
|
||||||
|
@ -98,6 +105,7 @@ export class RelayService {
|
||||||
return JSON.stringify(result);
|
return JSON.stringify(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async deliverToRelays(user: { id: User['id']; host: null; }, activity: any): Promise<void> {
|
public async deliverToRelays(user: { id: User['id']; host: null; }, activity: any): Promise<void> {
|
||||||
if (activity == null) return;
|
if (activity == null) return;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
import { LoggerService } from '@/core/LoggerService.js';
|
import { LoggerService } from '@/core/LoggerService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RemoteLoggerService {
|
export class RemoteLoggerService {
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { UtilityService } from '@/core/UtilityService.js';
|
||||||
import { WebfingerService } from '@/core/WebfingerService.js';
|
import { WebfingerService } from '@/core/WebfingerService.js';
|
||||||
import { RemoteLoggerService } from '@/core/RemoteLoggerService.js';
|
import { RemoteLoggerService } from '@/core/RemoteLoggerService.js';
|
||||||
import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js';
|
import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RemoteUserResolveService {
|
export class RemoteUserResolveService {
|
||||||
|
@ -31,6 +32,7 @@ export class RemoteUserResolveService {
|
||||||
this.logger = this.remoteLoggerService.logger.createSubLogger('resolve-user');
|
this.logger = this.remoteLoggerService.logger.createSubLogger('resolve-user');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async resolveUser(username: string, host: string | null): Promise<User> {
|
public async resolveUser(username: string, host: string | null): Promise<User> {
|
||||||
const usernameLower = username.toLowerCase();
|
const usernameLower = username.toLowerCase();
|
||||||
|
|
||||||
|
@ -116,6 +118,7 @@ export class RemoteUserResolveService {
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async resolveSelf(acctLower: string) {
|
private async resolveSelf(acctLower: string) {
|
||||||
this.logger.info(`WebFinger for ${chalk.yellow(acctLower)}`);
|
this.logger.info(`WebFinger for ${chalk.yellow(acctLower)}`);
|
||||||
const finger = await this.webfingerService.webfinger(acctLower).catch(err => {
|
const finger = await this.webfingerService.webfinger(acctLower).catch(err => {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { DI } from '@/di-symbols.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import type { Meta } from '@/models/entities/Meta.js';
|
import type { Meta } from '@/models/entities/Meta.js';
|
||||||
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class S3Service {
|
export class S3Service {
|
||||||
|
@ -16,6 +17,7 @@ export class S3Service {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public getS3(meta: Meta) {
|
public getS3(meta: Meta) {
|
||||||
const u = meta.objectStorageEndpoint != null
|
const u = meta.objectStorageEndpoint != null
|
||||||
? `${meta.objectStorageUseSSL ? 'https://' : 'http://'}${meta.objectStorageEndpoint}`
|
? `${meta.objectStorageUseSSL ? 'https://' : 'http://'}${meta.objectStorageEndpoint}`
|
||||||
|
|
|
@ -14,6 +14,7 @@ import generateUserToken from '@/misc/generate-native-user-token.js';
|
||||||
import UsersChart from './chart/charts/users.js';
|
import UsersChart from './chart/charts/users.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { UtilityService } from './UtilityService.js';
|
import { UtilityService } from './UtilityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SignupService {
|
export class SignupService {
|
||||||
|
@ -37,6 +38,7 @@ export class SignupService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async signup(opts: {
|
public async signup(opts: {
|
||||||
username: User['username'];
|
username: User['username'];
|
||||||
password?: string | null;
|
password?: string | null;
|
||||||
|
|
|
@ -103,6 +103,7 @@ function PEMString(pemBuffer: Buffer, type = 'CERTIFICATE') {
|
||||||
`\n-----END ${type}-----\n`
|
`\n-----END ${type}-----\n`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TwoFactorAuthenticationService {
|
export class TwoFactorAuthenticationService {
|
||||||
|
@ -115,6 +116,7 @@ export class TwoFactorAuthenticationService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public hash(data: Buffer) {
|
public hash(data: Buffer) {
|
||||||
return crypto
|
return crypto
|
||||||
.createHash('sha256')
|
.createHash('sha256')
|
||||||
|
@ -122,6 +124,7 @@ export class TwoFactorAuthenticationService {
|
||||||
.digest();
|
.digest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public verifySignin({
|
public verifySignin({
|
||||||
publicKey,
|
publicKey,
|
||||||
authenticatorData,
|
authenticatorData,
|
||||||
|
@ -159,6 +162,7 @@ export class TwoFactorAuthenticationService {
|
||||||
.verify(PEMString(publicKey), signature);
|
.verify(PEMString(publicKey), signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public getProcedures() {
|
public getProcedures() {
|
||||||
return {
|
return {
|
||||||
none: {
|
none: {
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
||||||
import { LoggerService } from '@/core/LoggerService.js';
|
import { LoggerService } from '@/core/LoggerService.js';
|
||||||
import { WebhookService } from '@/core/WebhookService.js';
|
import { WebhookService } from '@/core/WebhookService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UserBlockingService {
|
export class UserBlockingService {
|
||||||
|
@ -50,6 +51,7 @@ export class UserBlockingService {
|
||||||
this.logger = this.loggerService.getLogger('user-block');
|
this.logger = this.loggerService.getLogger('user-block');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async block(blocker: User, blockee: User) {
|
public async block(blocker: User, blockee: User) {
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
this.cancelRequest(blocker, blockee),
|
this.cancelRequest(blocker, blockee),
|
||||||
|
@ -76,6 +78,7 @@ export class UserBlockingService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async cancelRequest(follower: User, followee: User) {
|
private async cancelRequest(follower: User, followee: User) {
|
||||||
const request = await this.followRequestsRepository.findOneBy({
|
const request = await this.followRequestsRepository.findOneBy({
|
||||||
followeeId: followee.id,
|
followeeId: followee.id,
|
||||||
|
@ -126,6 +129,7 @@ export class UserBlockingService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async unFollow(follower: User, followee: User) {
|
private async unFollow(follower: User, followee: User) {
|
||||||
const following = await this.followingsRepository.findOneBy({
|
const following = await this.followingsRepository.findOneBy({
|
||||||
followerId: follower.id,
|
followerId: follower.id,
|
||||||
|
@ -167,6 +171,7 @@ export class UserBlockingService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async removeFromList(listOwner: User, user: User) {
|
private async removeFromList(listOwner: User, user: User) {
|
||||||
const userLists = await this.userListsRepository.findBy({
|
const userLists = await this.userListsRepository.findBy({
|
||||||
userId: listOwner.id,
|
userId: listOwner.id,
|
||||||
|
@ -180,6 +185,7 @@ export class UserBlockingService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async unblock(blocker: CacheableUser, blockee: CacheableUser) {
|
public async unblock(blocker: CacheableUser, blockee: CacheableUser) {
|
||||||
const blocking = await this.blockingsRepository.findOneBy({
|
const blocking = await this.blockingsRepository.findOneBy({
|
||||||
blockerId: blocker.id,
|
blockerId: blocker.id,
|
||||||
|
|
|
@ -6,6 +6,7 @@ import type { CacheableLocalUser, CacheableUser, ILocalUser } from '@/models/ent
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import type { OnApplicationShutdown } from '@nestjs/common';
|
import type { OnApplicationShutdown } from '@nestjs/common';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UserCacheService implements OnApplicationShutdown {
|
export class UserCacheService implements OnApplicationShutdown {
|
||||||
|
@ -23,7 +24,7 @@ export class UserCacheService implements OnApplicationShutdown {
|
||||||
|
|
||||||
private userEntityService: UserEntityService,
|
private userEntityService: UserEntityService,
|
||||||
) {
|
) {
|
||||||
this.onMessage = this.onMessage.bind(this);
|
//this.onMessage = this.onMessage.bind(this);
|
||||||
|
|
||||||
this.userByIdCache = new Cache<CacheableUser>(Infinity);
|
this.userByIdCache = new Cache<CacheableUser>(Infinity);
|
||||||
this.localUserByNativeTokenCache = new Cache<CacheableLocalUser | null>(Infinity);
|
this.localUserByNativeTokenCache = new Cache<CacheableLocalUser | null>(Infinity);
|
||||||
|
@ -33,6 +34,7 @@ export class UserCacheService implements OnApplicationShutdown {
|
||||||
this.redisSubscriber.on('message', this.onMessage);
|
this.redisSubscriber.on('message', this.onMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async onMessage(_: string, data: string): Promise<void> {
|
private async onMessage(_: string, data: string): Promise<void> {
|
||||||
const obj = JSON.parse(data);
|
const obj = JSON.parse(data);
|
||||||
|
|
||||||
|
@ -68,6 +70,7 @@ export class UserCacheService implements OnApplicationShutdown {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public onApplicationShutdown(signal?: string | undefined) {
|
public onApplicationShutdown(signal?: string | undefined) {
|
||||||
this.redisSubscriber.off('message', this.onMessage);
|
this.redisSubscriber.off('message', this.onMessage);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ type Remote = IRemoteUser | {
|
||||||
inbox: IRemoteUser['inbox'];
|
inbox: IRemoteUser['inbox'];
|
||||||
};
|
};
|
||||||
type Both = Local | Remote;
|
type Both = Local | Remote;
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UserFollowingService {
|
export class UserFollowingService {
|
||||||
|
@ -66,6 +67,7 @@ export class UserFollowingService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async follow(_follower: { id: User['id'] }, _followee: { id: User['id'] }, requestId?: string): Promise<void> {
|
public async follow(_follower: { id: User['id'] }, _followee: { id: User['id'] }, requestId?: string): Promise<void> {
|
||||||
const [follower, followee] = await Promise.all([
|
const [follower, followee] = await Promise.all([
|
||||||
this.usersRepository.findOneByOrFail({ id: _follower.id }),
|
this.usersRepository.findOneByOrFail({ id: _follower.id }),
|
||||||
|
@ -140,6 +142,7 @@ export class UserFollowingService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async insertFollowingDoc(
|
private async insertFollowingDoc(
|
||||||
followee: {
|
followee: {
|
||||||
id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']
|
id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox']
|
||||||
|
@ -253,6 +256,7 @@ export class UserFollowingService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async unfollow(
|
public async unfollow(
|
||||||
follower: {
|
follower: {
|
||||||
id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox'];
|
id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox'];
|
||||||
|
@ -305,6 +309,7 @@ export class UserFollowingService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async decrementFollowing(
|
private async decrementFollowing(
|
||||||
follower: {id: User['id']; host: User['host']; },
|
follower: {id: User['id']; host: User['host']; },
|
||||||
followee: { id: User['id']; host: User['host']; },
|
followee: { id: User['id']; host: User['host']; },
|
||||||
|
@ -333,6 +338,7 @@ export class UserFollowingService {
|
||||||
this.perUserFollowingChart.update(follower, followee, false);
|
this.perUserFollowingChart.update(follower, followee, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async createFollowRequest(
|
public async createFollowRequest(
|
||||||
follower: {
|
follower: {
|
||||||
id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox'];
|
id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox'];
|
||||||
|
@ -396,6 +402,7 @@ export class UserFollowingService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async cancelFollowRequest(
|
public async cancelFollowRequest(
|
||||||
followee: {
|
followee: {
|
||||||
id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']
|
id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']
|
||||||
|
@ -431,6 +438,7 @@ export class UserFollowingService {
|
||||||
}).then(packed => this.globalEventServie.publishMainStream(followee.id, 'meUpdated', packed));
|
}).then(packed => this.globalEventServie.publishMainStream(followee.id, 'meUpdated', packed));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async acceptFollowRequest(
|
public async acceptFollowRequest(
|
||||||
followee: {
|
followee: {
|
||||||
id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox'];
|
id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox'];
|
||||||
|
@ -458,6 +466,7 @@ export class UserFollowingService {
|
||||||
}).then(packed => this.globalEventServie.publishMainStream(followee.id, 'meUpdated', packed));
|
}).then(packed => this.globalEventServie.publishMainStream(followee.id, 'meUpdated', packed));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async acceptAllFollowRequests(
|
public async acceptAllFollowRequests(
|
||||||
user: {
|
user: {
|
||||||
id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox'];
|
id: User['id']; host: User['host']; uri: User['host']; inbox: User['inbox']; sharedInbox: User['sharedInbox'];
|
||||||
|
@ -476,6 +485,7 @@ export class UserFollowingService {
|
||||||
/**
|
/**
|
||||||
* API following/request/reject
|
* API following/request/reject
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async rejectFollowRequest(user: Local, follower: Both): Promise<void> {
|
public async rejectFollowRequest(user: Local, follower: Both): Promise<void> {
|
||||||
if (this.userEntityService.isRemoteUser(follower)) {
|
if (this.userEntityService.isRemoteUser(follower)) {
|
||||||
this.deliverReject(user, follower);
|
this.deliverReject(user, follower);
|
||||||
|
@ -491,6 +501,7 @@ export class UserFollowingService {
|
||||||
/**
|
/**
|
||||||
* API following/reject
|
* API following/reject
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async rejectFollow(user: Local, follower: Both): Promise<void> {
|
public async rejectFollow(user: Local, follower: Both): Promise<void> {
|
||||||
if (this.userEntityService.isRemoteUser(follower)) {
|
if (this.userEntityService.isRemoteUser(follower)) {
|
||||||
this.deliverReject(user, follower);
|
this.deliverReject(user, follower);
|
||||||
|
@ -506,6 +517,7 @@ export class UserFollowingService {
|
||||||
/**
|
/**
|
||||||
* AP Reject/Follow
|
* AP Reject/Follow
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async remoteReject(actor: Remote, follower: Local): Promise<void> {
|
public async remoteReject(actor: Remote, follower: Local): Promise<void> {
|
||||||
await this.removeFollowRequest(actor, follower);
|
await this.removeFollowRequest(actor, follower);
|
||||||
await this.removeFollow(actor, follower);
|
await this.removeFollow(actor, follower);
|
||||||
|
@ -515,6 +527,7 @@ export class UserFollowingService {
|
||||||
/**
|
/**
|
||||||
* Remove follow request record
|
* Remove follow request record
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
private async removeFollowRequest(followee: Both, follower: Both): Promise<void> {
|
private async removeFollowRequest(followee: Both, follower: Both): Promise<void> {
|
||||||
const request = await this.followRequestsRepository.findOneBy({
|
const request = await this.followRequestsRepository.findOneBy({
|
||||||
followeeId: followee.id,
|
followeeId: followee.id,
|
||||||
|
@ -529,6 +542,7 @@ export class UserFollowingService {
|
||||||
/**
|
/**
|
||||||
* Remove follow record
|
* Remove follow record
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
private async removeFollow(followee: Both, follower: Both): Promise<void> {
|
private async removeFollow(followee: Both, follower: Both): Promise<void> {
|
||||||
const following = await this.followingsRepository.findOneBy({
|
const following = await this.followingsRepository.findOneBy({
|
||||||
followeeId: followee.id,
|
followeeId: followee.id,
|
||||||
|
@ -544,6 +558,7 @@ export class UserFollowingService {
|
||||||
/**
|
/**
|
||||||
* Deliver Reject to remote
|
* Deliver Reject to remote
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
private async deliverReject(followee: Local, follower: Remote): Promise<void> {
|
private async deliverReject(followee: Local, follower: Remote): Promise<void> {
|
||||||
const request = await this.followRequestsRepository.findOneBy({
|
const request = await this.followRequestsRepository.findOneBy({
|
||||||
followeeId: followee.id,
|
followeeId: followee.id,
|
||||||
|
@ -557,6 +572,7 @@ export class UserFollowingService {
|
||||||
/**
|
/**
|
||||||
* Publish unfollow to local
|
* Publish unfollow to local
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
private async publishUnfollow(followee: Both, follower: Local): Promise<void> {
|
private async publishUnfollow(followee: Both, follower: Local): Promise<void> {
|
||||||
const packedFollowee = await this.userEntityService.pack(followee.id, follower, {
|
const packedFollowee = await this.userEntityService.pack(followee.id, follower, {
|
||||||
detail: true,
|
detail: true,
|
||||||
|
|
|
@ -4,6 +4,7 @@ import type { UserKeypairsRepository } from '@/models/index.js';
|
||||||
import { Cache } from '@/misc/cache.js';
|
import { Cache } from '@/misc/cache.js';
|
||||||
import type { UserKeypair } from '@/models/entities/UserKeypair.js';
|
import type { UserKeypair } from '@/models/entities/UserKeypair.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UserKeypairStoreService {
|
export class UserKeypairStoreService {
|
||||||
|
@ -16,6 +17,7 @@ export class UserKeypairStoreService {
|
||||||
this.cache = new Cache<UserKeypair>(Infinity);
|
this.cache = new Cache<UserKeypair>(Infinity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async getUserKeypair(userId: User['id']): Promise<UserKeypair> {
|
public async getUserKeypair(userId: User['id']): Promise<UserKeypair> {
|
||||||
return await this.cache.fetch(userId, () => this.userKeypairsRepository.findOneByOrFail({ userId: userId }));
|
return await this.cache.fetch(userId, () => this.userKeypairsRepository.findOneByOrFail({ userId: userId }));
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { ProxyAccountService } from '@/core/ProxyAccountService.js';
|
import { ProxyAccountService } from '@/core/ProxyAccountService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UserListService {
|
export class UserListService {
|
||||||
|
@ -27,6 +28,7 @@ export class UserListService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async push(target: User, list: UserList) {
|
public async push(target: User, list: UserList) {
|
||||||
await this.userListJoiningsRepository.insert({
|
await this.userListJoiningsRepository.insert({
|
||||||
id: this.idService.genId(),
|
id: this.idService.genId(),
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { QueueService } from '@/core/QueueService.js';
|
||||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||||
import type { User } from '@/models/entities/User.js';
|
import type { User } from '@/models/entities/User.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UserMutingService {
|
export class UserMutingService {
|
||||||
|
@ -21,6 +22,7 @@ export class UserMutingService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async mute(user: User, target: User): Promise<void> {
|
public async mute(user: User, target: User): Promise<void> {
|
||||||
await this.mutingsRepository.insert({
|
await this.mutingsRepository.insert({
|
||||||
id: this.idService.genId(),
|
id: this.idService.genId(),
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { DI } from '@/di-symbols.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UserSuspendService {
|
export class UserSuspendService {
|
||||||
|
@ -28,6 +29,7 @@ export class UserSuspendService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async doPostSuspend(user: { id: User['id']; host: User['host'] }): Promise<void> {
|
public async doPostSuspend(user: { id: User['id']; host: User['host'] }): Promise<void> {
|
||||||
this.globalEventService.publishInternalEvent('userChangeSuspendedState', { id: user.id, isSuspended: true });
|
this.globalEventService.publishInternalEvent('userChangeSuspendedState', { id: user.id, isSuspended: true });
|
||||||
|
|
||||||
|
@ -57,6 +59,7 @@ export class UserSuspendService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async doPostUnsuspend(user: User): Promise<void> {
|
public async doPostUnsuspend(user: User): Promise<void> {
|
||||||
this.globalEventService.publishInternalEvent('userChangeSuspendedState', { id: user.id, isSuspended: false });
|
this.globalEventService.publishInternalEvent('userChangeSuspendedState', { id: user.id, isSuspended: false });
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { toASCII } from 'punycode';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UtilityService {
|
export class UtilityService {
|
||||||
|
@ -12,24 +13,29 @@ export class UtilityService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public getFullApAccount(username: string, host: string | null): string {
|
public getFullApAccount(username: string, host: string | null): string {
|
||||||
return host ? `${username}@${this.toPuny(host)}` : `${username}@${this.toPuny(this.config.host)}`;
|
return host ? `${username}@${this.toPuny(host)}` : `${username}@${this.toPuny(this.config.host)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public isSelfHost(host: string | null): boolean {
|
public isSelfHost(host: string | null): boolean {
|
||||||
if (host == null) return true;
|
if (host == null) return true;
|
||||||
return this.toPuny(this.config.host) === this.toPuny(host);
|
return this.toPuny(this.config.host) === this.toPuny(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public extractDbHost(uri: string): string {
|
public extractDbHost(uri: string): string {
|
||||||
const url = new URL(uri);
|
const url = new URL(uri);
|
||||||
return this.toPuny(url.hostname);
|
return this.toPuny(url.hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public toPuny(host: string): string {
|
public toPuny(host: string): string {
|
||||||
return toASCII(host.toLowerCase());
|
return toASCII(host.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public toPunyNullable(host: string | null | undefined): string | null {
|
public toPunyNullable(host: string | null | undefined): string | null {
|
||||||
if (host == null) return null;
|
if (host == null) return null;
|
||||||
return toASCII(host.toLowerCase());
|
return toASCII(host.toLowerCase());
|
||||||
|
|
|
@ -5,6 +5,7 @@ import type { Config } from '@/config.js';
|
||||||
import { ImageProcessingService } from '@/core/ImageProcessingService.js';
|
import { ImageProcessingService } from '@/core/ImageProcessingService.js';
|
||||||
import type { IImage } from '@/core/ImageProcessingService.js';
|
import type { IImage } from '@/core/ImageProcessingService.js';
|
||||||
import { createTempDir } from '@/misc/create-temp.js';
|
import { createTempDir } from '@/misc/create-temp.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class VideoProcessingService {
|
export class VideoProcessingService {
|
||||||
|
@ -16,6 +17,7 @@ export class VideoProcessingService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async generateVideoThumbnail(source: string): Promise<IImage> {
|
public async generateVideoThumbnail(source: string): Promise<IImage> {
|
||||||
const [dir, cleanup] = await createTempDir();
|
const [dir, cleanup] = await createTempDir();
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ type IWebFinger = {
|
||||||
links: ILink[];
|
links: ILink[];
|
||||||
subject: string;
|
subject: string;
|
||||||
};
|
};
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class WebfingerService {
|
export class WebfingerService {
|
||||||
|
@ -25,12 +26,14 @@ export class WebfingerService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async webfinger(query: string): Promise<IWebFinger> {
|
public async webfinger(query: string): Promise<IWebFinger> {
|
||||||
const url = this.genUrl(query);
|
const url = this.genUrl(query);
|
||||||
|
|
||||||
return await this.httpRequestService.getJson(url, 'application/jrd+json, application/json') as IWebFinger;
|
return await this.httpRequestService.getJson(url, 'application/jrd+json, application/json') as IWebFinger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private genUrl(query: string): string {
|
private genUrl(query: string): string {
|
||||||
if (query.match(/^https?:\/\//)) {
|
if (query.match(/^https?:\/\//)) {
|
||||||
const u = new URL(query);
|
const u = new URL(query);
|
||||||
|
|
|
@ -4,6 +4,7 @@ import type { WebhooksRepository } from '@/models/index.js';
|
||||||
import type { Webhook } from '@/models/entities/Webhook.js';
|
import type { Webhook } from '@/models/entities/Webhook.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { OnApplicationShutdown } from '@nestjs/common';
|
import type { OnApplicationShutdown } from '@nestjs/common';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class WebhookService implements OnApplicationShutdown {
|
export class WebhookService implements OnApplicationShutdown {
|
||||||
|
@ -17,10 +18,11 @@ export class WebhookService implements OnApplicationShutdown {
|
||||||
@Inject(DI.webhooksRepository)
|
@Inject(DI.webhooksRepository)
|
||||||
private webhooksRepository: WebhooksRepository,
|
private webhooksRepository: WebhooksRepository,
|
||||||
) {
|
) {
|
||||||
this.onMessage = this.onMessage.bind(this);
|
//this.onMessage = this.onMessage.bind(this);
|
||||||
this.redisSubscriber.on('message', this.onMessage);
|
this.redisSubscriber.on('message', this.onMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async getActiveWebhooks() {
|
public async getActiveWebhooks() {
|
||||||
if (!this.webhooksFetched) {
|
if (!this.webhooksFetched) {
|
||||||
this.webhooks = await this.webhooksRepository.findBy({
|
this.webhooks = await this.webhooksRepository.findBy({
|
||||||
|
@ -32,6 +34,7 @@ export class WebhookService implements OnApplicationShutdown {
|
||||||
return this.webhooks;
|
return this.webhooks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async onMessage(_: string, data: string): Promise<void> {
|
private async onMessage(_: string, data: string): Promise<void> {
|
||||||
const obj = JSON.parse(data);
|
const obj = JSON.parse(data);
|
||||||
|
|
||||||
|
@ -64,6 +67,7 @@ export class WebhookService implements OnApplicationShutdown {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public onApplicationShutdown(signal?: string | undefined) {
|
public onApplicationShutdown(signal?: string | undefined) {
|
||||||
this.redisSubscriber.off('message', this.onMessage);
|
this.redisSubscriber.off('message', this.onMessage);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import promiseLimit from 'promise-limit';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { CacheableRemoteUser, CacheableUser } from '@/models/entities/User.js';
|
import type { CacheableRemoteUser, CacheableUser } from '@/models/entities/User.js';
|
||||||
import { concat, toArray, toSingle, unique } from '@/misc/prelude/array.js';
|
import { concat, toArray, toSingle, unique } from '@/misc/prelude/array.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import { getApId, getApIds, getApType, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isPost, isRead, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js';
|
import { getApId, getApIds, getApType, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isPost, isRead, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js';
|
||||||
import { ApPersonService } from './models/ApPersonService.js';
|
import { ApPersonService } from './models/ApPersonService.js';
|
||||||
import type { ApObject } from './type.js';
|
import type { ApObject } from './type.js';
|
||||||
|
@ -24,6 +25,7 @@ export class ApAudienceService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async parseAudience(actor: CacheableRemoteUser, to?: ApObject, cc?: ApObject, resolver?: Resolver): Promise<AudienceInfo> {
|
public async parseAudience(actor: CacheableRemoteUser, to?: ApObject, cc?: ApObject, resolver?: Resolver): Promise<AudienceInfo> {
|
||||||
const toGroups = this.groupingAudience(getApIds(to), actor);
|
const toGroups = this.groupingAudience(getApIds(to), actor);
|
||||||
const ccGroups = this.groupingAudience(getApIds(cc), actor);
|
const ccGroups = this.groupingAudience(getApIds(cc), actor);
|
||||||
|
@ -66,6 +68,7 @@ export class ApAudienceService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private groupingAudience(ids: string[], actor: CacheableRemoteUser) {
|
private groupingAudience(ids: string[], actor: CacheableRemoteUser) {
|
||||||
const groups = {
|
const groups = {
|
||||||
public: [] as string[],
|
public: [] as string[],
|
||||||
|
@ -88,6 +91,7 @@ export class ApAudienceService {
|
||||||
return groups;
|
return groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private isPublic(id: string) {
|
private isPublic(id: string) {
|
||||||
return [
|
return [
|
||||||
'https://www.w3.org/ns/activitystreams#Public',
|
'https://www.w3.org/ns/activitystreams#Public',
|
||||||
|
@ -96,6 +100,7 @@ export class ApAudienceService {
|
||||||
].includes(id);
|
].includes(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private isFollowers(id: string, actor: CacheableRemoteUser) {
|
private isFollowers(id: string, actor: CacheableRemoteUser) {
|
||||||
return (
|
return (
|
||||||
id === (actor.followersUri ?? `${actor.uri}/followers`)
|
id === (actor.followersUri ?? `${actor.uri}/followers`)
|
||||||
|
|
|
@ -9,6 +9,7 @@ import type { UserPublickey } from '@/models/entities/UserPublickey.js';
|
||||||
import { UserCacheService } from '@/core/UserCacheService.js';
|
import { UserCacheService } from '@/core/UserCacheService.js';
|
||||||
import type { Note } from '@/models/entities/Note.js';
|
import type { Note } from '@/models/entities/Note.js';
|
||||||
import type { MessagingMessage } from '@/models/entities/MessagingMessage.js';
|
import type { MessagingMessage } from '@/models/entities/MessagingMessage.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import { getApId } from './type.js';
|
import { getApId } from './type.js';
|
||||||
import { ApPersonService } from './models/ApPersonService.js';
|
import { ApPersonService } from './models/ApPersonService.js';
|
||||||
import type { IObject } from './type.js';
|
import type { IObject } from './type.js';
|
||||||
|
@ -57,6 +58,7 @@ export class ApDbResolverService {
|
||||||
this.publicKeyByUserIdCache = new Cache<UserPublickey | null>(Infinity);
|
this.publicKeyByUserIdCache = new Cache<UserPublickey | null>(Infinity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public parseUri(value: string | IObject): UriParseResult {
|
public parseUri(value: string | IObject): UriParseResult {
|
||||||
const uri = getApId(value);
|
const uri = getApId(value);
|
||||||
|
|
||||||
|
@ -82,6 +84,7 @@ export class ApDbResolverService {
|
||||||
/**
|
/**
|
||||||
* AP Note => Misskey Note in DB
|
* AP Note => Misskey Note in DB
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async getNoteFromApId(value: string | IObject): Promise<Note | null> {
|
public async getNoteFromApId(value: string | IObject): Promise<Note | null> {
|
||||||
const parsed = this.parseUri(value);
|
const parsed = this.parseUri(value);
|
||||||
|
|
||||||
|
@ -98,6 +101,7 @@ export class ApDbResolverService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async getMessageFromApId(value: string | IObject): Promise<MessagingMessage | null> {
|
public async getMessageFromApId(value: string | IObject): Promise<MessagingMessage | null> {
|
||||||
const parsed = this.parseUri(value);
|
const parsed = this.parseUri(value);
|
||||||
|
|
||||||
|
@ -117,6 +121,7 @@ export class ApDbResolverService {
|
||||||
/**
|
/**
|
||||||
* AP Person => Misskey User in DB
|
* AP Person => Misskey User in DB
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async getUserFromApId(value: string | IObject): Promise<CacheableUser | null> {
|
public async getUserFromApId(value: string | IObject): Promise<CacheableUser | null> {
|
||||||
const parsed = this.parseUri(value);
|
const parsed = this.parseUri(value);
|
||||||
|
|
||||||
|
@ -136,6 +141,7 @@ export class ApDbResolverService {
|
||||||
/**
|
/**
|
||||||
* AP KeyId => Misskey User and Key
|
* AP KeyId => Misskey User and Key
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async getAuthUserFromKeyId(keyId: string): Promise<{
|
public async getAuthUserFromKeyId(keyId: string): Promise<{
|
||||||
user: CacheableRemoteUser;
|
user: CacheableRemoteUser;
|
||||||
key: UserPublickey;
|
key: UserPublickey;
|
||||||
|
@ -161,6 +167,7 @@ export class ApDbResolverService {
|
||||||
/**
|
/**
|
||||||
* AP Actor id => Misskey User and Key
|
* AP Actor id => Misskey User and Key
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async getAuthUserFromApId(uri: string): Promise<{
|
public async getAuthUserFromApId(uri: string): Promise<{
|
||||||
user: CacheableRemoteUser;
|
user: CacheableRemoteUser;
|
||||||
key: UserPublickey | null;
|
key: UserPublickey | null;
|
||||||
|
|
|
@ -6,6 +6,7 @@ import type { Config } from '@/config.js';
|
||||||
import type { ILocalUser, IRemoteUser, User } from '@/models/entities/User.js';
|
import type { ILocalUser, IRemoteUser, User } from '@/models/entities/User.js';
|
||||||
import { QueueService } from '@/core/QueueService.js';
|
import { QueueService } from '@/core/QueueService.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
interface IRecipe {
|
interface IRecipe {
|
||||||
type: string;
|
type: string;
|
||||||
|
@ -48,6 +49,7 @@ export class ApDeliverManagerService {
|
||||||
* @param activity Activity
|
* @param activity Activity
|
||||||
* @param from Followee
|
* @param from Followee
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async deliverToFollowers(actor: { id: ILocalUser['id']; host: null; }, activity: any) {
|
public async deliverToFollowers(actor: { id: ILocalUser['id']; host: null; }, activity: any) {
|
||||||
const manager = new DeliverManager(
|
const manager = new DeliverManager(
|
||||||
this.userEntityService,
|
this.userEntityService,
|
||||||
|
@ -65,6 +67,7 @@ export class ApDeliverManagerService {
|
||||||
* @param activity Activity
|
* @param activity Activity
|
||||||
* @param to Target user
|
* @param to Target user
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async deliverToUser(actor: { id: ILocalUser['id']; host: null; }, activity: any, to: IRemoteUser) {
|
public async deliverToUser(actor: { id: ILocalUser['id']; host: null; }, activity: any, to: IRemoteUser) {
|
||||||
const manager = new DeliverManager(
|
const manager = new DeliverManager(
|
||||||
this.userEntityService,
|
this.userEntityService,
|
||||||
|
@ -77,6 +80,7 @@ export class ApDeliverManagerService {
|
||||||
await manager.execute();
|
await manager.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public createDeliverManager(actor: { id: User['id']; host: null; }, activity: any) {
|
public createDeliverManager(actor: { id: User['id']; host: null; }, activity: any) {
|
||||||
return new DeliverManager(
|
return new DeliverManager(
|
||||||
this.userEntityService,
|
this.userEntityService,
|
||||||
|
@ -114,6 +118,7 @@ class DeliverManager {
|
||||||
/**
|
/**
|
||||||
* Add recipe for followers deliver
|
* Add recipe for followers deliver
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public addFollowersRecipe() {
|
public addFollowersRecipe() {
|
||||||
const deliver = {
|
const deliver = {
|
||||||
type: 'Followers',
|
type: 'Followers',
|
||||||
|
@ -126,6 +131,7 @@ class DeliverManager {
|
||||||
* Add recipe for direct deliver
|
* Add recipe for direct deliver
|
||||||
* @param to To
|
* @param to To
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public addDirectRecipe(to: IRemoteUser) {
|
public addDirectRecipe(to: IRemoteUser) {
|
||||||
const recipe = {
|
const recipe = {
|
||||||
type: 'Direct',
|
type: 'Direct',
|
||||||
|
@ -139,6 +145,7 @@ class DeliverManager {
|
||||||
* Add recipe
|
* Add recipe
|
||||||
* @param recipe Recipe
|
* @param recipe Recipe
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public addRecipe(recipe: IRecipe) {
|
public addRecipe(recipe: IRecipe) {
|
||||||
this.recipes.push(recipe);
|
this.recipes.push(recipe);
|
||||||
}
|
}
|
||||||
|
@ -146,6 +153,7 @@ class DeliverManager {
|
||||||
/**
|
/**
|
||||||
* Execute delivers
|
* Execute delivers
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async execute() {
|
public async execute() {
|
||||||
if (!this.userEntityService.isLocalUser(this.actor)) return;
|
if (!this.userEntityService.isLocalUser(this.actor)) return;
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ import { ApPersonService } from './models/ApPersonService.js';
|
||||||
import { ApQuestionService } from './models/ApQuestionService.js';
|
import { ApQuestionService } from './models/ApQuestionService.js';
|
||||||
import type { Resolver } from './ApResolverService.js';
|
import type { Resolver } from './ApResolverService.js';
|
||||||
import type { IAccept, IAdd, IAnnounce, IBlock, ICreate, IDelete, IFlag, IFollow, ILike, IObject, IRead, IReject, IRemove, IUndo, IUpdate } from './type.js';
|
import type { IAccept, IAdd, IAnnounce, IBlock, ICreate, IDelete, IFlag, IFollow, ILike, IObject, IRead, IReject, IRemove, IUndo, IUpdate } from './type.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ApInboxService {
|
export class ApInboxService {
|
||||||
|
@ -85,6 +86,7 @@ export class ApInboxService {
|
||||||
this.logger = this.apLoggerService.logger;
|
this.logger = this.apLoggerService.logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async performActivity(actor: CacheableRemoteUser, activity: IObject) {
|
public async performActivity(actor: CacheableRemoteUser, activity: IObject) {
|
||||||
if (isCollectionOrOrderedCollection(activity)) {
|
if (isCollectionOrOrderedCollection(activity)) {
|
||||||
const resolver = this.apResolverService.createResolver();
|
const resolver = this.apResolverService.createResolver();
|
||||||
|
@ -112,6 +114,7 @@ export class ApInboxService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async performOneActivity(actor: CacheableRemoteUser, activity: IObject): Promise<void> {
|
public async performOneActivity(actor: CacheableRemoteUser, activity: IObject): Promise<void> {
|
||||||
if (actor.isSuspended) return;
|
if (actor.isSuspended) return;
|
||||||
|
|
||||||
|
@ -148,6 +151,7 @@ export class ApInboxService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async follow(actor: CacheableRemoteUser, activity: IFollow): Promise<string> {
|
private async follow(actor: CacheableRemoteUser, activity: IFollow): Promise<string> {
|
||||||
const followee = await this.apDbResolverService.getUserFromApId(activity.object);
|
const followee = await this.apDbResolverService.getUserFromApId(activity.object);
|
||||||
|
|
||||||
|
@ -163,6 +167,7 @@ export class ApInboxService {
|
||||||
return 'ok';
|
return 'ok';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async like(actor: CacheableRemoteUser, activity: ILike): Promise<string> {
|
private async like(actor: CacheableRemoteUser, activity: ILike): Promise<string> {
|
||||||
const targetUri = getApId(activity.object);
|
const targetUri = getApId(activity.object);
|
||||||
|
|
||||||
|
@ -180,6 +185,7 @@ export class ApInboxService {
|
||||||
}).then(() => 'ok');
|
}).then(() => 'ok');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async read(actor: CacheableRemoteUser, activity: IRead): Promise<string> {
|
private async read(actor: CacheableRemoteUser, activity: IRead): Promise<string> {
|
||||||
const id = await getApId(activity.object);
|
const id = await getApId(activity.object);
|
||||||
|
|
||||||
|
@ -202,6 +208,7 @@ export class ApInboxService {
|
||||||
return `ok: mark as read (${message.userId} => ${message.recipientId} ${message.id})`;
|
return `ok: mark as read (${message.userId} => ${message.recipientId} ${message.id})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async accept(actor: CacheableRemoteUser, activity: IAccept): Promise<string> {
|
private async accept(actor: CacheableRemoteUser, activity: IAccept): Promise<string> {
|
||||||
const uri = activity.id ?? activity;
|
const uri = activity.id ?? activity;
|
||||||
|
|
||||||
|
@ -219,6 +226,7 @@ export class ApInboxService {
|
||||||
return `skip: Unknown Accept type: ${getApType(object)}`;
|
return `skip: Unknown Accept type: ${getApType(object)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async acceptFollow(actor: CacheableRemoteUser, activity: IFollow): Promise<string> {
|
private async acceptFollow(actor: CacheableRemoteUser, activity: IFollow): Promise<string> {
|
||||||
// ※ activityはこっちから投げたフォローリクエストなので、activity.actorは存在するローカルユーザーである必要がある
|
// ※ activityはこっちから投げたフォローリクエストなので、activity.actorは存在するローカルユーザーである必要がある
|
||||||
|
|
||||||
|
@ -242,6 +250,7 @@ export class ApInboxService {
|
||||||
return 'ok';
|
return 'ok';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async add(actor: CacheableRemoteUser, activity: IAdd): Promise<void> {
|
private async add(actor: CacheableRemoteUser, activity: IAdd): Promise<void> {
|
||||||
if ('actor' in activity && actor.uri !== activity.actor) {
|
if ('actor' in activity && actor.uri !== activity.actor) {
|
||||||
throw new Error('invalid actor');
|
throw new Error('invalid actor');
|
||||||
|
@ -261,6 +270,7 @@ export class ApInboxService {
|
||||||
throw new Error(`unknown target: ${activity.target}`);
|
throw new Error(`unknown target: ${activity.target}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async announce(actor: CacheableRemoteUser, activity: IAnnounce): Promise<void> {
|
private async announce(actor: CacheableRemoteUser, activity: IAnnounce): Promise<void> {
|
||||||
const uri = getApId(activity);
|
const uri = getApId(activity);
|
||||||
|
|
||||||
|
@ -271,6 +281,7 @@ export class ApInboxService {
|
||||||
this.announceNote(actor, activity, targetUri);
|
this.announceNote(actor, activity, targetUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async announceNote(actor: CacheableRemoteUser, activity: IAnnounce, targetUri: string): Promise<void> {
|
private async announceNote(actor: CacheableRemoteUser, activity: IAnnounce, targetUri: string): Promise<void> {
|
||||||
const uri = getApId(activity);
|
const uri = getApId(activity);
|
||||||
|
|
||||||
|
@ -330,6 +341,7 @@ export class ApInboxService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async block(actor: CacheableRemoteUser, activity: IBlock): Promise<string> {
|
private async block(actor: CacheableRemoteUser, activity: IBlock): Promise<string> {
|
||||||
// ※ activity.objectにブロック対象があり、それは存在するローカルユーザーのはず
|
// ※ activity.objectにブロック対象があり、それは存在するローカルユーザーのはず
|
||||||
|
|
||||||
|
@ -347,6 +359,7 @@ export class ApInboxService {
|
||||||
return 'ok';
|
return 'ok';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async create(actor: CacheableRemoteUser, activity: ICreate): Promise<void> {
|
private async create(actor: CacheableRemoteUser, activity: ICreate): Promise<void> {
|
||||||
const uri = getApId(activity);
|
const uri = getApId(activity);
|
||||||
|
|
||||||
|
@ -382,6 +395,7 @@ export class ApInboxService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async createNote(resolver: Resolver, actor: CacheableRemoteUser, note: IObject, silent = false, activity?: ICreate): Promise<string> {
|
private async createNote(resolver: Resolver, actor: CacheableRemoteUser, note: IObject, silent = false, activity?: ICreate): Promise<string> {
|
||||||
const uri = getApId(note);
|
const uri = getApId(note);
|
||||||
|
|
||||||
|
@ -416,6 +430,7 @@ export class ApInboxService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async delete(actor: CacheableRemoteUser, activity: IDelete): Promise<string> {
|
private async delete(actor: CacheableRemoteUser, activity: IDelete): Promise<string> {
|
||||||
if ('actor' in activity && actor.uri !== activity.actor) {
|
if ('actor' in activity && actor.uri !== activity.actor) {
|
||||||
throw new Error('invalid actor');
|
throw new Error('invalid actor');
|
||||||
|
@ -457,6 +472,7 @@ export class ApInboxService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async deleteActor(actor: CacheableRemoteUser, uri: string): Promise<string> {
|
private async deleteActor(actor: CacheableRemoteUser, uri: string): Promise<string> {
|
||||||
this.logger.info(`Deleting the Actor: ${uri}`);
|
this.logger.info(`Deleting the Actor: ${uri}`);
|
||||||
|
|
||||||
|
@ -478,6 +494,7 @@ export class ApInboxService {
|
||||||
return `ok: queued ${job.name} ${job.id}`;
|
return `ok: queued ${job.name} ${job.id}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async deleteNote(actor: CacheableRemoteUser, uri: string): Promise<string> {
|
private async deleteNote(actor: CacheableRemoteUser, uri: string): Promise<string> {
|
||||||
this.logger.info(`Deleting the Note: ${uri}`);
|
this.logger.info(`Deleting the Note: ${uri}`);
|
||||||
|
|
||||||
|
@ -510,6 +527,7 @@ export class ApInboxService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async flag(actor: CacheableRemoteUser, activity: IFlag): Promise<string> {
|
private async flag(actor: CacheableRemoteUser, activity: IFlag): Promise<string> {
|
||||||
// objectは `(User|Note) | (User|Note)[]` だけど、全パターンDBスキーマと対応させられないので
|
// objectは `(User|Note) | (User|Note)[]` だけど、全パターンDBスキーマと対応させられないので
|
||||||
// 対象ユーザーは一番最初のユーザー として あとはコメントとして格納する
|
// 対象ユーザーは一番最初のユーザー として あとはコメントとして格納する
|
||||||
|
@ -534,6 +552,7 @@ export class ApInboxService {
|
||||||
return 'ok';
|
return 'ok';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async reject(actor: CacheableRemoteUser, activity: IReject): Promise<string> {
|
private async reject(actor: CacheableRemoteUser, activity: IReject): Promise<string> {
|
||||||
const uri = activity.id ?? activity;
|
const uri = activity.id ?? activity;
|
||||||
|
|
||||||
|
@ -551,6 +570,7 @@ export class ApInboxService {
|
||||||
return `skip: Unknown Reject type: ${getApType(object)}`;
|
return `skip: Unknown Reject type: ${getApType(object)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async rejectFollow(actor: CacheableRemoteUser, activity: IFollow): Promise<string> {
|
private async rejectFollow(actor: CacheableRemoteUser, activity: IFollow): Promise<string> {
|
||||||
// ※ activityはこっちから投げたフォローリクエストなので、activity.actorは存在するローカルユーザーである必要がある
|
// ※ activityはこっちから投げたフォローリクエストなので、activity.actorは存在するローカルユーザーである必要がある
|
||||||
|
|
||||||
|
@ -574,6 +594,7 @@ export class ApInboxService {
|
||||||
return 'ok';
|
return 'ok';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async remove(actor: CacheableRemoteUser, activity: IRemove): Promise<void> {
|
private async remove(actor: CacheableRemoteUser, activity: IRemove): Promise<void> {
|
||||||
if ('actor' in activity && actor.uri !== activity.actor) {
|
if ('actor' in activity && actor.uri !== activity.actor) {
|
||||||
throw new Error('invalid actor');
|
throw new Error('invalid actor');
|
||||||
|
@ -593,6 +614,7 @@ export class ApInboxService {
|
||||||
throw new Error(`unknown target: ${activity.target}`);
|
throw new Error(`unknown target: ${activity.target}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async undo(actor: CacheableRemoteUser, activity: IUndo): Promise<string> {
|
private async undo(actor: CacheableRemoteUser, activity: IUndo): Promise<string> {
|
||||||
if ('actor' in activity && actor.uri !== activity.actor) {
|
if ('actor' in activity && actor.uri !== activity.actor) {
|
||||||
throw new Error('invalid actor');
|
throw new Error('invalid actor');
|
||||||
|
@ -618,6 +640,7 @@ export class ApInboxService {
|
||||||
return `skip: unknown object type ${getApType(object)}`;
|
return `skip: unknown object type ${getApType(object)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async undoAccept(actor: CacheableRemoteUser, activity: IAccept): Promise<string> {
|
private async undoAccept(actor: CacheableRemoteUser, activity: IAccept): Promise<string> {
|
||||||
const follower = await this.apDbResolverService.getUserFromApId(activity.object);
|
const follower = await this.apDbResolverService.getUserFromApId(activity.object);
|
||||||
if (follower == null) {
|
if (follower == null) {
|
||||||
|
@ -637,6 +660,7 @@ export class ApInboxService {
|
||||||
return 'skip: フォローされていない';
|
return 'skip: フォローされていない';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async undoAnnounce(actor: CacheableRemoteUser, activity: IAnnounce): Promise<string> {
|
private async undoAnnounce(actor: CacheableRemoteUser, activity: IAnnounce): Promise<string> {
|
||||||
const uri = getApId(activity);
|
const uri = getApId(activity);
|
||||||
|
|
||||||
|
@ -651,6 +675,7 @@ export class ApInboxService {
|
||||||
return 'ok: deleted';
|
return 'ok: deleted';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async undoBlock(actor: CacheableRemoteUser, activity: IBlock): Promise<string> {
|
private async undoBlock(actor: CacheableRemoteUser, activity: IBlock): Promise<string> {
|
||||||
const blockee = await this.apDbResolverService.getUserFromApId(activity.object);
|
const blockee = await this.apDbResolverService.getUserFromApId(activity.object);
|
||||||
|
|
||||||
|
@ -666,6 +691,7 @@ export class ApInboxService {
|
||||||
return 'ok';
|
return 'ok';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async undoFollow(actor: CacheableRemoteUser, activity: IFollow): Promise<string> {
|
private async undoFollow(actor: CacheableRemoteUser, activity: IFollow): Promise<string> {
|
||||||
const followee = await this.apDbResolverService.getUserFromApId(activity.object);
|
const followee = await this.apDbResolverService.getUserFromApId(activity.object);
|
||||||
if (followee == null) {
|
if (followee == null) {
|
||||||
|
@ -699,6 +725,7 @@ export class ApInboxService {
|
||||||
return 'skip: リクエストもフォローもされていない';
|
return 'skip: リクエストもフォローもされていない';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async undoLike(actor: CacheableRemoteUser, activity: ILike): Promise<string> {
|
private async undoLike(actor: CacheableRemoteUser, activity: ILike): Promise<string> {
|
||||||
const targetUri = getApId(activity.object);
|
const targetUri = getApId(activity.object);
|
||||||
|
|
||||||
|
@ -713,6 +740,7 @@ export class ApInboxService {
|
||||||
return 'ok';
|
return 'ok';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async update(actor: CacheableRemoteUser, activity: IUpdate): Promise<string> {
|
private async update(actor: CacheableRemoteUser, activity: IUpdate): Promise<string> {
|
||||||
if ('actor' in activity && actor.uri !== activity.actor) {
|
if ('actor' in activity && actor.uri !== activity.actor) {
|
||||||
return 'skip: invalid actor';
|
return 'skip: invalid actor';
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
import { RemoteLoggerService } from '@/core/RemoteLoggerService.js';
|
import { RemoteLoggerService } from '@/core/RemoteLoggerService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ApLoggerService {
|
export class ApLoggerService {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { MfmService } from '@/core/MfmService.js';
|
||||||
import type { Note } from '@/models/entities/Note.js';
|
import type { Note } from '@/models/entities/Note.js';
|
||||||
import { extractApHashtagObjects } from './models/tag.js';
|
import { extractApHashtagObjects } from './models/tag.js';
|
||||||
import type { IObject } from './type.js';
|
import type { IObject } from './type.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ApMfmService {
|
export class ApMfmService {
|
||||||
|
@ -17,12 +18,14 @@ export class ApMfmService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public htmlToMfm(html: string, tag?: IObject | IObject[]) {
|
public htmlToMfm(html: string, tag?: IObject | IObject[]) {
|
||||||
const hashtagNames = extractApHashtagObjects(tag).map(x => x.name).filter((x): x is string => x != null);
|
const hashtagNames = extractApHashtagObjects(tag).map(x => x.name).filter((x): x is string => x != null);
|
||||||
|
|
||||||
return this.mfmService.fromHtml(html, hashtagNames);
|
return this.mfmService.fromHtml(html, hashtagNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public getNoteHtml(note: Note) {
|
public getNoteHtml(note: Note) {
|
||||||
if (!note.text) return '';
|
if (!note.text) return '';
|
||||||
return this.mfmService.toHtml(mfm.parse(note.text), JSON.parse(note.mentionedRemoteUsers));
|
return this.mfmService.toHtml(mfm.parse(note.text), JSON.parse(note.mentionedRemoteUsers));
|
||||||
|
|
|
@ -25,6 +25,7 @@ import { LdSignatureService } from './LdSignatureService.js';
|
||||||
import { ApMfmService } from './ApMfmService.js';
|
import { ApMfmService } from './ApMfmService.js';
|
||||||
import type { IActivity, IObject } from './type.js';
|
import type { IActivity, IObject } from './type.js';
|
||||||
import type { IIdentifier } from './models/identifier.js';
|
import type { IIdentifier } from './models/identifier.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ApRendererService {
|
export class ApRendererService {
|
||||||
|
@ -59,6 +60,7 @@ export class ApRendererService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public renderAccept(object: any, user: { id: User['id']; host: null }) {
|
public renderAccept(object: any, user: { id: User['id']; host: null }) {
|
||||||
return {
|
return {
|
||||||
type: 'Accept',
|
type: 'Accept',
|
||||||
|
@ -67,6 +69,7 @@ export class ApRendererService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public renderAdd(user: ILocalUser, target: any, object: any) {
|
public renderAdd(user: ILocalUser, target: any, object: any) {
|
||||||
return {
|
return {
|
||||||
type: 'Add',
|
type: 'Add',
|
||||||
|
@ -76,6 +79,7 @@ export class ApRendererService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public renderAnnounce(object: any, note: Note) {
|
public renderAnnounce(object: any, note: Note) {
|
||||||
const attributedTo = `${this.config.url}/users/${note.userId}`;
|
const attributedTo = `${this.config.url}/users/${note.userId}`;
|
||||||
|
|
||||||
|
@ -108,6 +112,7 @@ export class ApRendererService {
|
||||||
*
|
*
|
||||||
* @param block The block to be rendered. The blockee relation must be loaded.
|
* @param block The block to be rendered. The blockee relation must be loaded.
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public renderBlock(block: Blocking) {
|
public renderBlock(block: Blocking) {
|
||||||
if (block.blockee?.uri == null) {
|
if (block.blockee?.uri == null) {
|
||||||
throw new Error('renderBlock: missing blockee uri');
|
throw new Error('renderBlock: missing blockee uri');
|
||||||
|
@ -121,6 +126,7 @@ export class ApRendererService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public renderCreate(object: any, note: Note) {
|
public renderCreate(object: any, note: Note) {
|
||||||
const activity = {
|
const activity = {
|
||||||
id: `${this.config.url}/notes/${note.id}/activity`,
|
id: `${this.config.url}/notes/${note.id}/activity`,
|
||||||
|
@ -136,6 +142,7 @@ export class ApRendererService {
|
||||||
return activity;
|
return activity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public renderDelete(object: any, user: { id: User['id']; host: null }) {
|
public renderDelete(object: any, user: { id: User['id']; host: null }) {
|
||||||
return {
|
return {
|
||||||
type: 'Delete',
|
type: 'Delete',
|
||||||
|
@ -145,6 +152,7 @@ export class ApRendererService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public renderDocument(file: DriveFile) {
|
public renderDocument(file: DriveFile) {
|
||||||
return {
|
return {
|
||||||
type: 'Document',
|
type: 'Document',
|
||||||
|
@ -154,6 +162,7 @@ export class ApRendererService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public renderEmoji(emoji: Emoji) {
|
public renderEmoji(emoji: Emoji) {
|
||||||
return {
|
return {
|
||||||
id: `${this.config.url}/emojis/${emoji.name}`,
|
id: `${this.config.url}/emojis/${emoji.name}`,
|
||||||
|
@ -170,6 +179,7 @@ export class ApRendererService {
|
||||||
|
|
||||||
// to anonymise reporters, the reporting actor must be a system user
|
// to anonymise reporters, the reporting actor must be a system user
|
||||||
// object has to be a uri or array of uris
|
// object has to be a uri or array of uris
|
||||||
|
@bindThis
|
||||||
public renderFlag(user: ILocalUser, object: [string], content: string) {
|
public renderFlag(user: ILocalUser, object: [string], content: string) {
|
||||||
return {
|
return {
|
||||||
type: 'Flag',
|
type: 'Flag',
|
||||||
|
@ -179,6 +189,7 @@ export class ApRendererService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public renderFollowRelay(relay: Relay, relayActor: ILocalUser) {
|
public renderFollowRelay(relay: Relay, relayActor: ILocalUser) {
|
||||||
const follow = {
|
const follow = {
|
||||||
id: `${this.config.url}/activities/follow-relay/${relay.id}`,
|
id: `${this.config.url}/activities/follow-relay/${relay.id}`,
|
||||||
|
@ -194,11 +205,13 @@ export class ApRendererService {
|
||||||
* Convert (local|remote)(Follower|Followee)ID to URL
|
* Convert (local|remote)(Follower|Followee)ID to URL
|
||||||
* @param id Follower|Followee ID
|
* @param id Follower|Followee ID
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async renderFollowUser(id: User['id']) {
|
public async renderFollowUser(id: User['id']) {
|
||||||
const user = await this.usersRepository.findOneByOrFail({ id: id });
|
const user = await this.usersRepository.findOneByOrFail({ id: id });
|
||||||
return this.userEntityService.isLocalUser(user) ? `${this.config.url}/users/${user.id}` : user.uri;
|
return this.userEntityService.isLocalUser(user) ? `${this.config.url}/users/${user.id}` : user.uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public renderFollow(
|
public renderFollow(
|
||||||
follower: { id: User['id']; host: User['host']; uri: User['host'] },
|
follower: { id: User['id']; host: User['host']; uri: User['host'] },
|
||||||
followee: { id: User['id']; host: User['host']; uri: User['host'] },
|
followee: { id: User['id']; host: User['host']; uri: User['host'] },
|
||||||
|
@ -214,6 +227,7 @@ export class ApRendererService {
|
||||||
return follow;
|
return follow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public renderHashtag(tag: string) {
|
public renderHashtag(tag: string) {
|
||||||
return {
|
return {
|
||||||
type: 'Hashtag',
|
type: 'Hashtag',
|
||||||
|
@ -222,6 +236,7 @@ export class ApRendererService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public renderImage(file: DriveFile) {
|
public renderImage(file: DriveFile) {
|
||||||
return {
|
return {
|
||||||
type: 'Image',
|
type: 'Image',
|
||||||
|
@ -231,6 +246,7 @@ export class ApRendererService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public renderKey(user: ILocalUser, key: UserKeypair, postfix?: string) {
|
public renderKey(user: ILocalUser, key: UserKeypair, postfix?: string) {
|
||||||
return {
|
return {
|
||||||
id: `${this.config.url}/users/${user.id}${postfix ?? '/publickey'}`,
|
id: `${this.config.url}/users/${user.id}${postfix ?? '/publickey'}`,
|
||||||
|
@ -243,6 +259,7 @@ export class ApRendererService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async renderLike(noteReaction: NoteReaction, note: { uri: string | null }) {
|
public async renderLike(noteReaction: NoteReaction, note: { uri: string | null }) {
|
||||||
const reaction = noteReaction.reaction;
|
const reaction = noteReaction.reaction;
|
||||||
|
|
||||||
|
@ -268,6 +285,7 @@ export class ApRendererService {
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public renderMention(mention: User) {
|
public renderMention(mention: User) {
|
||||||
return {
|
return {
|
||||||
type: 'Mention',
|
type: 'Mention',
|
||||||
|
@ -276,6 +294,7 @@ export class ApRendererService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async renderNote(note: Note, dive = true, isTalk = false): Promise<IObject> {
|
public async renderNote(note: Note, dive = true, isTalk = false): Promise<IObject> {
|
||||||
const getPromisedFiles = async (ids: string[]) => {
|
const getPromisedFiles = async (ids: string[]) => {
|
||||||
if (!ids || ids.length === 0) return [];
|
if (!ids || ids.length === 0) return [];
|
||||||
|
@ -420,6 +439,7 @@ export class ApRendererService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async renderPerson(user: ILocalUser) {
|
public async renderPerson(user: ILocalUser) {
|
||||||
const id = `${this.config.url}/users/${user.id}`;
|
const id = `${this.config.url}/users/${user.id}`;
|
||||||
const isSystem = !!user.username.match(/\./);
|
const isSystem = !!user.username.match(/\./);
|
||||||
|
@ -496,6 +516,7 @@ export class ApRendererService {
|
||||||
return person;
|
return person;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async renderQuestion(user: { id: User['id'] }, note: Note, poll: Poll) {
|
public async renderQuestion(user: { id: User['id'] }, note: Note, poll: Poll) {
|
||||||
const question = {
|
const question = {
|
||||||
type: 'Question',
|
type: 'Question',
|
||||||
|
@ -515,6 +536,7 @@ export class ApRendererService {
|
||||||
return question;
|
return question;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public renderRead(user: { id: User['id'] }, message: MessagingMessage) {
|
public renderRead(user: { id: User['id'] }, message: MessagingMessage) {
|
||||||
return {
|
return {
|
||||||
type: 'Read',
|
type: 'Read',
|
||||||
|
@ -523,6 +545,7 @@ export class ApRendererService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public renderReject(object: any, user: { id: User['id'] }) {
|
public renderReject(object: any, user: { id: User['id'] }) {
|
||||||
return {
|
return {
|
||||||
type: 'Reject',
|
type: 'Reject',
|
||||||
|
@ -531,6 +554,7 @@ export class ApRendererService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public renderRemove(user: { id: User['id'] }, target: any, object: any) {
|
public renderRemove(user: { id: User['id'] }, target: any, object: any) {
|
||||||
return {
|
return {
|
||||||
type: 'Remove',
|
type: 'Remove',
|
||||||
|
@ -540,6 +564,7 @@ export class ApRendererService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public renderTombstone(id: string) {
|
public renderTombstone(id: string) {
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
|
@ -547,6 +572,7 @@ export class ApRendererService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public renderUndo(object: any, user: { id: User['id'] }) {
|
public renderUndo(object: any, user: { id: User['id'] }) {
|
||||||
if (object == null) return null;
|
if (object == null) return null;
|
||||||
const id = typeof object.id === 'string' && object.id.startsWith(this.config.url) ? `${object.id}/undo` : undefined;
|
const id = typeof object.id === 'string' && object.id.startsWith(this.config.url) ? `${object.id}/undo` : undefined;
|
||||||
|
@ -560,6 +586,7 @@ export class ApRendererService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public renderUpdate(object: any, user: { id: User['id'] }) {
|
public renderUpdate(object: any, user: { id: User['id'] }) {
|
||||||
const activity = {
|
const activity = {
|
||||||
id: `${this.config.url}/users/${user.id}#updates/${new Date().getTime()}`,
|
id: `${this.config.url}/users/${user.id}#updates/${new Date().getTime()}`,
|
||||||
|
@ -573,6 +600,7 @@ export class ApRendererService {
|
||||||
return activity;
|
return activity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public renderVote(user: { id: User['id'] }, vote: PollVote, note: Note, poll: Poll, pollOwner: IRemoteUser) {
|
public renderVote(user: { id: User['id'] }, vote: PollVote, note: Note, poll: Poll, pollOwner: IRemoteUser) {
|
||||||
return {
|
return {
|
||||||
id: `${this.config.url}/users/${user.id}#votes/${vote.id}/activity`,
|
id: `${this.config.url}/users/${user.id}#votes/${vote.id}/activity`,
|
||||||
|
@ -591,6 +619,7 @@ export class ApRendererService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public renderActivity(x: any): IActivity | null {
|
public renderActivity(x: any): IActivity | null {
|
||||||
if (x == null) return null;
|
if (x == null) return null;
|
||||||
|
|
||||||
|
@ -632,6 +661,7 @@ export class ApRendererService {
|
||||||
}, x);
|
}, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async attachLdSignature(activity: any, user: { id: User['id']; host: null; }): Promise<IActivity> {
|
public async attachLdSignature(activity: any, user: { id: User['id']; host: null; }): Promise<IActivity> {
|
||||||
const keypair = await this.userKeypairStoreService.getUserKeypair(user.id);
|
const keypair = await this.userKeypairStoreService.getUserKeypair(user.id);
|
||||||
|
|
||||||
|
@ -651,6 +681,7 @@ export class ApRendererService {
|
||||||
* @param prev URL of prev page (optional)
|
* @param prev URL of prev page (optional)
|
||||||
* @param next URL of next page (optional)
|
* @param next URL of next page (optional)
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public renderOrderedCollectionPage(id: string, totalItems: any, orderedItems: any, partOf: string, prev?: string, next?: string) {
|
public renderOrderedCollectionPage(id: string, totalItems: any, orderedItems: any, partOf: string, prev?: string, next?: string) {
|
||||||
const page = {
|
const page = {
|
||||||
id,
|
id,
|
||||||
|
@ -674,6 +705,7 @@ export class ApRendererService {
|
||||||
* @param last URL of last page (optional)
|
* @param last URL of last page (optional)
|
||||||
* @param orderedItems attached objects (optional)
|
* @param orderedItems attached objects (optional)
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public renderOrderedCollection(id: string | null, totalItems: any, first?: string, last?: string, orderedItems?: IObject[]) {
|
public renderOrderedCollection(id: string | null, totalItems: any, first?: string, last?: string, orderedItems?: IObject[]) {
|
||||||
const page: any = {
|
const page: any = {
|
||||||
id,
|
id,
|
||||||
|
@ -688,6 +720,7 @@ export class ApRendererService {
|
||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async getEmojis(names: string[]): Promise<Emoji[]> {
|
private async getEmojis(names: string[]): Promise<Emoji[]> {
|
||||||
if (names == null || names.length === 0) return [];
|
if (names == null || names.length === 0) return [];
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import type { Config } from '@/config.js';
|
||||||
import type { User } from '@/models/entities/User.js';
|
import type { User } from '@/models/entities/User.js';
|
||||||
import { UserKeypairStoreService } from '@/core/UserKeypairStoreService.js';
|
import { UserKeypairStoreService } from '@/core/UserKeypairStoreService.js';
|
||||||
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
type Request = {
|
type Request = {
|
||||||
url: string;
|
url: string;
|
||||||
|
@ -36,6 +37,7 @@ export class ApRequestService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private createSignedPost(args: { key: PrivateKey, url: string, body: string, additionalHeaders: Record<string, string> }): Signed {
|
private createSignedPost(args: { key: PrivateKey, url: string, body: string, additionalHeaders: Record<string, string> }): Signed {
|
||||||
const u = new URL(args.url);
|
const u = new URL(args.url);
|
||||||
const digestHeader = `SHA-256=${crypto.createHash('sha256').update(args.body).digest('base64')}`;
|
const digestHeader = `SHA-256=${crypto.createHash('sha256').update(args.body).digest('base64')}`;
|
||||||
|
@ -61,6 +63,7 @@ export class ApRequestService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private createSignedGet(args: { key: PrivateKey, url: string, additionalHeaders: Record<string, string> }): Signed {
|
private createSignedGet(args: { key: PrivateKey, url: string, additionalHeaders: Record<string, string> }): Signed {
|
||||||
const u = new URL(args.url);
|
const u = new URL(args.url);
|
||||||
|
|
||||||
|
@ -84,6 +87,7 @@ export class ApRequestService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private signToRequest(request: Request, key: PrivateKey, includeHeaders: string[]): Signed {
|
private signToRequest(request: Request, key: PrivateKey, includeHeaders: string[]): Signed {
|
||||||
const signingString = this.genSigningString(request, includeHeaders);
|
const signingString = this.genSigningString(request, includeHeaders);
|
||||||
const signature = crypto.sign('sha256', Buffer.from(signingString), key.privateKeyPem).toString('base64');
|
const signature = crypto.sign('sha256', Buffer.from(signingString), key.privateKeyPem).toString('base64');
|
||||||
|
@ -101,6 +105,7 @@ export class ApRequestService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private genSigningString(request: Request, includeHeaders: string[]): string {
|
private genSigningString(request: Request, includeHeaders: string[]): string {
|
||||||
request.headers = this.lcObjectKey(request.headers);
|
request.headers = this.lcObjectKey(request.headers);
|
||||||
|
|
||||||
|
@ -117,16 +122,19 @@ export class ApRequestService {
|
||||||
return results.join('\n');
|
return results.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private lcObjectKey(src: Record<string, string>): Record<string, string> {
|
private lcObjectKey(src: Record<string, string>): Record<string, string> {
|
||||||
const dst: Record<string, string> = {};
|
const dst: Record<string, string> = {};
|
||||||
for (const key of Object.keys(src).filter(x => x !== '__proto__' && typeof src[x] === 'string')) dst[key.toLowerCase()] = src[key];
|
for (const key of Object.keys(src).filter(x => x !== '__proto__' && typeof src[x] === 'string')) dst[key.toLowerCase()] = src[key];
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private objectAssignWithLcKey(a: Record<string, string>, b: Record<string, string>): Record<string, string> {
|
private objectAssignWithLcKey(a: Record<string, string>, b: Record<string, string>): Record<string, string> {
|
||||||
return Object.assign(this.lcObjectKey(a), this.lcObjectKey(b));
|
return Object.assign(this.lcObjectKey(a), this.lcObjectKey(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async signedPost(user: { id: User['id'] }, url: string, object: any) {
|
public async signedPost(user: { id: User['id'] }, url: string, object: any) {
|
||||||
const body = JSON.stringify(object);
|
const body = JSON.stringify(object);
|
||||||
|
|
||||||
|
@ -157,6 +165,7 @@ export class ApRequestService {
|
||||||
* @param user http-signature user
|
* @param user http-signature user
|
||||||
* @param url URL to fetch
|
* @param url URL to fetch
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async signedGet(url: string, user: { id: User['id'] }) {
|
public async signedGet(url: string, user: { id: User['id'] }) {
|
||||||
const keypair = await this.userKeypairStoreService.getUserKeypair(user.id);
|
const keypair = await this.userKeypairStoreService.getUserKeypair(user.id);
|
||||||
|
|
||||||
|
|
|
@ -7,58 +7,13 @@ import { MetaService } from '@/core/MetaService.js';
|
||||||
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { UtilityService } from '@/core/UtilityService.js';
|
import { UtilityService } from '@/core/UtilityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import { isCollectionOrOrderedCollection } from './type.js';
|
import { isCollectionOrOrderedCollection } from './type.js';
|
||||||
import { ApDbResolverService } from './ApDbResolverService.js';
|
import { ApDbResolverService } from './ApDbResolverService.js';
|
||||||
import { ApRendererService } from './ApRendererService.js';
|
import { ApRendererService } from './ApRendererService.js';
|
||||||
import { ApRequestService } from './ApRequestService.js';
|
import { ApRequestService } from './ApRequestService.js';
|
||||||
import type { IObject, ICollection, IOrderedCollection } from './type.js';
|
import type { IObject, ICollection, IOrderedCollection } from './type.js';
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class ApResolverService {
|
|
||||||
constructor(
|
|
||||||
@Inject(DI.config)
|
|
||||||
private config: Config,
|
|
||||||
|
|
||||||
@Inject(DI.usersRepository)
|
|
||||||
private usersRepository: UsersRepository,
|
|
||||||
|
|
||||||
@Inject(DI.notesRepository)
|
|
||||||
private notesRepository: NotesRepository,
|
|
||||||
|
|
||||||
@Inject(DI.pollsRepository)
|
|
||||||
private pollsRepository: PollsRepository,
|
|
||||||
|
|
||||||
@Inject(DI.noteReactionsRepository)
|
|
||||||
private noteReactionsRepository: NoteReactionsRepository,
|
|
||||||
|
|
||||||
private utilityService: UtilityService,
|
|
||||||
private instanceActorService: InstanceActorService,
|
|
||||||
private metaService: MetaService,
|
|
||||||
private apRequestService: ApRequestService,
|
|
||||||
private httpRequestService: HttpRequestService,
|
|
||||||
private apRendererService: ApRendererService,
|
|
||||||
private apDbResolverService: ApDbResolverService,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public createResolver(): Resolver {
|
|
||||||
return new Resolver(
|
|
||||||
this.config,
|
|
||||||
this.usersRepository,
|
|
||||||
this.notesRepository,
|
|
||||||
this.pollsRepository,
|
|
||||||
this.noteReactionsRepository,
|
|
||||||
this.utilityService,
|
|
||||||
this.instanceActorService,
|
|
||||||
this.metaService,
|
|
||||||
this.apRequestService,
|
|
||||||
this.httpRequestService,
|
|
||||||
this.apRendererService,
|
|
||||||
this.apDbResolverService,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Resolver {
|
export class Resolver {
|
||||||
private history: Set<string>;
|
private history: Set<string>;
|
||||||
private user?: ILocalUser;
|
private user?: ILocalUser;
|
||||||
|
@ -76,15 +31,17 @@ export class Resolver {
|
||||||
private httpRequestService: HttpRequestService,
|
private httpRequestService: HttpRequestService,
|
||||||
private apRendererService: ApRendererService,
|
private apRendererService: ApRendererService,
|
||||||
private apDbResolverService: ApDbResolverService,
|
private apDbResolverService: ApDbResolverService,
|
||||||
private recursionLimit = 100
|
private recursionLimit = 100,
|
||||||
) {
|
) {
|
||||||
this.history = new Set();
|
this.history = new Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public getHistory(): string[] {
|
public getHistory(): string[] {
|
||||||
return Array.from(this.history);
|
return Array.from(this.history);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async resolveCollection(value: string | IObject): Promise<ICollection | IOrderedCollection> {
|
public async resolveCollection(value: string | IObject): Promise<ICollection | IOrderedCollection> {
|
||||||
const collection = typeof value === 'string'
|
const collection = typeof value === 'string'
|
||||||
? await this.resolve(value)
|
? await this.resolve(value)
|
||||||
|
@ -97,6 +54,7 @@ export class Resolver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async resolve(value: string | IObject): Promise<IObject> {
|
public async resolve(value: string | IObject): Promise<IObject> {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
throw new Error('resolvee is null (or undefined)');
|
throw new Error('resolvee is null (or undefined)');
|
||||||
|
@ -152,6 +110,7 @@ export class Resolver {
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private resolveLocal(url: string): Promise<IObject> {
|
private resolveLocal(url: string): Promise<IObject> {
|
||||||
const parsed = this.apDbResolverService.parseUri(url);
|
const parsed = this.apDbResolverService.parseUri(url);
|
||||||
if (!parsed.local) throw new Error('resolveLocal: not local');
|
if (!parsed.local) throw new Error('resolveLocal: not local');
|
||||||
|
@ -193,3 +152,50 @@ export class Resolver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ApResolverService {
|
||||||
|
constructor(
|
||||||
|
@Inject(DI.config)
|
||||||
|
private config: Config,
|
||||||
|
|
||||||
|
@Inject(DI.usersRepository)
|
||||||
|
private usersRepository: UsersRepository,
|
||||||
|
|
||||||
|
@Inject(DI.notesRepository)
|
||||||
|
private notesRepository: NotesRepository,
|
||||||
|
|
||||||
|
@Inject(DI.pollsRepository)
|
||||||
|
private pollsRepository: PollsRepository,
|
||||||
|
|
||||||
|
@Inject(DI.noteReactionsRepository)
|
||||||
|
private noteReactionsRepository: NoteReactionsRepository,
|
||||||
|
|
||||||
|
private utilityService: UtilityService,
|
||||||
|
private instanceActorService: InstanceActorService,
|
||||||
|
private metaService: MetaService,
|
||||||
|
private apRequestService: ApRequestService,
|
||||||
|
private httpRequestService: HttpRequestService,
|
||||||
|
private apRendererService: ApRendererService,
|
||||||
|
private apDbResolverService: ApDbResolverService,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public createResolver(): Resolver {
|
||||||
|
return new Resolver(
|
||||||
|
this.config,
|
||||||
|
this.usersRepository,
|
||||||
|
this.notesRepository,
|
||||||
|
this.pollsRepository,
|
||||||
|
this.noteReactionsRepository,
|
||||||
|
this.utilityService,
|
||||||
|
this.instanceActorService,
|
||||||
|
this.metaService,
|
||||||
|
this.apRequestService,
|
||||||
|
this.httpRequestService,
|
||||||
|
this.apRendererService,
|
||||||
|
this.apDbResolverService,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,22 +2,11 @@ import * as crypto from 'node:crypto';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import fetch from 'node-fetch';
|
import fetch from 'node-fetch';
|
||||||
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import { CONTEXTS } from './misc/contexts.js';
|
import { CONTEXTS } from './misc/contexts.js';
|
||||||
|
|
||||||
// RsaSignature2017 based from https://github.com/transmute-industries/RsaSignature2017
|
// RsaSignature2017 based from https://github.com/transmute-industries/RsaSignature2017
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class LdSignatureService {
|
|
||||||
constructor(
|
|
||||||
private httpRequestService: HttpRequestService,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public use(): LdSignature {
|
|
||||||
return new LdSignature(this.httpRequestService);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class LdSignature {
|
class LdSignature {
|
||||||
public debug = false;
|
public debug = false;
|
||||||
public preLoad = true;
|
public preLoad = true;
|
||||||
|
@ -28,6 +17,7 @@ class LdSignature {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async signRsaSignature2017(data: any, privateKey: string, creator: string, domain?: string, created?: Date): Promise<any> {
|
public async signRsaSignature2017(data: any, privateKey: string, creator: string, domain?: string, created?: Date): Promise<any> {
|
||||||
const options = {
|
const options = {
|
||||||
type: 'RsaSignature2017',
|
type: 'RsaSignature2017',
|
||||||
|
@ -64,6 +54,7 @@ class LdSignature {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async verifyRsaSignature2017(data: any, publicKey: string): Promise<boolean> {
|
public async verifyRsaSignature2017(data: any, publicKey: string): Promise<boolean> {
|
||||||
const toBeSigned = await this.createVerifyData(data, data.signature);
|
const toBeSigned = await this.createVerifyData(data, data.signature);
|
||||||
const verifier = crypto.createVerify('sha256');
|
const verifier = crypto.createVerify('sha256');
|
||||||
|
@ -71,6 +62,7 @@ class LdSignature {
|
||||||
return verifier.verify(publicKey, data.signature.signatureValue, 'base64');
|
return verifier.verify(publicKey, data.signature.signatureValue, 'base64');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async createVerifyData(data: any, options: any) {
|
public async createVerifyData(data: any, options: any) {
|
||||||
const transformedOptions = {
|
const transformedOptions = {
|
||||||
...options,
|
...options,
|
||||||
|
@ -90,11 +82,13 @@ class LdSignature {
|
||||||
return verifyData;
|
return verifyData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async normalize(data: any) {
|
public async normalize(data: any) {
|
||||||
const customLoader = this.getLoader();
|
const customLoader = this.getLoader();
|
||||||
return 42;
|
return 42;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private getLoader() {
|
private getLoader() {
|
||||||
return async (url: string): Promise<any> => {
|
return async (url: string): Promise<any> => {
|
||||||
if (!url.match('^https?\:\/\/')) throw `Invalid URL ${url}`;
|
if (!url.match('^https?\:\/\/')) throw `Invalid URL ${url}`;
|
||||||
|
@ -120,6 +114,7 @@ class LdSignature {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private async fetchDocument(url: string) {
|
private async fetchDocument(url: string) {
|
||||||
const json = await fetch(url, {
|
const json = await fetch(url, {
|
||||||
headers: {
|
headers: {
|
||||||
|
@ -139,9 +134,23 @@ class LdSignature {
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public sha256(data: string): string {
|
public sha256(data: string): string {
|
||||||
const hash = crypto.createHash('sha256');
|
const hash = crypto.createHash('sha256');
|
||||||
hash.update(data);
|
hash.update(data);
|
||||||
return hash.digest('hex');
|
return hash.digest('hex');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class LdSignatureService {
|
||||||
|
constructor(
|
||||||
|
private httpRequestService: HttpRequestService,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public use(): LdSignature {
|
||||||
|
return new LdSignature(this.httpRequestService);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { DriveService } from '@/core/DriveService.js';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
import { ApResolverService } from '../ApResolverService.js';
|
import { ApResolverService } from '../ApResolverService.js';
|
||||||
import { ApLoggerService } from '../ApLoggerService.js';
|
import { ApLoggerService } from '../ApLoggerService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ApImageService {
|
export class ApImageService {
|
||||||
|
@ -34,6 +35,7 @@ export class ApImageService {
|
||||||
/**
|
/**
|
||||||
* Imageを作成します。
|
* Imageを作成します。
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async createImage(actor: CacheableRemoteUser, value: any): Promise<DriveFile> {
|
public async createImage(actor: CacheableRemoteUser, value: any): Promise<DriveFile> {
|
||||||
// 投稿者が凍結されていたらスキップ
|
// 投稿者が凍結されていたらスキップ
|
||||||
if (actor.isSuspended) {
|
if (actor.isSuspended) {
|
||||||
|
@ -81,6 +83,7 @@ export class ApImageService {
|
||||||
* Misskeyに対象のImageが登録されていればそれを返し、そうでなければ
|
* Misskeyに対象のImageが登録されていればそれを返し、そうでなければ
|
||||||
* リモートサーバーからフェッチしてMisskeyに登録しそれを返します。
|
* リモートサーバーからフェッチしてMisskeyに登録しそれを返します。
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async resolveImage(actor: CacheableRemoteUser, value: any): Promise<DriveFile> {
|
public async resolveImage(actor: CacheableRemoteUser, value: any): Promise<DriveFile> {
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { isMention } from '../type.js';
|
||||||
import { ApResolverService, Resolver } from '../ApResolverService.js';
|
import { ApResolverService, Resolver } from '../ApResolverService.js';
|
||||||
import { ApPersonService } from './ApPersonService.js';
|
import { ApPersonService } from './ApPersonService.js';
|
||||||
import type { IObject, IApMention } from '../type.js';
|
import type { IObject, IApMention } from '../type.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ApMentionService {
|
export class ApMentionService {
|
||||||
|
@ -21,6 +22,7 @@ export class ApMentionService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async extractApMentions(tags: IObject | IObject[] | null | undefined, resolver: Resolver) {
|
public async extractApMentions(tags: IObject | IObject[] | null | undefined, resolver: Resolver) {
|
||||||
const hrefs = unique(this.extractApMentionObjects(tags).map(x => x.href as string));
|
const hrefs = unique(this.extractApMentionObjects(tags).map(x => x.href as string));
|
||||||
|
|
||||||
|
@ -32,6 +34,7 @@ export class ApMentionService {
|
||||||
return mentionedUsers;
|
return mentionedUsers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public extractApMentionObjects(tags: IObject | IObject[] | null | undefined): IApMention[] {
|
public extractApMentionObjects(tags: IObject | IObject[] | null | undefined): IApMention[] {
|
||||||
if (tags == null) return [];
|
if (tags == null) return [];
|
||||||
return toArray(tags).filter(isMention);
|
return toArray(tags).filter(isMention);
|
||||||
|
|
|
@ -32,6 +32,7 @@ import { ApQuestionService } from './ApQuestionService.js';
|
||||||
import { ApImageService } from './ApImageService.js';
|
import { ApImageService } from './ApImageService.js';
|
||||||
import type { Resolver } from '../ApResolverService.js';
|
import type { Resolver } from '../ApResolverService.js';
|
||||||
import type { IObject, IPost } from '../type.js';
|
import type { IObject, IPost } from '../type.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ApNoteService {
|
export class ApNoteService {
|
||||||
|
@ -74,6 +75,7 @@ export class ApNoteService {
|
||||||
this.logger = this.apLoggerService.logger;
|
this.logger = this.apLoggerService.logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public validateNote(object: any, uri: string) {
|
public validateNote(object: any, uri: string) {
|
||||||
const expectHost = this.utilityService.extractDbHost(uri);
|
const expectHost = this.utilityService.extractDbHost(uri);
|
||||||
|
|
||||||
|
@ -101,6 +103,7 @@ export class ApNoteService {
|
||||||
*
|
*
|
||||||
* Misskeyに対象のNoteが登録されていればそれを返します。
|
* Misskeyに対象のNoteが登録されていればそれを返します。
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async fetchNote(object: string | IObject): Promise<Note | null> {
|
public async fetchNote(object: string | IObject): Promise<Note | null> {
|
||||||
return await this.apDbResolverService.getNoteFromApId(object);
|
return await this.apDbResolverService.getNoteFromApId(object);
|
||||||
}
|
}
|
||||||
|
@ -108,6 +111,7 @@ export class ApNoteService {
|
||||||
/**
|
/**
|
||||||
* Noteを作成します。
|
* Noteを作成します。
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async createNote(value: string | IObject, resolver?: Resolver, silent = false): Promise<Note | null> {
|
public async createNote(value: string | IObject, resolver?: Resolver, silent = false): Promise<Note | null> {
|
||||||
if (resolver == null) resolver = this.apResolverService.createResolver();
|
if (resolver == null) resolver = this.apResolverService.createResolver();
|
||||||
|
|
||||||
|
@ -313,6 +317,7 @@ export class ApNoteService {
|
||||||
* Misskeyに対象のNoteが登録されていればそれを返し、そうでなければ
|
* Misskeyに対象のNoteが登録されていればそれを返し、そうでなければ
|
||||||
* リモートサーバーからフェッチしてMisskeyに登録しそれを返します。
|
* リモートサーバーからフェッチしてMisskeyに登録しそれを返します。
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async resolveNote(value: string | IObject, resolver?: Resolver): Promise<Note | null> {
|
public async resolveNote(value: string | IObject, resolver?: Resolver): Promise<Note | null> {
|
||||||
const uri = typeof value === 'string' ? value : value.id;
|
const uri = typeof value === 'string' ? value : value.id;
|
||||||
if (uri == null) throw new Error('missing uri');
|
if (uri == null) throw new Error('missing uri');
|
||||||
|
@ -345,6 +350,7 @@ export class ApNoteService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async extractEmojis(tags: IObject | IObject[], host: string): Promise<Emoji[]> {
|
public async extractEmojis(tags: IObject | IObject[], host: string): Promise<Emoji[]> {
|
||||||
host = this.utilityService.toPuny(host);
|
host = this.utilityService.toPuny(host);
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,7 @@ function addService(target: { [x: string]: any }, source: IApPropertyValue) {
|
||||||
target[source.name.split(':')[2]] = service(id, username);
|
target[source.name.split(':')[2]] = service(id, username);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ApPersonService implements OnModuleInit {
|
export class ApPersonService implements OnModuleInit {
|
||||||
|
@ -161,6 +162,7 @@ export class ApPersonService implements OnModuleInit {
|
||||||
* @param x Fetched object
|
* @param x Fetched object
|
||||||
* @param uri Fetch target URI
|
* @param uri Fetch target URI
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
private validateActor(x: IObject, uri: string): IActor {
|
private validateActor(x: IObject, uri: string): IActor {
|
||||||
const expectHost = this.utilityService.toPuny(new URL(uri).hostname);
|
const expectHost = this.utilityService.toPuny(new URL(uri).hostname);
|
||||||
|
|
||||||
|
@ -224,6 +226,7 @@ export class ApPersonService implements OnModuleInit {
|
||||||
*
|
*
|
||||||
* Misskeyに対象のPersonが登録されていればそれを返します。
|
* Misskeyに対象のPersonが登録されていればそれを返します。
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async fetchPerson(uri: string, resolver?: Resolver): Promise<CacheableUser | null> {
|
public async fetchPerson(uri: string, resolver?: Resolver): Promise<CacheableUser | null> {
|
||||||
if (typeof uri !== 'string') throw new Error('uri is not string');
|
if (typeof uri !== 'string') throw new Error('uri is not string');
|
||||||
|
|
||||||
|
@ -253,6 +256,7 @@ export class ApPersonService implements OnModuleInit {
|
||||||
/**
|
/**
|
||||||
* Personを作成します。
|
* Personを作成します。
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async createPerson(uri: string, resolver?: Resolver): Promise<User> {
|
public async createPerson(uri: string, resolver?: Resolver): Promise<User> {
|
||||||
if (typeof uri !== 'string') throw new Error('uri is not string');
|
if (typeof uri !== 'string') throw new Error('uri is not string');
|
||||||
|
|
||||||
|
@ -402,6 +406,7 @@ export class ApPersonService implements OnModuleInit {
|
||||||
* @param resolver Resolver
|
* @param resolver Resolver
|
||||||
* @param hint Hint of Person object (この値が正当なPersonの場合、Remote resolveをせずに更新に利用します)
|
* @param hint Hint of Person object (この値が正当なPersonの場合、Remote resolveをせずに更新に利用します)
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async updatePerson(uri: string, resolver?: Resolver | null, hint?: IObject): Promise<void> {
|
public async updatePerson(uri: string, resolver?: Resolver | null, hint?: IObject): Promise<void> {
|
||||||
if (typeof uri !== 'string') throw new Error('uri is not string');
|
if (typeof uri !== 'string') throw new Error('uri is not string');
|
||||||
|
|
||||||
|
@ -512,6 +517,7 @@ export class ApPersonService implements OnModuleInit {
|
||||||
* Misskeyに対象のPersonが登録されていればそれを返し、そうでなければ
|
* Misskeyに対象のPersonが登録されていればそれを返し、そうでなければ
|
||||||
* リモートサーバーからフェッチしてMisskeyに登録しそれを返します。
|
* リモートサーバーからフェッチしてMisskeyに登録しそれを返します。
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async resolvePerson(uri: string, resolver?: Resolver): Promise<CacheableUser> {
|
public async resolvePerson(uri: string, resolver?: Resolver): Promise<CacheableUser> {
|
||||||
if (typeof uri !== 'string') throw new Error('uri is not string');
|
if (typeof uri !== 'string') throw new Error('uri is not string');
|
||||||
|
|
||||||
|
@ -528,6 +534,7 @@ export class ApPersonService implements OnModuleInit {
|
||||||
return await this.createPerson(uri, resolver);
|
return await this.createPerson(uri, resolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public analyzeAttachments(attachments: IObject | IObject[] | undefined) {
|
public analyzeAttachments(attachments: IObject | IObject[] | undefined) {
|
||||||
const fields: {
|
const fields: {
|
||||||
name: string,
|
name: string,
|
||||||
|
@ -551,6 +558,7 @@ export class ApPersonService implements OnModuleInit {
|
||||||
return { fields, services };
|
return { fields, services };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async updateFeatured(userId: User['id'], resolver?: Resolver) {
|
public async updateFeatured(userId: User['id'], resolver?: Resolver) {
|
||||||
const user = await this.usersRepository.findOneByOrFail({ id: userId });
|
const user = await this.usersRepository.findOneByOrFail({ id: userId });
|
||||||
if (!this.userEntityService.isRemoteUser(user)) return;
|
if (!this.userEntityService.isRemoteUser(user)) return;
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { ApLoggerService } from '../ApLoggerService.js';
|
||||||
import { ApResolverService } from '../ApResolverService.js';
|
import { ApResolverService } from '../ApResolverService.js';
|
||||||
import type { Resolver } from '../ApResolverService.js';
|
import type { Resolver } from '../ApResolverService.js';
|
||||||
import type { IObject, IQuestion } from '../type.js';
|
import type { IObject, IQuestion } from '../type.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ApQuestionService {
|
export class ApQuestionService {
|
||||||
|
@ -30,6 +31,7 @@ export class ApQuestionService {
|
||||||
this.logger = this.apLoggerService.logger;
|
this.logger = this.apLoggerService.logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async extractPollFromQuestion(source: string | IObject, resolver?: Resolver): Promise<IPoll> {
|
public async extractPollFromQuestion(source: string | IObject, resolver?: Resolver): Promise<IPoll> {
|
||||||
if (resolver == null) resolver = this.apResolverService.createResolver();
|
if (resolver == null) resolver = this.apResolverService.createResolver();
|
||||||
|
|
||||||
|
@ -65,6 +67,7 @@ export class ApQuestionService {
|
||||||
* @param uri URI of AP Question object
|
* @param uri URI of AP Question object
|
||||||
* @returns true if updated
|
* @returns true if updated
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
public async updateQuestion(value: any, resolver?: Resolver) {
|
public async updateQuestion(value: any, resolver?: Resolver) {
|
||||||
const uri = typeof value === 'string' ? value : value.id;
|
const uri = typeof value === 'string' ? value : value.id;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
import { LoggerService } from '@/core/LoggerService.js';
|
import { LoggerService } from '@/core/LoggerService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ChartLoggerService {
|
export class ChartLoggerService {
|
||||||
|
|
|
@ -13,6 +13,7 @@ import PerUserFollowingChart from './charts/per-user-following.js';
|
||||||
import PerUserDriveChart from './charts/per-user-drive.js';
|
import PerUserDriveChart from './charts/per-user-drive.js';
|
||||||
import ApRequestChart from './charts/ap-request.js';
|
import ApRequestChart from './charts/ap-request.js';
|
||||||
import type { OnApplicationShutdown } from '@nestjs/common';
|
import type { OnApplicationShutdown } from '@nestjs/common';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ChartManagementService implements OnApplicationShutdown {
|
export class ChartManagementService implements OnApplicationShutdown {
|
||||||
|
@ -49,6 +50,7 @@ export class ChartManagementService implements OnApplicationShutdown {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async run() {
|
public async run() {
|
||||||
// 20分おきにメモリ情報をDBに書き込み
|
// 20分おきにメモリ情報をDBに書き込み
|
||||||
this.saveIntervalId = setInterval(() => {
|
this.saveIntervalId = setInterval(() => {
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { DataSource } from 'typeorm';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
import { AppLockService } from '@/core/AppLockService.js';
|
||||||
import type { User } from '@/models/entities/User.js';
|
import type { User } from '@/models/entities/User.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/active-users.js';
|
import { name, schema } from './entities/active-users.js';
|
||||||
|
@ -36,6 +37,7 @@ export default class ActiveUsersChart extends Chart<typeof schema> {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async read(user: { id: User['id'], host: null, createdAt: User['createdAt'] }): Promise<void> {
|
public async read(user: { id: User['id'], host: null, createdAt: User['createdAt'] }): Promise<void> {
|
||||||
await this.commit({
|
await this.commit({
|
||||||
'read': [user.id],
|
'read': [user.id],
|
||||||
|
@ -48,6 +50,7 @@ export default class ActiveUsersChart extends Chart<typeof schema> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async write(user: { id: User['id'], host: null, createdAt: User['createdAt'] }): Promise<void> {
|
public async write(user: { id: User['id'], host: null, createdAt: User['createdAt'] }): Promise<void> {
|
||||||
await this.commit({
|
await this.commit({
|
||||||
'write': [user.id],
|
'write': [user.id],
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { Injectable, Inject } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
import { AppLockService } from '@/core/AppLockService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/ap-request.js';
|
import { name, schema } from './entities/ap-request.js';
|
||||||
|
@ -31,18 +32,21 @@ export default class ApRequestChart extends Chart<typeof schema> {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async deliverSucc(): Promise<void> {
|
public async deliverSucc(): Promise<void> {
|
||||||
await this.commit({
|
await this.commit({
|
||||||
'deliverSucceeded': 1,
|
'deliverSucceeded': 1,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async deliverFail(): Promise<void> {
|
public async deliverFail(): Promise<void> {
|
||||||
await this.commit({
|
await this.commit({
|
||||||
'deliverFailed': 1,
|
'deliverFailed': 1,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async inbox(): Promise<void> {
|
public async inbox(): Promise<void> {
|
||||||
await this.commit({
|
await this.commit({
|
||||||
'inboxReceived': 1,
|
'inboxReceived': 1,
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { Not, IsNull, DataSource } from 'typeorm';
|
||||||
import type { DriveFile } from '@/models/entities/DriveFile.js';
|
import type { DriveFile } from '@/models/entities/DriveFile.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
import { AppLockService } from '@/core/AppLockService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/drive.js';
|
import { name, schema } from './entities/drive.js';
|
||||||
|
@ -32,6 +33,7 @@ export default class DriveChart extends Chart<typeof schema> {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async update(file: DriveFile, isAdditional: boolean): Promise<void> {
|
public async update(file: DriveFile, isAdditional: boolean): Promise<void> {
|
||||||
const fileSizeKb = file.size / 1000;
|
const fileSizeKb = file.size / 1000;
|
||||||
await this.commit(file.userHost === null ? {
|
await this.commit(file.userHost === null ? {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import type { FollowingsRepository, InstancesRepository } from '@/models/index.j
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
import { AppLockService } from '@/core/AppLockService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { MetaService } from '@/core/MetaService.js';
|
import { MetaService } from '@/core/MetaService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/federation.js';
|
import { name, schema } from './entities/federation.js';
|
||||||
|
@ -107,6 +108,7 @@ export default class FederationChart extends Chart<typeof schema> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async deliverd(host: string, succeeded: boolean): Promise<void> {
|
public async deliverd(host: string, succeeded: boolean): Promise<void> {
|
||||||
await this.commit(succeeded ? {
|
await this.commit(succeeded ? {
|
||||||
'deliveredInstances': [host],
|
'deliveredInstances': [host],
|
||||||
|
@ -115,6 +117,7 @@ export default class FederationChart extends Chart<typeof schema> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async inbox(host: string): Promise<void> {
|
public async inbox(host: string): Promise<void> {
|
||||||
await this.commit({
|
await this.commit({
|
||||||
'inboxInstances': [host],
|
'inboxInstances': [host],
|
||||||
|
|
|
@ -4,6 +4,7 @@ import type { User } from '@/models/entities/User.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
import { AppLockService } from '@/core/AppLockService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/hashtag.js';
|
import { name, schema } from './entities/hashtag.js';
|
||||||
|
@ -34,6 +35,7 @@ export default class HashtagChart extends Chart<typeof schema> {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async update(hashtag: string, user: { id: User['id'], host: User['host'] }): Promise<void> {
|
public async update(hashtag: string, user: { id: User['id'], host: User['host'] }): Promise<void> {
|
||||||
await this.commit({
|
await this.commit({
|
||||||
'local.users': this.userEntityService.isLocalUser(user) ? [user.id] : [],
|
'local.users': this.userEntityService.isLocalUser(user) ? [user.id] : [],
|
||||||
|
|
|
@ -6,6 +6,7 @@ import type { Note } from '@/models/entities/Note.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
import { AppLockService } from '@/core/AppLockService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { UtilityService } from '@/core/UtilityService.js';
|
import { UtilityService } from '@/core/UtilityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/instance.js';
|
import { name, schema } from './entities/instance.js';
|
||||||
|
@ -68,12 +69,14 @@ export default class InstanceChart extends Chart<typeof schema> {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async requestReceived(host: string): Promise<void> {
|
public async requestReceived(host: string): Promise<void> {
|
||||||
await this.commit({
|
await this.commit({
|
||||||
'requests.received': 1,
|
'requests.received': 1,
|
||||||
}, this.utilityService.toPuny(host));
|
}, this.utilityService.toPuny(host));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async requestSent(host: string, isSucceeded: boolean): Promise<void> {
|
public async requestSent(host: string, isSucceeded: boolean): Promise<void> {
|
||||||
await this.commit({
|
await this.commit({
|
||||||
'requests.succeeded': isSucceeded ? 1 : 0,
|
'requests.succeeded': isSucceeded ? 1 : 0,
|
||||||
|
@ -81,6 +84,7 @@ export default class InstanceChart extends Chart<typeof schema> {
|
||||||
}, this.utilityService.toPuny(host));
|
}, this.utilityService.toPuny(host));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async newUser(host: string): Promise<void> {
|
public async newUser(host: string): Promise<void> {
|
||||||
await this.commit({
|
await this.commit({
|
||||||
'users.total': 1,
|
'users.total': 1,
|
||||||
|
@ -88,6 +92,7 @@ export default class InstanceChart extends Chart<typeof schema> {
|
||||||
}, this.utilityService.toPuny(host));
|
}, this.utilityService.toPuny(host));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async updateNote(host: string, note: Note, isAdditional: boolean): Promise<void> {
|
public async updateNote(host: string, note: Note, isAdditional: boolean): Promise<void> {
|
||||||
await this.commit({
|
await this.commit({
|
||||||
'notes.total': isAdditional ? 1 : -1,
|
'notes.total': isAdditional ? 1 : -1,
|
||||||
|
@ -100,6 +105,7 @@ export default class InstanceChart extends Chart<typeof schema> {
|
||||||
}, this.utilityService.toPuny(host));
|
}, this.utilityService.toPuny(host));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async updateFollowing(host: string, isAdditional: boolean): Promise<void> {
|
public async updateFollowing(host: string, isAdditional: boolean): Promise<void> {
|
||||||
await this.commit({
|
await this.commit({
|
||||||
'following.total': isAdditional ? 1 : -1,
|
'following.total': isAdditional ? 1 : -1,
|
||||||
|
@ -108,6 +114,7 @@ export default class InstanceChart extends Chart<typeof schema> {
|
||||||
}, this.utilityService.toPuny(host));
|
}, this.utilityService.toPuny(host));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async updateFollowers(host: string, isAdditional: boolean): Promise<void> {
|
public async updateFollowers(host: string, isAdditional: boolean): Promise<void> {
|
||||||
await this.commit({
|
await this.commit({
|
||||||
'followers.total': isAdditional ? 1 : -1,
|
'followers.total': isAdditional ? 1 : -1,
|
||||||
|
@ -116,6 +123,7 @@ export default class InstanceChart extends Chart<typeof schema> {
|
||||||
}, this.utilityService.toPuny(host));
|
}, this.utilityService.toPuny(host));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async updateDrive(file: DriveFile, isAdditional: boolean): Promise<void> {
|
public async updateDrive(file: DriveFile, isAdditional: boolean): Promise<void> {
|
||||||
const fileSizeKb = file.size / 1000;
|
const fileSizeKb = file.size / 1000;
|
||||||
await this.commit({
|
await this.commit({
|
||||||
|
|
|
@ -4,6 +4,7 @@ import type { NotesRepository } from '@/models/index.js';
|
||||||
import type { Note } from '@/models/entities/Note.js';
|
import type { Note } from '@/models/entities/Note.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
import { AppLockService } from '@/core/AppLockService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/notes.js';
|
import { name, schema } from './entities/notes.js';
|
||||||
|
@ -44,6 +45,7 @@ export default class NotesChart extends Chart<typeof schema> {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async update(note: Note, isAdditional: boolean): Promise<void> {
|
public async update(note: Note, isAdditional: boolean): Promise<void> {
|
||||||
const prefix = note.userHost === null ? 'local' : 'remote';
|
const prefix = note.userHost === null ? 'local' : 'remote';
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import type { DriveFile } from '@/models/entities/DriveFile.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
import { AppLockService } from '@/core/AppLockService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
|
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/per-user-drive.js';
|
import { name, schema } from './entities/per-user-drive.js';
|
||||||
|
@ -46,6 +47,7 @@ export default class PerUserDriveChart extends Chart<typeof schema> {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async update(file: DriveFile, isAdditional: boolean): Promise<void> {
|
public async update(file: DriveFile, isAdditional: boolean): Promise<void> {
|
||||||
const fileSizeKb = file.size / 1000;
|
const fileSizeKb = file.size / 1000;
|
||||||
await this.commit({
|
await this.commit({
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { AppLockService } from '@/core/AppLockService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import type { FollowingsRepository } from '@/models/index.js';
|
import type { FollowingsRepository } from '@/models/index.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/per-user-following.js';
|
import { name, schema } from './entities/per-user-following.js';
|
||||||
|
@ -55,6 +56,7 @@ export default class PerUserFollowingChart extends Chart<typeof schema> {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async update(follower: { id: User['id']; host: User['host']; }, followee: { id: User['id']; host: User['host']; }, isFollow: boolean): Promise<void> {
|
public async update(follower: { id: User['id']; host: User['host']; }, followee: { id: User['id']; host: User['host']; }, isFollow: boolean): Promise<void> {
|
||||||
const prefixFollower = this.userEntityService.isLocalUser(follower) ? 'local' : 'remote';
|
const prefixFollower = this.userEntityService.isLocalUser(follower) ? 'local' : 'remote';
|
||||||
const prefixFollowee = this.userEntityService.isLocalUser(followee) ? 'local' : 'remote';
|
const prefixFollowee = this.userEntityService.isLocalUser(followee) ? 'local' : 'remote';
|
||||||
|
|
|
@ -5,6 +5,7 @@ import type { Note } from '@/models/entities/Note.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
import { AppLockService } from '@/core/AppLockService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { NotesRepository } from '@/models/index.js';
|
import type { NotesRepository } from '@/models/index.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/per-user-notes.js';
|
import { name, schema } from './entities/per-user-notes.js';
|
||||||
|
@ -43,6 +44,7 @@ export default class PerUserNotesChart extends Chart<typeof schema> {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async update(user: { id: User['id'] }, note: Note, isAdditional: boolean): Promise<void> {
|
public async update(user: { id: User['id'] }, note: Note, isAdditional: boolean): Promise<void> {
|
||||||
await this.commit({
|
await this.commit({
|
||||||
'total': isAdditional ? 1 : -1,
|
'total': isAdditional ? 1 : -1,
|
||||||
|
|
|
@ -5,6 +5,7 @@ import type { Note } from '@/models/entities/Note.js';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
import { AppLockService } from '@/core/AppLockService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/per-user-reactions.js';
|
import { name, schema } from './entities/per-user-reactions.js';
|
||||||
|
@ -35,6 +36,7 @@ export default class PerUserReactionsChart extends Chart<typeof schema> {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async update(user: { id: User['id'], host: User['host'] }, note: Note): Promise<void> {
|
public async update(user: { id: User['id'], host: User['host'] }, note: Note): Promise<void> {
|
||||||
const prefix = this.userEntityService.isLocalUser(user) ? 'local' : 'remote';
|
const prefix = this.userEntityService.isLocalUser(user) ? 'local' : 'remote';
|
||||||
this.commit({
|
this.commit({
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { DataSource } from 'typeorm';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
import { AppLockService } from '@/core/AppLockService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import Logger from '@/logger.js';
|
import Logger from '@/logger.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { name, schema } from './entities/test-grouped.js';
|
import { name, schema } from './entities/test-grouped.js';
|
||||||
import type { KVs } from '../core.js';
|
import type { KVs } from '../core.js';
|
||||||
|
@ -35,6 +36,7 @@ export default class TestGroupedChart extends Chart<typeof schema> {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async increment(group: string): Promise<void> {
|
public async increment(group: string): Promise<void> {
|
||||||
if (this.total[group] == null) this.total[group] = 0;
|
if (this.total[group] == null) this.total[group] = 0;
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { DataSource } from 'typeorm';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
import { AppLockService } from '@/core/AppLockService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import Logger from '@/logger.js';
|
import Logger from '@/logger.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { name, schema } from './entities/test-intersection.js';
|
import { name, schema } from './entities/test-intersection.js';
|
||||||
import type { KVs } from '../core.js';
|
import type { KVs } from '../core.js';
|
||||||
|
@ -31,12 +32,14 @@ export default class TestIntersectionChart extends Chart<typeof schema> {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async addA(key: string): Promise<void> {
|
public async addA(key: string): Promise<void> {
|
||||||
await this.commit({
|
await this.commit({
|
||||||
a: [key],
|
a: [key],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async addB(key: string): Promise<void> {
|
public async addB(key: string): Promise<void> {
|
||||||
await this.commit({
|
await this.commit({
|
||||||
b: [key],
|
b: [key],
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { DataSource } from 'typeorm';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
import { AppLockService } from '@/core/AppLockService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import Logger from '@/logger.js';
|
import Logger from '@/logger.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { name, schema } from './entities/test-unique.js';
|
import { name, schema } from './entities/test-unique.js';
|
||||||
import type { KVs } from '../core.js';
|
import type { KVs } from '../core.js';
|
||||||
|
@ -31,6 +32,7 @@ export default class TestUniqueChart extends Chart<typeof schema> {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async uniqueIncrement(key: string): Promise<void> {
|
public async uniqueIncrement(key: string): Promise<void> {
|
||||||
await this.commit({
|
await this.commit({
|
||||||
foo: [key],
|
foo: [key],
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { DataSource } from 'typeorm';
|
||||||
import { AppLockService } from '@/core/AppLockService.js';
|
import { AppLockService } from '@/core/AppLockService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import Logger from '@/logger.js';
|
import Logger from '@/logger.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { name, schema } from './entities/test.js';
|
import { name, schema } from './entities/test.js';
|
||||||
import type { KVs } from '../core.js';
|
import type { KVs } from '../core.js';
|
||||||
|
@ -35,6 +36,7 @@ export default class TestChart extends Chart<typeof schema> {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async increment(): Promise<void> {
|
public async increment(): Promise<void> {
|
||||||
this.total++;
|
this.total++;
|
||||||
|
|
||||||
|
@ -44,6 +46,7 @@ export default class TestChart extends Chart<typeof schema> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async decrement(): Promise<void> {
|
public async decrement(): Promise<void> {
|
||||||
this.total--;
|
this.total--;
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { AppLockService } from '@/core/AppLockService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import type { UsersRepository } from '@/models/index.js';
|
import type { UsersRepository } from '@/models/index.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import Chart from '../core.js';
|
import Chart from '../core.js';
|
||||||
import { ChartLoggerService } from '../ChartLoggerService.js';
|
import { ChartLoggerService } from '../ChartLoggerService.js';
|
||||||
import { name, schema } from './entities/users.js';
|
import { name, schema } from './entities/users.js';
|
||||||
|
@ -46,6 +47,7 @@ export default class UsersChart extends Chart<typeof schema> {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async update(user: { id: User['id'], host: User['host'] }, isAdditional: boolean): Promise<void> {
|
public async update(user: { id: User['id'], host: User['host'] }, isAdditional: boolean): Promise<void> {
|
||||||
const prefix = this.userEntityService.isLocalUser(user) ? 'local' : 'remote';
|
const prefix = this.userEntityService.isLocalUser(user) ? 'local' : 'remote';
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import * as nestedProperty from 'nested-property';
|
||||||
import { EntitySchema, LessThan, Between } from 'typeorm';
|
import { EntitySchema, LessThan, Between } from 'typeorm';
|
||||||
import { dateUTC, isTimeSame, isTimeBefore, subtractTime, addTime } from '@/misc/prelude/time.js';
|
import { dateUTC, isTimeSame, isTimeBefore, subtractTime, addTime } from '@/misc/prelude/time.js';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import type { Repository, DataSource } from 'typeorm';
|
import type { Repository, DataSource } from 'typeorm';
|
||||||
|
|
||||||
const columnPrefix = '___' as const;
|
const columnPrefix = '___' as const;
|
||||||
|
@ -249,6 +250,7 @@ export default abstract class Chart<T extends Schema> {
|
||||||
this.repositoryForDay = db.getRepository<{ id: number; group?: string | null; date: number; }>(day);
|
this.repositoryForDay = db.getRepository<{ id: number; group?: string | null; date: number; }>(day);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private convertRawRecord(x: RawRecord<T>): KVs<T> {
|
private convertRawRecord(x: RawRecord<T>): KVs<T> {
|
||||||
const kvs = {} as Record<string, number>;
|
const kvs = {} as Record<string, number>;
|
||||||
for (const k of Object.keys(x).filter((k) => k.startsWith(columnPrefix)) as (keyof Columns<T>)[]) {
|
for (const k of Object.keys(x).filter((k) => k.startsWith(columnPrefix)) as (keyof Columns<T>)[]) {
|
||||||
|
@ -257,6 +259,7 @@ export default abstract class Chart<T extends Schema> {
|
||||||
return kvs as KVs<T>;
|
return kvs as KVs<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private getNewLog(latest: KVs<T> | null): KVs<T> {
|
private getNewLog(latest: KVs<T> | null): KVs<T> {
|
||||||
const log = {} as Record<keyof T, number>;
|
const log = {} as Record<keyof T, number>;
|
||||||
for (const [k, v] of Object.entries(this.schema) as ([keyof typeof this['schema'], this['schema'][string]])[]) {
|
for (const [k, v] of Object.entries(this.schema) as ([keyof typeof this['schema'], this['schema'][string]])[]) {
|
||||||
|
@ -269,6 +272,7 @@ export default abstract class Chart<T extends Schema> {
|
||||||
return log as KVs<T>;
|
return log as KVs<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
private getLatestLog(group: string | null, span: 'hour' | 'day'): Promise<RawRecord<T> | null> {
|
private getLatestLog(group: string | null, span: 'hour' | 'day'): Promise<RawRecord<T> | null> {
|
||||||
const repository =
|
const repository =
|
||||||
span === 'hour' ? this.repositoryForHour :
|
span === 'hour' ? this.repositoryForHour :
|
||||||
|
@ -288,6 +292,7 @@ export default abstract class Chart<T extends Schema> {
|
||||||
/**
|
/**
|
||||||
* 現在(=今のHour or Day)のログをデータベースから探して、あればそれを返し、なければ作成して返します。
|
* 現在(=今のHour or Day)のログをデータベースから探して、あればそれを返し、なければ作成して返します。
|
||||||
*/
|
*/
|
||||||
|
@bindThis
|
||||||
private async claimCurrentLog(group: string | null, span: 'hour' | 'day'): Promise<RawRecord<T>> {
|
private async claimCurrentLog(group: string | null, span: 'hour' | 'day'): Promise<RawRecord<T>> {
|
||||||
const [y, m, d, h] = Chart.getCurrentDate();
|
const [y, m, d, h] = Chart.getCurrentDate();
|
||||||
|
|
||||||
|
@ -380,6 +385,7 @@ export default abstract class Chart<T extends Schema> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async save(): Promise<void> {
|
public async save(): Promise<void> {
|
||||||
if (this.buffer.length === 0) {
|
if (this.buffer.length === 0) {
|
||||||
this.logger.info(`${this.name}: Write skipped`);
|
this.logger.info(`${this.name}: Write skipped`);
|
||||||
|
@ -498,6 +504,7 @@ export default abstract class Chart<T extends Schema> {
|
||||||
update(logHour, logDay))));
|
update(logHour, logDay))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async tick(major: boolean, group: string | null = null): Promise<void> {
|
public async tick(major: boolean, group: string | null = null): Promise<void> {
|
||||||
const data = major ? await this.tickMajor(group) : await this.tickMinor(group);
|
const data = major ? await this.tickMajor(group) : await this.tickMinor(group);
|
||||||
|
|
||||||
|
@ -533,10 +540,12 @@ export default abstract class Chart<T extends Schema> {
|
||||||
update(logHour, logDay));
|
update(logHour, logDay));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public resync(group: string | null = null): Promise<void> {
|
public resync(group: string | null = null): Promise<void> {
|
||||||
return this.tick(true, group);
|
return this.tick(true, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async clean(): Promise<void> {
|
public async clean(): Promise<void> {
|
||||||
const current = dateUTC(Chart.getCurrentDate());
|
const current = dateUTC(Chart.getCurrentDate());
|
||||||
|
|
||||||
|
@ -572,6 +581,7 @@ export default abstract class Chart<T extends Schema> {
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async getChartRaw(span: 'hour' | 'day', amount: number, cursor: Date | null, group: string | null = null): Promise<ChartResult<T>> {
|
public async getChartRaw(span: 'hour' | 'day', amount: number, cursor: Date | null, group: string | null = null): Promise<ChartResult<T>> {
|
||||||
const [y, m, d, h, _m, _s, _ms] = cursor ? Chart.parseDate(subtractTime(addTime(cursor, 1, span), 1)) : Chart.getCurrentDate();
|
const [y, m, d, h, _m, _s, _ms] = cursor ? Chart.parseDate(subtractTime(addTime(cursor, 1, span), 1)) : Chart.getCurrentDate();
|
||||||
const [y2, m2, d2, h2] = cursor ? Chart.parseDate(addTime(cursor, 1, span)) : [] as never;
|
const [y2, m2, d2, h2] = cursor ? Chart.parseDate(addTime(cursor, 1, span)) : [] as never;
|
||||||
|
@ -676,6 +686,7 @@ export default abstract class Chart<T extends Schema> {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async getChart(span: 'hour' | 'day', amount: number, cursor: Date | null, group: string | null = null): Promise<Unflatten<ChartResult<T>>> {
|
public async getChart(span: 'hour' | 'day', amount: number, cursor: Date | null, group: string | null = null): Promise<Unflatten<ChartResult<T>>> {
|
||||||
const result = await this.getChartRaw(span, amount, cursor, group);
|
const result = await this.getChartRaw(span, amount, cursor, group);
|
||||||
const object = {};
|
const object = {};
|
||||||
|
|
|
@ -4,6 +4,7 @@ import type { AbuseUserReportsRepository } from '@/models/index.js';
|
||||||
import { awaitAll } from '@/misc/prelude/await-all.js';
|
import { awaitAll } from '@/misc/prelude/await-all.js';
|
||||||
import type { AbuseUserReport } from '@/models/entities/AbuseUserReport.js';
|
import type { AbuseUserReport } from '@/models/entities/AbuseUserReport.js';
|
||||||
import { UserEntityService } from './UserEntityService.js';
|
import { UserEntityService } from './UserEntityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AbuseUserReportEntityService {
|
export class AbuseUserReportEntityService {
|
||||||
|
@ -15,6 +16,7 @@ export class AbuseUserReportEntityService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async pack(
|
public async pack(
|
||||||
src: AbuseUserReport['id'] | AbuseUserReport,
|
src: AbuseUserReport['id'] | AbuseUserReport,
|
||||||
) {
|
) {
|
||||||
|
@ -41,6 +43,7 @@ export class AbuseUserReportEntityService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public packMany(
|
public packMany(
|
||||||
reports: any[],
|
reports: any[],
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import type { AntennaNotesRepository, AntennasRepository, UserGroupJoiningsRepos
|
||||||
import { awaitAll } from '@/misc/prelude/await-all.js';
|
import { awaitAll } from '@/misc/prelude/await-all.js';
|
||||||
import type { Packed } from '@/misc/schema.js';
|
import type { Packed } from '@/misc/schema.js';
|
||||||
import type { Antenna } from '@/models/entities/Antenna.js';
|
import type { Antenna } from '@/models/entities/Antenna.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AntennaEntityService {
|
export class AntennaEntityService {
|
||||||
|
@ -19,6 +20,7 @@ export class AntennaEntityService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async pack(
|
public async pack(
|
||||||
src: Antenna['id'] | Antenna,
|
src: Antenna['id'] | Antenna,
|
||||||
): Promise<Packed<'Antenna'>> {
|
): Promise<Packed<'Antenna'>> {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import type { Packed } from '@/misc/schema.js';
|
||||||
import type { App } from '@/models/entities/App.js';
|
import type { App } from '@/models/entities/App.js';
|
||||||
import type { User } from '@/models/entities/User.js';
|
import type { User } from '@/models/entities/User.js';
|
||||||
import { UserEntityService } from './UserEntityService.js';
|
import { UserEntityService } from './UserEntityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AppEntityService {
|
export class AppEntityService {
|
||||||
|
@ -18,6 +19,7 @@ export class AppEntityService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async pack(
|
public async pack(
|
||||||
src: App['id'] | App,
|
src: App['id'] | App,
|
||||||
me?: { id: User['id'] } | null | undefined,
|
me?: { id: User['id'] } | null | undefined,
|
||||||
|
|
|
@ -7,6 +7,7 @@ import type { AuthSession } from '@/models/entities/AuthSession.js';
|
||||||
import type { User } from '@/models/entities/User.js';
|
import type { User } from '@/models/entities/User.js';
|
||||||
import { UserEntityService } from './UserEntityService.js';
|
import { UserEntityService } from './UserEntityService.js';
|
||||||
import { AppEntityService } from './AppEntityService.js';
|
import { AppEntityService } from './AppEntityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthSessionEntityService {
|
export class AuthSessionEntityService {
|
||||||
|
@ -18,6 +19,7 @@ export class AuthSessionEntityService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async pack(
|
public async pack(
|
||||||
src: AuthSession['id'] | AuthSession,
|
src: AuthSession['id'] | AuthSession,
|
||||||
me?: { id: User['id'] } | null | undefined,
|
me?: { id: User['id'] } | null | undefined,
|
||||||
|
|
|
@ -6,6 +6,7 @@ import type { Packed } from '@/misc/schema.js';
|
||||||
import type { Blocking } from '@/models/entities/Blocking.js';
|
import type { Blocking } from '@/models/entities/Blocking.js';
|
||||||
import type { User } from '@/models/entities/User.js';
|
import type { User } from '@/models/entities/User.js';
|
||||||
import { UserEntityService } from './UserEntityService.js';
|
import { UserEntityService } from './UserEntityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class BlockingEntityService {
|
export class BlockingEntityService {
|
||||||
|
@ -17,6 +18,7 @@ export class BlockingEntityService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async pack(
|
public async pack(
|
||||||
src: Blocking['id'] | Blocking,
|
src: Blocking['id'] | Blocking,
|
||||||
me?: { id: User['id'] } | null | undefined,
|
me?: { id: User['id'] } | null | undefined,
|
||||||
|
@ -33,6 +35,7 @@ export class BlockingEntityService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public packMany(
|
public packMany(
|
||||||
blockings: any[],
|
blockings: any[],
|
||||||
me: { id: User['id'] },
|
me: { id: User['id'] },
|
||||||
|
|
|
@ -8,6 +8,7 @@ import type { User } from '@/models/entities/User.js';
|
||||||
import type { Channel } from '@/models/entities/Channel.js';
|
import type { Channel } from '@/models/entities/Channel.js';
|
||||||
import { UserEntityService } from './UserEntityService.js';
|
import { UserEntityService } from './UserEntityService.js';
|
||||||
import { DriveFileEntityService } from './DriveFileEntityService.js';
|
import { DriveFileEntityService } from './DriveFileEntityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ChannelEntityService {
|
export class ChannelEntityService {
|
||||||
|
@ -29,6 +30,7 @@ export class ChannelEntityService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async pack(
|
public async pack(
|
||||||
src: Channel['id'] | Channel,
|
src: Channel['id'] | Channel,
|
||||||
me?: { id: User['id'] } | null | undefined,
|
me?: { id: User['id'] } | null | undefined,
|
||||||
|
|
|
@ -7,6 +7,7 @@ import type { } from '@/models/entities/Blocking.js';
|
||||||
import type { User } from '@/models/entities/User.js';
|
import type { User } from '@/models/entities/User.js';
|
||||||
import type { Clip } from '@/models/entities/Clip.js';
|
import type { Clip } from '@/models/entities/Clip.js';
|
||||||
import { UserEntityService } from './UserEntityService.js';
|
import { UserEntityService } from './UserEntityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ClipEntityService {
|
export class ClipEntityService {
|
||||||
|
@ -18,6 +19,7 @@ export class ClipEntityService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async pack(
|
public async pack(
|
||||||
src: Clip['id'] | Clip,
|
src: Clip['id'] | Clip,
|
||||||
): Promise<Packed<'Clip'>> {
|
): Promise<Packed<'Clip'>> {
|
||||||
|
@ -34,6 +36,7 @@ export class ClipEntityService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public packMany(
|
public packMany(
|
||||||
clips: Clip[],
|
clips: Clip[],
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -19,6 +19,7 @@ type PackOptions = {
|
||||||
self?: boolean,
|
self?: boolean,
|
||||||
withUser?: boolean,
|
withUser?: boolean,
|
||||||
};
|
};
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DriveFileEntityService {
|
export class DriveFileEntityService {
|
||||||
|
@ -44,6 +45,7 @@ export class DriveFileEntityService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public validateFileName(name: string): boolean {
|
public validateFileName(name: string): boolean {
|
||||||
return (
|
return (
|
||||||
(name.trim().length > 0) &&
|
(name.trim().length > 0) &&
|
||||||
|
@ -54,6 +56,7 @@ export class DriveFileEntityService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public getPublicProperties(file: DriveFile): DriveFile['properties'] {
|
public getPublicProperties(file: DriveFile): DriveFile['properties'] {
|
||||||
if (file.properties.orientation != null) {
|
if (file.properties.orientation != null) {
|
||||||
const properties = deepClone(file.properties);
|
const properties = deepClone(file.properties);
|
||||||
|
@ -67,6 +70,7 @@ export class DriveFileEntityService {
|
||||||
return file.properties;
|
return file.properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public getPublicUrl(file: DriveFile, thumbnail = false): string | null {
|
public getPublicUrl(file: DriveFile, thumbnail = false): string | null {
|
||||||
// リモートかつメディアプロキシ
|
// リモートかつメディアプロキシ
|
||||||
if (file.uri != null && file.userHost != null && this.config.mediaProxy != null) {
|
if (file.uri != null && file.userHost != null && this.config.mediaProxy != null) {
|
||||||
|
@ -90,6 +94,7 @@ export class DriveFileEntityService {
|
||||||
return thumbnail ? (file.thumbnailUrl ?? (isImage ? (file.webpublicUrl ?? file.url) : null)) : (file.webpublicUrl ?? file.url);
|
return thumbnail ? (file.thumbnailUrl ?? (isImage ? (file.webpublicUrl ?? file.url) : null)) : (file.webpublicUrl ?? file.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async calcDriveUsageOf(user: User['id'] | { id: User['id'] }): Promise<number> {
|
public async calcDriveUsageOf(user: User['id'] | { id: User['id'] }): Promise<number> {
|
||||||
const id = typeof user === 'object' ? user.id : user;
|
const id = typeof user === 'object' ? user.id : user;
|
||||||
|
|
||||||
|
@ -103,6 +108,7 @@ export class DriveFileEntityService {
|
||||||
return parseInt(sum, 10) ?? 0;
|
return parseInt(sum, 10) ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async calcDriveUsageOfHost(host: string): Promise<number> {
|
public async calcDriveUsageOfHost(host: string): Promise<number> {
|
||||||
const { sum } = await this.driveFilesRepository
|
const { sum } = await this.driveFilesRepository
|
||||||
.createQueryBuilder('file')
|
.createQueryBuilder('file')
|
||||||
|
@ -114,6 +120,7 @@ export class DriveFileEntityService {
|
||||||
return parseInt(sum, 10) ?? 0;
|
return parseInt(sum, 10) ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async calcDriveUsageOfLocal(): Promise<number> {
|
public async calcDriveUsageOfLocal(): Promise<number> {
|
||||||
const { sum } = await this.driveFilesRepository
|
const { sum } = await this.driveFilesRepository
|
||||||
.createQueryBuilder('file')
|
.createQueryBuilder('file')
|
||||||
|
@ -125,6 +132,7 @@ export class DriveFileEntityService {
|
||||||
return parseInt(sum, 10) ?? 0;
|
return parseInt(sum, 10) ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async calcDriveUsageOfRemote(): Promise<number> {
|
public async calcDriveUsageOfRemote(): Promise<number> {
|
||||||
const { sum } = await this.driveFilesRepository
|
const { sum } = await this.driveFilesRepository
|
||||||
.createQueryBuilder('file')
|
.createQueryBuilder('file')
|
||||||
|
@ -136,6 +144,7 @@ export class DriveFileEntityService {
|
||||||
return parseInt(sum, 10) ?? 0;
|
return parseInt(sum, 10) ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async pack(
|
public async pack(
|
||||||
src: DriveFile['id'] | DriveFile,
|
src: DriveFile['id'] | DriveFile,
|
||||||
options?: PackOptions,
|
options?: PackOptions,
|
||||||
|
@ -169,6 +178,7 @@ export class DriveFileEntityService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async packNullable(
|
public async packNullable(
|
||||||
src: DriveFile['id'] | DriveFile,
|
src: DriveFile['id'] | DriveFile,
|
||||||
options?: PackOptions,
|
options?: PackOptions,
|
||||||
|
@ -203,6 +213,7 @@ export class DriveFileEntityService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async packMany(
|
public async packMany(
|
||||||
files: (DriveFile['id'] | DriveFile)[],
|
files: (DriveFile['id'] | DriveFile)[],
|
||||||
options?: PackOptions,
|
options?: PackOptions,
|
||||||
|
|
|
@ -7,6 +7,7 @@ import type { } from '@/models/entities/Blocking.js';
|
||||||
import type { User } from '@/models/entities/User.js';
|
import type { User } from '@/models/entities/User.js';
|
||||||
import type { DriveFolder } from '@/models/entities/DriveFolder.js';
|
import type { DriveFolder } from '@/models/entities/DriveFolder.js';
|
||||||
import { UserEntityService } from './UserEntityService.js';
|
import { UserEntityService } from './UserEntityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DriveFolderEntityService {
|
export class DriveFolderEntityService {
|
||||||
|
@ -19,6 +20,7 @@ export class DriveFolderEntityService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async pack(
|
public async pack(
|
||||||
src: DriveFolder['id'] | DriveFolder,
|
src: DriveFolder['id'] | DriveFolder,
|
||||||
options?: {
|
options?: {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import type { } from '@/models/entities/Blocking.js';
|
||||||
import type { User } from '@/models/entities/User.js';
|
import type { User } from '@/models/entities/User.js';
|
||||||
import type { Emoji } from '@/models/entities/Emoji.js';
|
import type { Emoji } from '@/models/entities/Emoji.js';
|
||||||
import { UserEntityService } from './UserEntityService.js';
|
import { UserEntityService } from './UserEntityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class EmojiEntityService {
|
export class EmojiEntityService {
|
||||||
|
@ -18,6 +19,7 @@ export class EmojiEntityService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async pack(
|
public async pack(
|
||||||
src: Emoji['id'] | Emoji,
|
src: Emoji['id'] | Emoji,
|
||||||
): Promise<Packed<'Emoji'>> {
|
): Promise<Packed<'Emoji'>> {
|
||||||
|
@ -34,6 +36,7 @@ export class EmojiEntityService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public packMany(
|
public packMany(
|
||||||
emojis: any[],
|
emojis: any[],
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import type { } from '@/models/entities/Blocking.js';
|
||||||
import type { User } from '@/models/entities/User.js';
|
import type { User } from '@/models/entities/User.js';
|
||||||
import type { FollowRequest } from '@/models/entities/FollowRequest.js';
|
import type { FollowRequest } from '@/models/entities/FollowRequest.js';
|
||||||
import { UserEntityService } from './UserEntityService.js';
|
import { UserEntityService } from './UserEntityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FollowRequestEntityService {
|
export class FollowRequestEntityService {
|
||||||
|
@ -18,6 +19,7 @@ export class FollowRequestEntityService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
public async pack(
|
public async pack(
|
||||||
src: FollowRequest['id'] | FollowRequest,
|
src: FollowRequest['id'] | FollowRequest,
|
||||||
me?: { id: User['id'] } | null | undefined,
|
me?: { id: User['id'] } | null | undefined,
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue