Merge branch 'develop' into feat-1714
This commit is contained in:
		
						commit
						a545d82396
					
				|  | @ -67,7 +67,7 @@ export class AnnouncementService { | |||
| 
 | ||||
| 	@bindThis | ||||
| 	public async create(values: Partial<MiAnnouncement>, moderator?: MiUser): Promise<{ raw: MiAnnouncement; packed: Packed<'Announcement'> }> { | ||||
| 		const announcement = await this.announcementsRepository.insert({ | ||||
| 		const announcement = await this.announcementsRepository.insertOne({ | ||||
| 			id: this.idService.gen(), | ||||
| 			updatedAt: null, | ||||
| 			title: values.title, | ||||
|  | @ -79,7 +79,7 @@ export class AnnouncementService { | |||
| 			silence: values.silence, | ||||
| 			needConfirmationToRead: values.needConfirmationToRead, | ||||
| 			userId: values.userId, | ||||
| 		}).then(x => this.announcementsRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 		}); | ||||
| 
 | ||||
| 		const packed = await this.announcementEntityService.pack(announcement); | ||||
| 
 | ||||
|  |  | |||
|  | @ -55,10 +55,10 @@ export class AvatarDecorationService implements OnApplicationShutdown { | |||
| 
 | ||||
| 	@bindThis | ||||
| 	public async create(options: Partial<MiAvatarDecoration>, moderator?: MiUser): Promise<MiAvatarDecoration> { | ||||
| 		const created = await this.avatarDecorationsRepository.insert({ | ||||
| 		const created = await this.avatarDecorationsRepository.insertOne({ | ||||
| 			id: this.idService.gen(), | ||||
| 			...options, | ||||
| 		}).then(x => this.avatarDecorationsRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 		}); | ||||
| 
 | ||||
| 		this.globalEventService.publishInternalEvent('avatarDecorationCreated', created); | ||||
| 
 | ||||
|  |  | |||
|  | @ -45,13 +45,13 @@ export class ClipService { | |||
| 			throw new ClipService.TooManyClipsError(); | ||||
| 		} | ||||
| 
 | ||||
| 		const clip = await this.clipsRepository.insert({ | ||||
| 		const clip = await this.clipsRepository.insertOne({ | ||||
| 			id: this.idService.gen(), | ||||
| 			userId: me.id, | ||||
| 			name: name, | ||||
| 			isPublic: isPublic, | ||||
| 			description: description, | ||||
| 		}).then(x => this.clipsRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 		}); | ||||
| 
 | ||||
| 		return clip; | ||||
| 	} | ||||
|  |  | |||
|  | @ -68,7 +68,7 @@ export class CustomEmojiService implements OnApplicationShutdown { | |||
| 		localOnly: boolean; | ||||
| 		roleIdsThatCanBeUsedThisEmojiAsReaction: MiRole['id'][]; | ||||
| 	}, moderator?: MiUser): Promise<MiEmoji> { | ||||
| 		const emoji = await this.emojisRepository.insert({ | ||||
| 		const emoji = await this.emojisRepository.insertOne({ | ||||
| 			id: this.idService.gen(), | ||||
| 			updatedAt: new Date(), | ||||
| 			name: data.name, | ||||
|  | @ -82,7 +82,7 @@ export class CustomEmojiService implements OnApplicationShutdown { | |||
| 			isSensitive: data.isSensitive, | ||||
| 			localOnly: data.localOnly, | ||||
| 			roleIdsThatCanBeUsedThisEmojiAsReaction: data.roleIdsThatCanBeUsedThisEmojiAsReaction, | ||||
| 		}).then(x => this.emojisRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 		}); | ||||
| 
 | ||||
| 		if (data.host == null) { | ||||
| 			this.localEmojisCache.refresh(); | ||||
|  |  | |||
|  | @ -220,7 +220,7 @@ export class DriveService { | |||
| 			file.size = size; | ||||
| 			file.storedInternal = false; | ||||
| 
 | ||||
| 			return await this.driveFilesRepository.insert(file).then(x => this.driveFilesRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 			return await this.driveFilesRepository.insertOne(file); | ||||
| 		} else { // use internal storage
 | ||||
| 			const accessKey = randomUUID(); | ||||
| 			const thumbnailAccessKey = 'thumbnail-' + randomUUID(); | ||||
|  | @ -254,7 +254,7 @@ export class DriveService { | |||
| 			file.md5 = hash; | ||||
| 			file.size = size; | ||||
| 
 | ||||
| 			return await this.driveFilesRepository.insert(file).then(x => this.driveFilesRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 			return await this.driveFilesRepository.insertOne(file); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | @ -615,7 +615,7 @@ export class DriveService { | |||
| 				file.type = info.type.mime; | ||||
| 				file.storedInternal = false; | ||||
| 
 | ||||
| 				file = await this.driveFilesRepository.insert(file).then(x => this.driveFilesRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 				file = await this.driveFilesRepository.insertOne(file); | ||||
| 			} catch (err) { | ||||
| 			// duplicate key error (when already registered)
 | ||||
| 				if (isDuplicateKeyValueError(err)) { | ||||
|  |  | |||
|  | @ -55,11 +55,11 @@ export class FederatedInstanceService implements OnApplicationShutdown { | |||
| 		const index = await this.instancesRepository.findOneBy({ host }); | ||||
| 
 | ||||
| 		if (index == null) { | ||||
| 			const i = await this.instancesRepository.insert({ | ||||
| 			const i = await this.instancesRepository.insertOne({ | ||||
| 				id: this.idService.gen(), | ||||
| 				host, | ||||
| 				firstRetrievedAt: new Date(), | ||||
| 			}).then(x => this.instancesRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 			}); | ||||
| 
 | ||||
| 			this.federatedInstanceCache.set(host, i); | ||||
| 			return i; | ||||
|  |  | |||
|  | @ -53,11 +53,11 @@ export class RelayService { | |||
| 
 | ||||
| 	@bindThis | ||||
| 	public async addRelay(inbox: string): Promise<MiRelay> { | ||||
| 		const relay = await this.relaysRepository.insert({ | ||||
| 		const relay = await this.relaysRepository.insertOne({ | ||||
| 			id: this.idService.gen(), | ||||
| 			inbox, | ||||
| 			status: 'requesting', | ||||
| 		}).then(x => this.relaysRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 		}); | ||||
| 
 | ||||
| 		const relayActor = await this.getRelayActor(); | ||||
| 		const follow = await this.apRendererService.renderFollowRelay(relay, relayActor); | ||||
|  |  | |||
|  | @ -281,7 +281,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit { | |||
| 
 | ||||
| 	@bindThis | ||||
| 	private async matched(parentId: MiUser['id'], childId: MiUser['id'], options: { noIrregularRules: boolean; }): Promise<MiReversiGame> { | ||||
| 		const game = await this.reversiGamesRepository.insert({ | ||||
| 		const game = await this.reversiGamesRepository.insertOne({ | ||||
| 			id: this.idService.gen(), | ||||
| 			user1Id: parentId, | ||||
| 			user2Id: childId, | ||||
|  | @ -294,10 +294,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit { | |||
| 			bw: 'random', | ||||
| 			isLlotheo: false, | ||||
| 			noIrregularRules: options.noIrregularRules, | ||||
| 		}).then(x => this.reversiGamesRepository.findOneOrFail({ | ||||
| 			where: { id: x.identifiers[0].id }, | ||||
| 			relations: ['user1', 'user2'], | ||||
| 		})); | ||||
| 		}, { relations: ['user1', 'user2'] }); | ||||
| 		this.cacheGame(game); | ||||
| 
 | ||||
| 		const packed = await this.reversiGameEntityService.packDetail(game); | ||||
|  |  | |||
|  | @ -471,12 +471,12 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit { | |||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		const created = await this.roleAssignmentsRepository.insert({ | ||||
| 		const created = await this.roleAssignmentsRepository.insertOne({ | ||||
| 			id: this.idService.gen(now), | ||||
| 			expiresAt: expiresAt, | ||||
| 			roleId: roleId, | ||||
| 			userId: userId, | ||||
| 		}).then(x => this.roleAssignmentsRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 		}); | ||||
| 
 | ||||
| 		this.rolesRepository.update(roleId, { | ||||
| 			lastUsedAt: new Date(), | ||||
|  | @ -558,7 +558,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit { | |||
| 	@bindThis | ||||
| 	public async create(values: Partial<MiRole>, moderator?: MiUser): Promise<MiRole> { | ||||
| 		const date = new Date(); | ||||
| 		const created = await this.rolesRepository.insert({ | ||||
| 		const created = await this.rolesRepository.insertOne({ | ||||
| 			id: this.idService.gen(date.getTime()), | ||||
| 			updatedAt: date, | ||||
| 			lastUsedAt: date, | ||||
|  | @ -576,7 +576,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit { | |||
| 			canEditMembersByModerator: values.canEditMembersByModerator, | ||||
| 			displayOrder: values.displayOrder, | ||||
| 			policies: values.policies, | ||||
| 		}).then(x => this.rolesRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 		}); | ||||
| 
 | ||||
| 		this.globalEventService.publishInternalEvent('roleCreated', created); | ||||
| 
 | ||||
|  |  | |||
|  | @ -517,7 +517,7 @@ export class UserFollowingService implements OnModuleInit { | |||
| 			followerId: follower.id, | ||||
| 		}); | ||||
| 
 | ||||
| 		const followRequest = await this.followRequestsRepository.insert({ | ||||
| 		const followRequest = await this.followRequestsRepository.insertOne({ | ||||
| 			id: this.idService.gen(), | ||||
| 			followerId: follower.id, | ||||
| 			followeeId: followee.id, | ||||
|  | @ -531,7 +531,7 @@ export class UserFollowingService implements OnModuleInit { | |||
| 			followeeHost: followee.host, | ||||
| 			followeeInbox: this.userEntityService.isRemoteUser(followee) ? followee.inbox : undefined, | ||||
| 			followeeSharedInbox: this.userEntityService.isRemoteUser(followee) ? followee.sharedInbox : undefined, | ||||
| 		}).then(x => this.followRequestsRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 		}); | ||||
| 
 | ||||
| 		// Publish receiveRequest event
 | ||||
| 		if (this.userEntityService.isLocalUser(followee)) { | ||||
|  |  | |||
|  | @ -407,7 +407,7 @@ export class ApNoteService { | |||
| 
 | ||||
| 			this.logger.info(`register emoji host=${host}, name=${name}`); | ||||
| 
 | ||||
| 			return await this.emojisRepository.insert({ | ||||
| 			return await this.emojisRepository.insertOne({ | ||||
| 				id: this.idService.gen(), | ||||
| 				host, | ||||
| 				name, | ||||
|  | @ -416,7 +416,7 @@ export class ApNoteService { | |||
| 				publicUrl: tag.icon.url, | ||||
| 				updatedAt: new Date(), | ||||
| 				aliases: [], | ||||
| 			}).then(x => this.emojisRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 			}); | ||||
| 		})); | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -14,7 +14,8 @@ import { EntitySchema, LessThan, Between } from 'typeorm'; | |||
| import { dateUTC, isTimeSame, isTimeBefore, subtractTime, addTime } from '@/misc/prelude/time.js'; | ||||
| import type Logger from '@/logger.js'; | ||||
| import { bindThis } from '@/decorators.js'; | ||||
| import type { Repository, DataSource } from 'typeorm'; | ||||
| import { MiRepository, miRepository } from '@/models/_.js'; | ||||
| import type { DataSource, Repository } from 'typeorm'; | ||||
| 
 | ||||
| const COLUMN_PREFIX = '___' as const; | ||||
| const UNIQUE_TEMP_COLUMN_PREFIX = 'unique_temp___' as const; | ||||
|  | @ -145,10 +146,10 @@ export default abstract class Chart<T extends Schema> { | |||
| 		group: string | null; | ||||
| 	}[] = []; | ||||
| 	// ↓にしたいけどfindOneとかで型エラーになる
 | ||||
| 	//private repositoryForHour: Repository<RawRecord<T>>;
 | ||||
| 	//private repositoryForDay: Repository<RawRecord<T>>;
 | ||||
| 	private repositoryForHour: Repository<{ id: number; group?: string | null; date: number; }>; | ||||
| 	private repositoryForDay: Repository<{ id: number; group?: string | null; date: number; }>; | ||||
| 	//private repositoryForHour: Repository<RawRecord<T>> & MiRepository<RawRecord<T>>;
 | ||||
| 	//private repositoryForDay: Repository<RawRecord<T>> & MiRepository<RawRecord<T>>;
 | ||||
| 	private repositoryForHour: Repository<{ id: number; group?: string | null; date: number; }> & MiRepository<{ id: number; group?: string | null; date: number; }>; | ||||
| 	private repositoryForDay: Repository<{ id: number; group?: string | null; date: number; }> & MiRepository<{ id: number; group?: string | null; date: number; }>; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * 1日に一回程度実行されれば良いような計算処理を入れる(主にCASCADE削除などアプリケーション側で感知できない変動によるズレの修正用) | ||||
|  | @ -211,6 +212,10 @@ export default abstract class Chart<T extends Schema> { | |||
| 	} { | ||||
| 		const createEntity = (span: 'hour' | 'day'): EntitySchema => new EntitySchema({ | ||||
| 			name: | ||||
| 				span === 'hour' ? `ChartX${name}` : | ||||
| 				span === 'day' ? `ChartDayX${name}` : | ||||
| 				new Error('not happen') as never, | ||||
| 			tableName: | ||||
| 				span === 'hour' ? `__chart__${camelToSnake(name)}` : | ||||
| 				span === 'day' ? `__chart_day__${camelToSnake(name)}` : | ||||
| 				new Error('not happen') as never, | ||||
|  | @ -271,8 +276,8 @@ export default abstract class Chart<T extends Schema> { | |||
| 		this.logger = logger; | ||||
| 
 | ||||
| 		const { hour, day } = Chart.schemaToEntity(name, schema, grouped); | ||||
| 		this.repositoryForHour = db.getRepository<{ id: number; group?: string | null; date: number; }>(hour); | ||||
| 		this.repositoryForDay = db.getRepository<{ id: number; group?: string | null; date: number; }>(day); | ||||
| 		this.repositoryForHour = db.getRepository<{ id: number; group?: string | null; date: number; }>(hour).extend(miRepository as MiRepository<{ id: number; group?: string | null; date: number; }>); | ||||
| 		this.repositoryForDay = db.getRepository<{ id: number; group?: string | null; date: number; }>(day).extend(miRepository as MiRepository<{ id: number; group?: string | null; date: number; }>); | ||||
| 	} | ||||
| 
 | ||||
| 	@bindThis | ||||
|  | @ -387,11 +392,11 @@ export default abstract class Chart<T extends Schema> { | |||
| 			} | ||||
| 
 | ||||
| 			// 新規ログ挿入
 | ||||
| 			log = await repository.insert({ | ||||
| 			log = await repository.insertOne({ | ||||
| 				date: date, | ||||
| 				...(group ? { group: group } : {}), | ||||
| 				...columns, | ||||
| 			}).then(x => repository.findOneByOrFail(x.identifiers[0])) as RawRecord<T>; | ||||
| 			}) as RawRecord<T>; | ||||
| 
 | ||||
| 			this.logger.info(`${this.name + (group ? `:${group}` : '')}(${span}): New commit created`); | ||||
| 
 | ||||
|  |  | |||
|  | @ -5,409 +5,409 @@ | |||
| 
 | ||||
| import { Module } from '@nestjs/common'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
| import { MiAbuseUserReport, MiAccessToken, MiAd, MiAnnouncement, MiAnnouncementRead, MiAntenna, MiApp, MiAuthSession, MiAvatarDecoration, MiBlocking, MiChannel, MiChannelFavorite, MiChannelFollowing, MiClip, MiClipFavorite, MiClipNote, MiDriveFile, MiDriveFolder, MiEmoji, MiFlash, MiFlashLike, MiFollowRequest, MiFollowing, MiGalleryLike, MiGalleryPost, MiHashtag, MiInstance, MiMeta, MiModerationLog, MiMuting, MiNote, MiNoteFavorite, MiNoteReaction, MiNoteThreadMuting, MiNoteUnread, MiPage, MiPageLike, MiPasswordResetRequest, MiPoll, MiPollVote, MiPromoNote, MiPromoRead, MiRegistrationTicket, MiRegistryItem, MiRelay, MiRenoteMuting, MiRetentionAggregation, MiRole, MiRoleAssignment, MiSignin, MiSwSubscription, MiUsedUsername, MiUser, MiUserIp, MiUserKeypair, MiUserList, MiUserListFavorite, MiUserListMembership, MiUserMemo, MiUserNotePining, MiUserPending, MiUserProfile, MiUserPublickey, MiUserSecurityKey, MiWebhook, MiBubbleGameRecord, MiReversiGame } from './_.js'; | ||||
| import { MiRepository, MiAbuseUserReport, MiAccessToken, MiAd, MiAnnouncement, MiAnnouncementRead, MiAntenna, MiApp, MiAuthSession, MiAvatarDecoration, MiBlocking, MiChannel, MiChannelFavorite, MiChannelFollowing, MiClip, MiClipFavorite, MiClipNote, MiDriveFile, MiDriveFolder, MiEmoji, MiFlash, MiFlashLike, MiFollowRequest, MiFollowing, MiGalleryLike, MiGalleryPost, MiHashtag, MiInstance, MiMeta, MiModerationLog, MiMuting, MiNote, MiNoteFavorite, MiNoteReaction, MiNoteThreadMuting, MiNoteUnread, MiPage, MiPageLike, MiPasswordResetRequest, MiPoll, MiPollVote, MiPromoNote, MiPromoRead, MiRegistrationTicket, MiRegistryItem, MiRelay, MiRenoteMuting, MiRetentionAggregation, MiRole, MiRoleAssignment, MiSignin, MiSwSubscription, MiUsedUsername, MiUser, MiUserIp, MiUserKeypair, MiUserList, MiUserListFavorite, MiUserListMembership, MiUserMemo, MiUserNotePining, MiUserPending, MiUserProfile, MiUserPublickey, MiUserSecurityKey, MiWebhook, MiBubbleGameRecord, MiReversiGame, miRepository } from './_.js'; | ||||
| import type { DataSource } from 'typeorm'; | ||||
| import type { Provider } from '@nestjs/common'; | ||||
| 
 | ||||
| const $usersRepository: Provider = { | ||||
| 	provide: DI.usersRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiUser), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiUser).extend(miRepository as MiRepository<MiUser>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $notesRepository: Provider = { | ||||
| 	provide: DI.notesRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiNote), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiNote).extend(miRepository as MiRepository<MiNote>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $announcementsRepository: Provider = { | ||||
| 	provide: DI.announcementsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiAnnouncement), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiAnnouncement).extend(miRepository as MiRepository<MiAnnouncement>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $announcementReadsRepository: Provider = { | ||||
| 	provide: DI.announcementReadsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiAnnouncementRead), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiAnnouncementRead).extend(miRepository as MiRepository<MiAnnouncementRead>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $appsRepository: Provider = { | ||||
| 	provide: DI.appsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiApp), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiApp).extend(miRepository as MiRepository<MiApp>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $avatarDecorationsRepository: Provider = { | ||||
| 	provide: DI.avatarDecorationsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiAvatarDecoration), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiAvatarDecoration).extend(miRepository as MiRepository<MiAvatarDecoration>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $noteFavoritesRepository: Provider = { | ||||
| 	provide: DI.noteFavoritesRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiNoteFavorite), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiNoteFavorite).extend(miRepository as MiRepository<MiNoteFavorite>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $noteThreadMutingsRepository: Provider = { | ||||
| 	provide: DI.noteThreadMutingsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiNoteThreadMuting), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiNoteThreadMuting).extend(miRepository as MiRepository<MiNoteThreadMuting>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $noteReactionsRepository: Provider = { | ||||
| 	provide: DI.noteReactionsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiNoteReaction), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiNoteReaction).extend(miRepository as MiRepository<MiNoteReaction>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $noteUnreadsRepository: Provider = { | ||||
| 	provide: DI.noteUnreadsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiNoteUnread), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiNoteUnread).extend(miRepository as MiRepository<MiNoteUnread>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $pollsRepository: Provider = { | ||||
| 	provide: DI.pollsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiPoll), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiPoll).extend(miRepository as MiRepository<MiPoll>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $pollVotesRepository: Provider = { | ||||
| 	provide: DI.pollVotesRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiPollVote), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiPollVote).extend(miRepository as MiRepository<MiPollVote>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $userProfilesRepository: Provider = { | ||||
| 	provide: DI.userProfilesRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiUserProfile), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiUserProfile).extend(miRepository as MiRepository<MiUserProfile>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $userKeypairsRepository: Provider = { | ||||
| 	provide: DI.userKeypairsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiUserKeypair), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiUserKeypair).extend(miRepository as MiRepository<MiUserKeypair>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $userPendingsRepository: Provider = { | ||||
| 	provide: DI.userPendingsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiUserPending), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiUserPending).extend(miRepository as MiRepository<MiUserPending>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $userSecurityKeysRepository: Provider = { | ||||
| 	provide: DI.userSecurityKeysRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiUserSecurityKey), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiUserSecurityKey).extend(miRepository as MiRepository<MiUserSecurityKey>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $userPublickeysRepository: Provider = { | ||||
| 	provide: DI.userPublickeysRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiUserPublickey), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiUserPublickey).extend(miRepository as MiRepository<MiUserPublickey>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $userListsRepository: Provider = { | ||||
| 	provide: DI.userListsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiUserList), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiUserList).extend(miRepository as MiRepository<MiUserList>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $userListFavoritesRepository: Provider = { | ||||
| 	provide: DI.userListFavoritesRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiUserListFavorite), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiUserListFavorite).extend(miRepository as MiRepository<MiUserListFavorite>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $userListMembershipsRepository: Provider = { | ||||
| 	provide: DI.userListMembershipsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiUserListMembership), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiUserListMembership).extend(miRepository as MiRepository<MiUserListMembership>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $userNotePiningsRepository: Provider = { | ||||
| 	provide: DI.userNotePiningsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiUserNotePining), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiUserNotePining).extend(miRepository as MiRepository<MiUserNotePining>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $userIpsRepository: Provider = { | ||||
| 	provide: DI.userIpsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiUserIp), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiUserIp).extend(miRepository as MiRepository<MiUserIp>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $usedUsernamesRepository: Provider = { | ||||
| 	provide: DI.usedUsernamesRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiUsedUsername), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiUsedUsername).extend(miRepository as MiRepository<MiUsedUsername>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $followingsRepository: Provider = { | ||||
| 	provide: DI.followingsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiFollowing), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiFollowing).extend(miRepository as MiRepository<MiFollowing>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $followRequestsRepository: Provider = { | ||||
| 	provide: DI.followRequestsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiFollowRequest), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiFollowRequest).extend(miRepository as MiRepository<MiFollowRequest>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $instancesRepository: Provider = { | ||||
| 	provide: DI.instancesRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiInstance), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiInstance).extend(miRepository as MiRepository<MiInstance>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $emojisRepository: Provider = { | ||||
| 	provide: DI.emojisRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiEmoji), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiEmoji).extend(miRepository as MiRepository<MiEmoji>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $driveFilesRepository: Provider = { | ||||
| 	provide: DI.driveFilesRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiDriveFile), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiDriveFile).extend(miRepository as MiRepository<MiDriveFile>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $driveFoldersRepository: Provider = { | ||||
| 	provide: DI.driveFoldersRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiDriveFolder), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiDriveFolder).extend(miRepository as MiRepository<MiDriveFolder>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $metasRepository: Provider = { | ||||
| 	provide: DI.metasRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiMeta), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiMeta).extend(miRepository as MiRepository<MiMeta>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $mutingsRepository: Provider = { | ||||
| 	provide: DI.mutingsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiMuting), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiMuting).extend(miRepository as MiRepository<MiMuting>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $renoteMutingsRepository: Provider = { | ||||
| 	provide: DI.renoteMutingsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiRenoteMuting), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiRenoteMuting).extend(miRepository as MiRepository<MiRenoteMuting>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $blockingsRepository: Provider = { | ||||
| 	provide: DI.blockingsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiBlocking), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiBlocking).extend(miRepository as MiRepository<MiBlocking>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $swSubscriptionsRepository: Provider = { | ||||
| 	provide: DI.swSubscriptionsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiSwSubscription), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiSwSubscription).extend(miRepository as MiRepository<MiSwSubscription>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $hashtagsRepository: Provider = { | ||||
| 	provide: DI.hashtagsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiHashtag), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiHashtag).extend(miRepository as MiRepository<MiHashtag>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $abuseUserReportsRepository: Provider = { | ||||
| 	provide: DI.abuseUserReportsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiAbuseUserReport), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiAbuseUserReport).extend(miRepository as MiRepository<MiAbuseUserReport>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $registrationTicketsRepository: Provider = { | ||||
| 	provide: DI.registrationTicketsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiRegistrationTicket), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiRegistrationTicket).extend(miRepository as MiRepository<MiRegistrationTicket>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $authSessionsRepository: Provider = { | ||||
| 	provide: DI.authSessionsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiAuthSession), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiAuthSession).extend(miRepository as MiRepository<MiAuthSession>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $accessTokensRepository: Provider = { | ||||
| 	provide: DI.accessTokensRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiAccessToken), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiAccessToken).extend(miRepository as MiRepository<MiAccessToken>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $signinsRepository: Provider = { | ||||
| 	provide: DI.signinsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiSignin), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiSignin).extend(miRepository as MiRepository<MiSignin>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $pagesRepository: Provider = { | ||||
| 	provide: DI.pagesRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiPage), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiPage).extend(miRepository as MiRepository<MiPage>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $pageLikesRepository: Provider = { | ||||
| 	provide: DI.pageLikesRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiPageLike), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiPageLike).extend(miRepository as MiRepository<MiPageLike>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $galleryPostsRepository: Provider = { | ||||
| 	provide: DI.galleryPostsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiGalleryPost), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiGalleryPost).extend(miRepository as MiRepository<MiGalleryPost>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $galleryLikesRepository: Provider = { | ||||
| 	provide: DI.galleryLikesRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiGalleryLike), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiGalleryLike).extend(miRepository as MiRepository<MiGalleryLike>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $moderationLogsRepository: Provider = { | ||||
| 	provide: DI.moderationLogsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiModerationLog), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiModerationLog).extend(miRepository as MiRepository<MiModerationLog>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $clipsRepository: Provider = { | ||||
| 	provide: DI.clipsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiClip), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiClip).extend(miRepository as MiRepository<MiClip>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $clipNotesRepository: Provider = { | ||||
| 	provide: DI.clipNotesRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiClipNote), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiClipNote).extend(miRepository as MiRepository<MiClipNote>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $clipFavoritesRepository: Provider = { | ||||
| 	provide: DI.clipFavoritesRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiClipFavorite), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiClipFavorite).extend(miRepository as MiRepository<MiClipFavorite>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $antennasRepository: Provider = { | ||||
| 	provide: DI.antennasRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiAntenna), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiAntenna).extend(miRepository as MiRepository<MiAntenna>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $promoNotesRepository: Provider = { | ||||
| 	provide: DI.promoNotesRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiPromoNote), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiPromoNote).extend(miRepository as MiRepository<MiPromoNote>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $promoReadsRepository: Provider = { | ||||
| 	provide: DI.promoReadsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiPromoRead), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiPromoRead).extend(miRepository as MiRepository<MiPromoRead>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $relaysRepository: Provider = { | ||||
| 	provide: DI.relaysRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiRelay), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiRelay).extend(miRepository as MiRepository<MiRelay>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $channelsRepository: Provider = { | ||||
| 	provide: DI.channelsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiChannel), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiChannel).extend(miRepository as MiRepository<MiChannel>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $channelFollowingsRepository: Provider = { | ||||
| 	provide: DI.channelFollowingsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiChannelFollowing), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiChannelFollowing).extend(miRepository as MiRepository<MiChannelFollowing>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $channelFavoritesRepository: Provider = { | ||||
| 	provide: DI.channelFavoritesRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiChannelFavorite), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiChannelFavorite).extend(miRepository as MiRepository<MiChannelFavorite>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $registryItemsRepository: Provider = { | ||||
| 	provide: DI.registryItemsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiRegistryItem), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiRegistryItem).extend(miRepository as MiRepository<MiRegistryItem>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $webhooksRepository: Provider = { | ||||
| 	provide: DI.webhooksRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiWebhook), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiWebhook).extend(miRepository as MiRepository<MiWebhook>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $adsRepository: Provider = { | ||||
| 	provide: DI.adsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiAd), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiAd).extend(miRepository as MiRepository<MiAd>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $passwordResetRequestsRepository: Provider = { | ||||
| 	provide: DI.passwordResetRequestsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiPasswordResetRequest), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiPasswordResetRequest).extend(miRepository as MiRepository<MiPasswordResetRequest>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $retentionAggregationsRepository: Provider = { | ||||
| 	provide: DI.retentionAggregationsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiRetentionAggregation), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiRetentionAggregation).extend(miRepository as MiRepository<MiRetentionAggregation>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $flashsRepository: Provider = { | ||||
| 	provide: DI.flashsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiFlash), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiFlash).extend(miRepository as MiRepository<MiFlash>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $flashLikesRepository: Provider = { | ||||
| 	provide: DI.flashLikesRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiFlashLike), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiFlashLike).extend(miRepository as MiRepository<MiFlashLike>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $rolesRepository: Provider = { | ||||
| 	provide: DI.rolesRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiRole), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiRole).extend(miRepository as MiRepository<MiRole>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $roleAssignmentsRepository: Provider = { | ||||
| 	provide: DI.roleAssignmentsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiRoleAssignment), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiRoleAssignment).extend(miRepository as MiRepository<MiRoleAssignment>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $userMemosRepository: Provider = { | ||||
| 	provide: DI.userMemosRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiUserMemo), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiUserMemo).extend(miRepository as MiRepository<MiUserMemo>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $bubbleGameRecordsRepository: Provider = { | ||||
| 	provide: DI.bubbleGameRecordsRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiBubbleGameRecord), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiBubbleGameRecord).extend(miRepository as MiRepository<MiBubbleGameRecord>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
| const $reversiGamesRepository: Provider = { | ||||
| 	provide: DI.reversiGamesRepository, | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiReversiGame), | ||||
| 	useFactory: (db: DataSource) => db.getRepository(MiReversiGame).extend(miRepository as MiRepository<MiReversiGame>), | ||||
| 	inject: [DI.db], | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,6 +3,13 @@ | |||
|  * SPDX-License-Identifier: AGPL-3.0-only | ||||
|  */ | ||||
| 
 | ||||
| import { FindOneOptions, InsertQueryBuilder, ObjectLiteral, Repository, SelectQueryBuilder, TypeORMError } from 'typeorm'; | ||||
| import { DriverUtils } from 'typeorm/driver/DriverUtils.js'; | ||||
| import { RelationCountLoader } from 'typeorm/query-builder/relation-count/RelationCountLoader.js'; | ||||
| import { RelationIdLoader } from 'typeorm/query-builder/relation-id/RelationIdLoader.js'; | ||||
| import { RawSqlResultsToEntityTransformer } from 'typeorm/query-builder/transformer/RawSqlResultsToEntityTransformer.js'; | ||||
| import { ObjectUtils } from 'typeorm/util/ObjectUtils.js'; | ||||
| import { OrmUtils } from 'typeorm/util/OrmUtils.js'; | ||||
| import { MiAbuseUserReport } from '@/models/AbuseUserReport.js'; | ||||
| import { MiAccessToken } from '@/models/AccessToken.js'; | ||||
| import { MiAd } from '@/models/Ad.js'; | ||||
|  | @ -70,8 +77,70 @@ import { MiFlashLike } from '@/models/FlashLike.js'; | |||
| import { MiUserListFavorite } from '@/models/UserListFavorite.js'; | ||||
| import { MiBubbleGameRecord } from '@/models/BubbleGameRecord.js'; | ||||
| import { MiReversiGame } from '@/models/ReversiGame.js'; | ||||
| import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity.js'; | ||||
| 
 | ||||
| import type { Repository } from 'typeorm'; | ||||
| export interface MiRepository<T extends ObjectLiteral> { | ||||
| 	createTableColumnNames(this: Repository<T> & MiRepository<T>, queryBuilder: InsertQueryBuilder<T>): string[]; | ||||
| 	createTableColumnNamesWithPrimaryKey(this: Repository<T> & MiRepository<T>, queryBuilder: InsertQueryBuilder<T>): string[]; | ||||
| 	insertOne(this: Repository<T> & MiRepository<T>, entity: QueryDeepPartialEntity<T>, findOptions?: Pick<FindOneOptions<T>, 'relations'>): Promise<T>; | ||||
| 	selectAliasColumnNames(this: Repository<T> & MiRepository<T>, queryBuilder: InsertQueryBuilder<T>, builder: SelectQueryBuilder<T>): void; | ||||
| } | ||||
| 
 | ||||
| export const miRepository = { | ||||
| 	createTableColumnNames(queryBuilder) { | ||||
| 		// @ts-expect-error -- protected
 | ||||
| 		const insertedColumns = queryBuilder.getInsertedColumns(); | ||||
| 		if (insertedColumns.length) { | ||||
| 			return insertedColumns.map(column => column.databaseName); | ||||
| 		} | ||||
| 		if (!queryBuilder.expressionMap.mainAlias?.hasMetadata && !queryBuilder.expressionMap.insertColumns.length) { | ||||
| 			// @ts-expect-error -- protected
 | ||||
| 			const valueSets = queryBuilder.getValueSets(); | ||||
| 			if (valueSets.length === 1) { | ||||
| 				return Object.keys(valueSets[0]); | ||||
| 			} | ||||
| 		} | ||||
| 		return queryBuilder.expressionMap.insertColumns; | ||||
| 	}, | ||||
| 	createTableColumnNamesWithPrimaryKey(queryBuilder) { | ||||
| 		const columnNames = this.createTableColumnNames(queryBuilder); | ||||
| 		if (!columnNames.includes('id')) { | ||||
| 			columnNames.unshift('id'); | ||||
| 		} | ||||
| 		return columnNames; | ||||
| 	}, | ||||
| 	async insertOne(entity, findOptions?) { | ||||
| 		const queryBuilder = this.createQueryBuilder().insert().values(entity); | ||||
| 		// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
 | ||||
| 		const mainAlias = queryBuilder.expressionMap.mainAlias!; | ||||
| 		const name = mainAlias.name; | ||||
| 		mainAlias.name = 't'; | ||||
| 		const columnNames = this.createTableColumnNamesWithPrimaryKey(queryBuilder); | ||||
| 		queryBuilder.returning(columnNames.reduce((a, c) => `${a}, ${queryBuilder.escape(c)}`, '').slice(2)); | ||||
| 		const builder = this.createQueryBuilder().addCommonTableExpression(queryBuilder, 'cte', { columnNames }); | ||||
| 		// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
 | ||||
| 		builder.expressionMap.mainAlias!.tablePath = 'cte'; | ||||
| 		this.selectAliasColumnNames(queryBuilder, builder); | ||||
| 		if (findOptions) { | ||||
| 			builder.setFindOptions(findOptions); | ||||
| 		} | ||||
| 		const raw = await builder.execute(); | ||||
| 		mainAlias.name = name; | ||||
| 		const relationId = await new RelationIdLoader(builder.connection, this.queryRunner, builder.expressionMap.relationIdAttributes).load(raw); | ||||
| 		const relationCount = await new RelationCountLoader(builder.connection, this.queryRunner, builder.expressionMap.relationCountAttributes).load(raw); | ||||
| 		const result = new RawSqlResultsToEntityTransformer(builder.expressionMap, builder.connection.driver, relationId, relationCount, this.queryRunner).transform(raw, mainAlias); | ||||
| 		return result[0]; | ||||
| 	}, | ||||
| 	selectAliasColumnNames(queryBuilder, builder) { | ||||
| 		let selectOrAddSelect = (selection: string, selectionAliasName?: string) => { | ||||
| 			selectOrAddSelect = (selection, selectionAliasName) => builder.addSelect(selection, selectionAliasName); | ||||
| 			return builder.select(selection, selectionAliasName); | ||||
| 		}; | ||||
| 		for (const columnName of this.createTableColumnNamesWithPrimaryKey(queryBuilder)) { | ||||
| 			selectOrAddSelect(`${builder.alias}.${columnName}`, `${builder.alias}_${columnName}`); | ||||
| 		} | ||||
| 	}, | ||||
| } satisfies MiRepository<ObjectLiteral>; | ||||
| 
 | ||||
| export { | ||||
| 	MiAbuseUserReport, | ||||
|  | @ -143,70 +212,70 @@ export { | |||
| 	MiReversiGame, | ||||
| }; | ||||
| 
 | ||||
| export type AbuseUserReportsRepository = Repository<MiAbuseUserReport>; | ||||
| export type AccessTokensRepository = Repository<MiAccessToken>; | ||||
| export type AdsRepository = Repository<MiAd>; | ||||
| export type AnnouncementsRepository = Repository<MiAnnouncement>; | ||||
| export type AnnouncementReadsRepository = Repository<MiAnnouncementRead>; | ||||
| export type AntennasRepository = Repository<MiAntenna>; | ||||
| export type AppsRepository = Repository<MiApp>; | ||||
| export type AvatarDecorationsRepository = Repository<MiAvatarDecoration>; | ||||
| export type AuthSessionsRepository = Repository<MiAuthSession>; | ||||
| export type BlockingsRepository = Repository<MiBlocking>; | ||||
| export type ChannelFollowingsRepository = Repository<MiChannelFollowing>; | ||||
| export type ChannelFavoritesRepository = Repository<MiChannelFavorite>; | ||||
| export type ClipsRepository = Repository<MiClip>; | ||||
| export type ClipNotesRepository = Repository<MiClipNote>; | ||||
| export type ClipFavoritesRepository = Repository<MiClipFavorite>; | ||||
| export type DriveFilesRepository = Repository<MiDriveFile>; | ||||
| export type DriveFoldersRepository = Repository<MiDriveFolder>; | ||||
| export type EmojisRepository = Repository<MiEmoji>; | ||||
| export type FollowingsRepository = Repository<MiFollowing>; | ||||
| export type FollowRequestsRepository = Repository<MiFollowRequest>; | ||||
| export type GalleryLikesRepository = Repository<MiGalleryLike>; | ||||
| export type GalleryPostsRepository = Repository<MiGalleryPost>; | ||||
| export type HashtagsRepository = Repository<MiHashtag>; | ||||
| export type InstancesRepository = Repository<MiInstance>; | ||||
| export type MetasRepository = Repository<MiMeta>; | ||||
| export type ModerationLogsRepository = Repository<MiModerationLog>; | ||||
| export type MutingsRepository = Repository<MiMuting>; | ||||
| export type RenoteMutingsRepository = Repository<MiRenoteMuting>; | ||||
| export type NotesRepository = Repository<MiNote>; | ||||
| export type NoteFavoritesRepository = Repository<MiNoteFavorite>; | ||||
| export type NoteReactionsRepository = Repository<MiNoteReaction>; | ||||
| export type NoteThreadMutingsRepository = Repository<MiNoteThreadMuting>; | ||||
| export type NoteUnreadsRepository = Repository<MiNoteUnread>; | ||||
| export type PagesRepository = Repository<MiPage>; | ||||
| export type PageLikesRepository = Repository<MiPageLike>; | ||||
| export type PasswordResetRequestsRepository = Repository<MiPasswordResetRequest>; | ||||
| export type PollsRepository = Repository<MiPoll>; | ||||
| export type PollVotesRepository = Repository<MiPollVote>; | ||||
| export type PromoNotesRepository = Repository<MiPromoNote>; | ||||
| export type PromoReadsRepository = Repository<MiPromoRead>; | ||||
| export type RegistrationTicketsRepository = Repository<MiRegistrationTicket>; | ||||
| export type RegistryItemsRepository = Repository<MiRegistryItem>; | ||||
| export type RelaysRepository = Repository<MiRelay>; | ||||
| export type SigninsRepository = Repository<MiSignin>; | ||||
| export type SwSubscriptionsRepository = Repository<MiSwSubscription>; | ||||
| export type UsedUsernamesRepository = Repository<MiUsedUsername>; | ||||
| export type UsersRepository = Repository<MiUser>; | ||||
| export type UserIpsRepository = Repository<MiUserIp>; | ||||
| export type UserKeypairsRepository = Repository<MiUserKeypair>; | ||||
| export type UserListsRepository = Repository<MiUserList>; | ||||
| export type UserListFavoritesRepository = Repository<MiUserListFavorite>; | ||||
| export type UserListMembershipsRepository = Repository<MiUserListMembership>; | ||||
| export type UserNotePiningsRepository = Repository<MiUserNotePining>; | ||||
| export type UserPendingsRepository = Repository<MiUserPending>; | ||||
| export type UserProfilesRepository = Repository<MiUserProfile>; | ||||
| export type UserPublickeysRepository = Repository<MiUserPublickey>; | ||||
| export type UserSecurityKeysRepository = Repository<MiUserSecurityKey>; | ||||
| export type WebhooksRepository = Repository<MiWebhook>; | ||||
| export type ChannelsRepository = Repository<MiChannel>; | ||||
| export type RetentionAggregationsRepository = Repository<MiRetentionAggregation>; | ||||
| export type RolesRepository = Repository<MiRole>; | ||||
| export type RoleAssignmentsRepository = Repository<MiRoleAssignment>; | ||||
| export type FlashsRepository = Repository<MiFlash>; | ||||
| export type FlashLikesRepository = Repository<MiFlashLike>; | ||||
| export type UserMemoRepository = Repository<MiUserMemo>; | ||||
| export type BubbleGameRecordsRepository = Repository<MiBubbleGameRecord>; | ||||
| export type ReversiGamesRepository = Repository<MiReversiGame>; | ||||
| export type AbuseUserReportsRepository = Repository<MiAbuseUserReport> & MiRepository<MiAbuseUserReport>; | ||||
| export type AccessTokensRepository = Repository<MiAccessToken> & MiRepository<MiAccessToken>; | ||||
| export type AdsRepository = Repository<MiAd> & MiRepository<MiAd>; | ||||
| export type AnnouncementsRepository = Repository<MiAnnouncement> & MiRepository<MiAnnouncement>; | ||||
| export type AnnouncementReadsRepository = Repository<MiAnnouncementRead> & MiRepository<MiAnnouncementRead>; | ||||
| export type AntennasRepository = Repository<MiAntenna> & MiRepository<MiAntenna>; | ||||
| export type AppsRepository = Repository<MiApp> & MiRepository<MiApp>; | ||||
| export type AvatarDecorationsRepository = Repository<MiAvatarDecoration> & MiRepository<MiAvatarDecoration>; | ||||
| export type AuthSessionsRepository = Repository<MiAuthSession> & MiRepository<MiAuthSession>; | ||||
| export type BlockingsRepository = Repository<MiBlocking> & MiRepository<MiBlocking>; | ||||
| export type ChannelFollowingsRepository = Repository<MiChannelFollowing> & MiRepository<MiChannelFollowing>; | ||||
| export type ChannelFavoritesRepository = Repository<MiChannelFavorite> & MiRepository<MiChannelFavorite>; | ||||
| export type ClipsRepository = Repository<MiClip> & MiRepository<MiClip>; | ||||
| export type ClipNotesRepository = Repository<MiClipNote> & MiRepository<MiClipNote>; | ||||
| export type ClipFavoritesRepository = Repository<MiClipFavorite> & MiRepository<MiClipFavorite>; | ||||
| export type DriveFilesRepository = Repository<MiDriveFile> & MiRepository<MiDriveFile>; | ||||
| export type DriveFoldersRepository = Repository<MiDriveFolder> & MiRepository<MiDriveFolder>; | ||||
| export type EmojisRepository = Repository<MiEmoji> & MiRepository<MiEmoji>; | ||||
| export type FollowingsRepository = Repository<MiFollowing> & MiRepository<MiFollowing>; | ||||
| export type FollowRequestsRepository = Repository<MiFollowRequest> & MiRepository<MiFollowRequest>; | ||||
| export type GalleryLikesRepository = Repository<MiGalleryLike> & MiRepository<MiGalleryLike>; | ||||
| export type GalleryPostsRepository = Repository<MiGalleryPost> & MiRepository<MiGalleryPost>; | ||||
| export type HashtagsRepository = Repository<MiHashtag> & MiRepository<MiHashtag>; | ||||
| export type InstancesRepository = Repository<MiInstance> & MiRepository<MiInstance>; | ||||
| export type MetasRepository = Repository<MiMeta> & MiRepository<MiMeta>; | ||||
| export type ModerationLogsRepository = Repository<MiModerationLog> & MiRepository<MiModerationLog>; | ||||
| export type MutingsRepository = Repository<MiMuting> & MiRepository<MiMuting>; | ||||
| export type RenoteMutingsRepository = Repository<MiRenoteMuting> & MiRepository<MiRenoteMuting>; | ||||
| export type NotesRepository = Repository<MiNote> & MiRepository<MiNote>; | ||||
| export type NoteFavoritesRepository = Repository<MiNoteFavorite> & MiRepository<MiNoteFavorite>; | ||||
| export type NoteReactionsRepository = Repository<MiNoteReaction> & MiRepository<MiNoteReaction>; | ||||
| export type NoteThreadMutingsRepository = Repository<MiNoteThreadMuting> & MiRepository<MiNoteThreadMuting>; | ||||
| export type NoteUnreadsRepository = Repository<MiNoteUnread> & MiRepository<MiNoteUnread>; | ||||
| export type PagesRepository = Repository<MiPage> & MiRepository<MiPage>; | ||||
| export type PageLikesRepository = Repository<MiPageLike> & MiRepository<MiPageLike>; | ||||
| export type PasswordResetRequestsRepository = Repository<MiPasswordResetRequest> & MiRepository<MiPasswordResetRequest>; | ||||
| export type PollsRepository = Repository<MiPoll> & MiRepository<MiPoll>; | ||||
| export type PollVotesRepository = Repository<MiPollVote> & MiRepository<MiPollVote>; | ||||
| export type PromoNotesRepository = Repository<MiPromoNote> & MiRepository<MiPromoNote>; | ||||
| export type PromoReadsRepository = Repository<MiPromoRead> & MiRepository<MiPromoRead>; | ||||
| export type RegistrationTicketsRepository = Repository<MiRegistrationTicket> & MiRepository<MiRegistrationTicket>; | ||||
| export type RegistryItemsRepository = Repository<MiRegistryItem> & MiRepository<MiRegistryItem>; | ||||
| export type RelaysRepository = Repository<MiRelay> & MiRepository<MiRelay>; | ||||
| export type SigninsRepository = Repository<MiSignin> & MiRepository<MiSignin>; | ||||
| export type SwSubscriptionsRepository = Repository<MiSwSubscription> & MiRepository<MiSwSubscription>; | ||||
| export type UsedUsernamesRepository = Repository<MiUsedUsername> & MiRepository<MiUsedUsername>; | ||||
| export type UsersRepository = Repository<MiUser> & MiRepository<MiUser>; | ||||
| export type UserIpsRepository = Repository<MiUserIp> & MiRepository<MiUserIp>; | ||||
| export type UserKeypairsRepository = Repository<MiUserKeypair> & MiRepository<MiUserKeypair>; | ||||
| export type UserListsRepository = Repository<MiUserList> & MiRepository<MiUserList>; | ||||
| export type UserListFavoritesRepository = Repository<MiUserListFavorite> & MiRepository<MiUserListFavorite>; | ||||
| export type UserListMembershipsRepository = Repository<MiUserListMembership> & MiRepository<MiUserListMembership>; | ||||
| export type UserNotePiningsRepository = Repository<MiUserNotePining> & MiRepository<MiUserNotePining>; | ||||
| export type UserPendingsRepository = Repository<MiUserPending> & MiRepository<MiUserPending>; | ||||
| export type UserProfilesRepository = Repository<MiUserProfile> & MiRepository<MiUserProfile>; | ||||
| export type UserPublickeysRepository = Repository<MiUserPublickey> & MiRepository<MiUserPublickey>; | ||||
| export type UserSecurityKeysRepository = Repository<MiUserSecurityKey> & MiRepository<MiUserSecurityKey>; | ||||
| export type WebhooksRepository = Repository<MiWebhook> & MiRepository<MiWebhook>; | ||||
| export type ChannelsRepository = Repository<MiChannel> & MiRepository<MiChannel>; | ||||
| export type RetentionAggregationsRepository = Repository<MiRetentionAggregation> & MiRepository<MiRetentionAggregation>; | ||||
| export type RolesRepository = Repository<MiRole> & MiRepository<MiRole>; | ||||
| export type RoleAssignmentsRepository = Repository<MiRoleAssignment> & MiRepository<MiRoleAssignment>; | ||||
| export type FlashsRepository = Repository<MiFlash> & MiRepository<MiFlash>; | ||||
| export type FlashLikesRepository = Repository<MiFlashLike> & MiRepository<MiFlashLike>; | ||||
| export type UserMemoRepository = Repository<MiUserMemo> & MiRepository<MiUserMemo>; | ||||
| export type BubbleGameRecordsRepository = Repository<MiBubbleGameRecord> & MiRepository<MiBubbleGameRecord>; | ||||
| export type ReversiGamesRepository = Repository<MiReversiGame> & MiRepository<MiReversiGame>; | ||||
|  |  | |||
|  | @ -76,7 +76,7 @@ export class ImportAntennasProcessorService { | |||
| 					this.logger.warn('Validation Failed'); | ||||
| 					continue; | ||||
| 				} | ||||
| 				const result = await this.antennasRepository.insert({ | ||||
| 				const result = await this.antennasRepository.insertOne({ | ||||
| 					id: this.idService.gen(now.getTime()), | ||||
| 					lastUsedAt: now, | ||||
| 					userId: job.data.user.id, | ||||
|  | @ -91,7 +91,7 @@ export class ImportAntennasProcessorService { | |||
| 					excludeBots: antenna.excludeBots, | ||||
| 					withReplies: antenna.withReplies, | ||||
| 					withFile: antenna.withFile, | ||||
| 				}).then(x => this.antennasRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 				}); | ||||
| 				this.logger.succ('Antenna created: ' + result.id); | ||||
| 				this.globalEventService.publishInternalEvent('antennaCreated', result); | ||||
| 			} | ||||
|  |  | |||
|  | @ -79,11 +79,11 @@ export class ImportUserListsProcessorService { | |||
| 				}); | ||||
| 
 | ||||
| 				if (list == null) { | ||||
| 					list = await this.userListsRepository.insert({ | ||||
| 					list = await this.userListsRepository.insertOne({ | ||||
| 						id: this.idService.gen(), | ||||
| 						userId: user.id, | ||||
| 						name: listName, | ||||
| 					}).then(x => this.userListsRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 					}); | ||||
| 				} | ||||
| 
 | ||||
| 				let target = this.utilityService.isSelfHost(host!) ? await this.usersRepository.findOneBy({ | ||||
|  |  | |||
|  | @ -29,13 +29,13 @@ export class SigninService { | |||
| 	public signin(request: FastifyRequest, reply: FastifyReply, user: MiLocalUser) { | ||||
| 		setImmediate(async () => { | ||||
| 			// Append signin history
 | ||||
| 			const record = await this.signinsRepository.insert({ | ||||
| 			const record = await this.signinsRepository.insertOne({ | ||||
| 				id: this.idService.gen(), | ||||
| 				userId: user.id, | ||||
| 				ip: request.ip, | ||||
| 				headers: request.headers as any, | ||||
| 				success: true, | ||||
| 			}).then(x => this.signinsRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 			}); | ||||
| 
 | ||||
| 			// Publish signin event
 | ||||
| 			this.globalEventService.publishMainStream(user.id, 'signin', await this.signinEntityService.pack(record)); | ||||
|  |  | |||
|  | @ -183,13 +183,13 @@ export class SignupApiService { | |||
| 			const salt = await bcrypt.genSalt(8); | ||||
| 			const hash = await bcrypt.hash(password, salt); | ||||
| 
 | ||||
| 			const pendingUser = await this.userPendingsRepository.insert({ | ||||
| 			const pendingUser = await this.userPendingsRepository.insertOne({ | ||||
| 				id: this.idService.gen(), | ||||
| 				code, | ||||
| 				email: emailAddress!, | ||||
| 				username: username, | ||||
| 				password: hash, | ||||
| 			}).then(x => this.userPendingsRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 			}); | ||||
| 
 | ||||
| 			const link = `${this.config.url}/signup-complete/${code}`; | ||||
| 
 | ||||
|  |  | |||
|  | @ -50,7 +50,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 		private moderationLogService: ModerationLogService, | ||||
| 	) { | ||||
| 		super(meta, paramDef, async (ps, me) => { | ||||
| 			const ad = await this.adsRepository.insert({ | ||||
| 			const ad = await this.adsRepository.insertOne({ | ||||
| 				id: this.idService.gen(), | ||||
| 				expiresAt: new Date(ps.expiresAt), | ||||
| 				startsAt: new Date(ps.startsAt), | ||||
|  | @ -61,7 +61,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 				ratio: ps.ratio, | ||||
| 				place: ps.place, | ||||
| 				memo: ps.memo, | ||||
| 			}).then(r => this.adsRepository.findOneByOrFail({ id: r.identifiers[0].id })); | ||||
| 			}); | ||||
| 
 | ||||
| 			this.moderationLogService.log(me, 'createAd', { | ||||
| 				adId: ad.id, | ||||
|  |  | |||
|  | @ -66,11 +66,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 			const ticketsPromises = []; | ||||
| 
 | ||||
| 			for (let i = 0; i < ps.count; i++) { | ||||
| 				ticketsPromises.push(this.registrationTicketsRepository.insert({ | ||||
| 				ticketsPromises.push(this.registrationTicketsRepository.insertOne({ | ||||
| 					id: this.idService.gen(), | ||||
| 					expiresAt: ps.expiresAt ? new Date(ps.expiresAt) : null, | ||||
| 					code: generateInviteCode(), | ||||
| 				}).then(x => this.registrationTicketsRepository.findOneByOrFail(x.identifiers[0]))); | ||||
| 				})); | ||||
| 			} | ||||
| 
 | ||||
| 			const tickets = await Promise.all(ticketsPromises); | ||||
|  |  | |||
|  | @ -112,7 +112,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 
 | ||||
| 			const now = new Date(); | ||||
| 
 | ||||
| 			const antenna = await this.antennasRepository.insert({ | ||||
| 			const antenna = await this.antennasRepository.insertOne({ | ||||
| 				id: this.idService.gen(now.getTime()), | ||||
| 				lastUsedAt: now, | ||||
| 				userId: me.id, | ||||
|  | @ -127,7 +127,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 				excludeBots: ps.excludeBots, | ||||
| 				withReplies: ps.withReplies, | ||||
| 				withFile: ps.withFile, | ||||
| 			}).then(x => this.antennasRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 			}); | ||||
| 
 | ||||
| 			this.globalEventService.publishInternalEvent('antennaCreated', antenna); | ||||
| 
 | ||||
|  |  | |||
|  | @ -54,7 +54,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 			const permission = unique(ps.permission.map(v => v.replace(/^(.+)(\/|-)(read|write)$/, '$3:$1'))); | ||||
| 
 | ||||
| 			// Create account
 | ||||
| 			const app = await this.appsRepository.insert({ | ||||
| 			const app = await this.appsRepository.insertOne({ | ||||
| 				id: this.idService.gen(), | ||||
| 				userId: me ? me.id : null, | ||||
| 				name: ps.name, | ||||
|  | @ -62,7 +62,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 				permission, | ||||
| 				callbackUrl: ps.callbackUrl, | ||||
| 				secret: secret, | ||||
| 			}).then(x => this.appsRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 			}); | ||||
| 
 | ||||
| 			return await this.appEntityService.pack(app, null, { | ||||
| 				detail: true, | ||||
|  |  | |||
|  | @ -78,11 +78,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 			const token = randomUUID(); | ||||
| 
 | ||||
| 			// Create session token document
 | ||||
| 			const doc = await this.authSessionsRepository.insert({ | ||||
| 			const doc = await this.authSessionsRepository.insertOne({ | ||||
| 				id: this.idService.gen(), | ||||
| 				appId: app.id, | ||||
| 				token: token, | ||||
| 			}).then(x => this.authSessionsRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 			}); | ||||
| 
 | ||||
| 			return { | ||||
| 				token: doc.token, | ||||
|  |  | |||
|  | @ -80,7 +80,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			const channel = await this.channelsRepository.insert({ | ||||
| 			const channel = await this.channelsRepository.insertOne({ | ||||
| 				id: this.idService.gen(), | ||||
| 				userId: me.id, | ||||
| 				name: ps.name, | ||||
|  | @ -89,7 +89,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 				isSensitive: ps.isSensitive ?? false, | ||||
| 				...(ps.color !== undefined ? { color: ps.color } : {}), | ||||
| 				allowRenoteToExternal: ps.allowRenoteToExternal ?? true, | ||||
| 			} as MiChannel).then(x => this.channelsRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 			} as MiChannel); | ||||
| 
 | ||||
| 			return await this.channelEntityService.pack(channel, me); | ||||
| 		}); | ||||
|  |  | |||
|  | @ -75,12 +75,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 			} | ||||
| 
 | ||||
| 			// Create folder
 | ||||
| 			const folder = await this.driveFoldersRepository.insert({ | ||||
| 			const folder = await this.driveFoldersRepository.insertOne({ | ||||
| 				id: this.idService.gen(), | ||||
| 				name: ps.name, | ||||
| 				parentId: parent !== null ? parent.id : null, | ||||
| 				userId: me.id, | ||||
| 			}).then(x => this.driveFoldersRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 			}); | ||||
| 
 | ||||
| 			const folderObj = await this.driveFolderEntityService.pack(folder); | ||||
| 
 | ||||
|  |  | |||
|  | @ -59,7 +59,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 		private idService: IdService, | ||||
| 	) { | ||||
| 		super(meta, paramDef, async (ps, me) => { | ||||
| 			const flash = await this.flashsRepository.insert({ | ||||
| 			const flash = await this.flashsRepository.insertOne({ | ||||
| 				id: this.idService.gen(), | ||||
| 				userId: me.id, | ||||
| 				updatedAt: new Date(), | ||||
|  | @ -68,7 +68,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 				script: ps.script, | ||||
| 				permissions: ps.permissions, | ||||
| 				visibility: ps.visibility, | ||||
| 			}).then(x => this.flashsRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 			}); | ||||
| 
 | ||||
| 			return await this.flashEntityService.pack(flash); | ||||
| 		}); | ||||
|  |  | |||
|  | @ -76,7 +76,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 				throw new Error(); | ||||
| 			} | ||||
| 
 | ||||
| 			const post = await this.galleryPostsRepository.insert(new MiGalleryPost({ | ||||
| 			const post = await this.galleryPostsRepository.insertOne(new MiGalleryPost({ | ||||
| 				id: this.idService.gen(), | ||||
| 				updatedAt: new Date(), | ||||
| 				title: ps.title, | ||||
|  | @ -84,7 +84,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 				userId: me.id, | ||||
| 				isSensitive: ps.isSensitive, | ||||
| 				fileIds: files.map(file => file.id), | ||||
| 			})).then(x => this.galleryPostsRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 			})); | ||||
| 
 | ||||
| 			return await this.galleryPostEntityService.pack(post, me); | ||||
| 		}); | ||||
|  |  | |||
|  | @ -89,14 +89,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 				throw new ApiError(meta.errors.tooManyWebhooks); | ||||
| 			} | ||||
| 
 | ||||
| 			const webhook = await this.webhooksRepository.insert({ | ||||
| 			const webhook = await this.webhooksRepository.insertOne({ | ||||
| 				id: this.idService.gen(), | ||||
| 				userId: me.id, | ||||
| 				name: ps.name, | ||||
| 				url: ps.url, | ||||
| 				secret: ps.secret, | ||||
| 				on: ps.on, | ||||
| 			}).then(x => this.webhooksRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 			}); | ||||
| 
 | ||||
| 			this.globalEventService.publishInternalEvent('webhookCreated', webhook); | ||||
| 
 | ||||
|  |  | |||
|  | @ -66,13 +66,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			const ticket = await this.registrationTicketsRepository.insert({ | ||||
| 			const ticket = await this.registrationTicketsRepository.insertOne({ | ||||
| 				id: this.idService.gen(), | ||||
| 				createdBy: me, | ||||
| 				createdById: me.id, | ||||
| 				expiresAt: policies.inviteExpirationTime ? new Date(Date.now() + (policies.inviteExpirationTime * 1000 * 60)) : null, | ||||
| 				code: generateInviteCode(), | ||||
| 			}).then(x => this.registrationTicketsRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 			}); | ||||
| 
 | ||||
| 			return await this.inviteCodeEntityService.pack(ticket, me); | ||||
| 		}); | ||||
|  |  | |||
|  | @ -144,12 +144,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 			} | ||||
| 
 | ||||
| 			// Create vote
 | ||||
| 			const vote = await this.pollVotesRepository.insert({ | ||||
| 			const vote = await this.pollVotesRepository.insertOne({ | ||||
| 				id: this.idService.gen(createdAt.getTime()), | ||||
| 				noteId: note.id, | ||||
| 				userId: me.id, | ||||
| 				choice: ps.choice, | ||||
| 			}).then(x => this.pollVotesRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 			}); | ||||
| 
 | ||||
| 			// Increment votes count
 | ||||
| 			const index = ps.choice + 1; // In SQL, array index is 1 based
 | ||||
|  |  | |||
|  | @ -102,7 +102,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 				} | ||||
| 			}); | ||||
| 
 | ||||
| 			const page = await this.pagesRepository.insert(new MiPage({ | ||||
| 			const page = await this.pagesRepository.insertOne(new MiPage({ | ||||
| 				id: this.idService.gen(), | ||||
| 				updatedAt: new Date(), | ||||
| 				title: ps.title, | ||||
|  | @ -117,7 +117,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 				alignCenter: ps.alignCenter, | ||||
| 				hideTitleWhenPinned: ps.hideTitleWhenPinned, | ||||
| 				font: ps.font, | ||||
| 			})).then(x => this.pagesRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 			})); | ||||
| 
 | ||||
| 			return await this.pageEntityService.pack(page); | ||||
| 		}); | ||||
|  |  | |||
|  | @ -104,11 +104,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 				throw new ApiError(meta.errors.tooManyUserLists); | ||||
| 			} | ||||
| 
 | ||||
| 			const userList = await this.userListsRepository.insert({ | ||||
| 			const userList = await this.userListsRepository.insertOne({ | ||||
| 				id: this.idService.gen(), | ||||
| 				userId: me.id, | ||||
| 				name: ps.name, | ||||
| 			} as MiUserList).then(x => this.userListsRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 			} as MiUserList); | ||||
| 
 | ||||
| 			const users = (await this.userListMembershipsRepository.findBy({ | ||||
| 				userListId: ps.listId, | ||||
|  |  | |||
|  | @ -65,11 +65,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 				throw new ApiError(meta.errors.tooManyUserLists); | ||||
| 			} | ||||
| 
 | ||||
| 			const userList = await this.userListsRepository.insert({ | ||||
| 			const userList = await this.userListsRepository.insertOne({ | ||||
| 				id: this.idService.gen(), | ||||
| 				userId: me.id, | ||||
| 				name: ps.name, | ||||
| 			} as MiUserList).then(x => this.userListsRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 			} as MiUserList); | ||||
| 
 | ||||
| 			return await this.userListEntityService.pack(userList); | ||||
| 		}); | ||||
|  |  | |||
|  | @ -82,14 +82,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 				throw new ApiError(meta.errors.cannotReportAdmin); | ||||
| 			} | ||||
| 
 | ||||
| 			const report = await this.abuseUserReportsRepository.insert({ | ||||
| 			const report = await this.abuseUserReportsRepository.insertOne({ | ||||
| 				id: this.idService.gen(), | ||||
| 				targetUserId: user.id, | ||||
| 				targetUserHost: user.host, | ||||
| 				reporterId: me.id, | ||||
| 				reporterHost: null, | ||||
| 				comment: ps.comment, | ||||
| 			}).then(x => this.abuseUserReportsRepository.findOneByOrFail(x.identifiers[0])); | ||||
| 			}); | ||||
| 
 | ||||
| 			// Publish event to moderators
 | ||||
| 			setImmediate(async () => { | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ process.env.NODE_ENV = 'test'; | |||
| 
 | ||||
| import * as assert from 'assert'; | ||||
| import { loadConfig } from '@/config.js'; | ||||
| import { MiUser, UsersRepository } from '@/models/_.js'; | ||||
| import { MiRepository, MiUser, UsersRepository, miRepository } from '@/models/_.js'; | ||||
| import { secureRndstr } from '@/misc/secure-rndstr.js'; | ||||
| import { jobQueue } from '@/boot/common.js'; | ||||
| import { api, initTestDb, signup, sleep, successfulApiCall, uploadFile } from '../utils.js'; | ||||
|  | @ -42,7 +42,7 @@ describe('Account Move', () => { | |||
| 		dave = await signup({ username: 'dave' }); | ||||
| 		eve = await signup({ username: 'eve' }); | ||||
| 		frank = await signup({ username: 'frank' }); | ||||
| 		Users = connection.getRepository(MiUser); | ||||
| 		Users = connection.getRepository(MiUser).extend(miRepository as MiRepository<MiUser>); | ||||
| 	}, 1000 * 60 * 2); | ||||
| 
 | ||||
| 	afterAll(async () => { | ||||
|  |  | |||
|  | @ -0,0 +1,33 @@ | |||
| /* | ||||
|  * SPDX-FileCopyrightText: syuilo and misskey-project | ||||
|  * SPDX-License-Identifier: AGPL-3.0-only | ||||
|  */ | ||||
| 
 | ||||
| process.env.NODE_ENV = 'test'; | ||||
| 
 | ||||
| import * as assert from 'assert'; | ||||
| import { ReversiMatchResponse } from 'misskey-js/entities.js'; | ||||
| import { api, signup } from '../utils.js'; | ||||
| import type * as misskey from 'misskey-js'; | ||||
| 
 | ||||
| describe('ReversiGame', () => { | ||||
| 	let alice: misskey.entities.SignupResponse; | ||||
| 	let bob: misskey.entities.SignupResponse; | ||||
| 
 | ||||
| 	beforeAll(async () => { | ||||
| 		alice = await signup({ username: 'alice' }); | ||||
| 		bob = await signup({ username: 'bob' }); | ||||
| 	}, 1000 * 60 * 2); | ||||
| 
 | ||||
| 	test('matches when alice invites bob and bob accepts', async () => { | ||||
| 		const response1 = await api('reversi/match', { userId: bob.id }, alice); | ||||
| 		assert.strictEqual(response1.status, 204); | ||||
| 		assert.strictEqual(response1.body, null); | ||||
| 		const response2 = await api('reversi/match', { userId: alice.id }, bob); | ||||
| 		assert.strictEqual(response2.status, 200); | ||||
| 		assert.notStrictEqual(response2.body, null); | ||||
| 		const body = response2.body as ReversiMatchResponse; | ||||
| 		assert.strictEqual(body.user1.id, alice.id); | ||||
| 		assert.strictEqual(body.user2.id, bob.id); | ||||
| 	}); | ||||
| }); | ||||
		Loading…
	
		Reference in New Issue