refactor: migrate to typeorm 3.0 (#8443)
* wip * wip * wip * Update following.ts * wip * wip * wip * Update resolve-user.ts * maxQueryExecutionTime * wip * wip
This commit is contained in:
		| @@ -1,4 +1,6 @@ | ||||
| import { getRepository, getCustomRepository } from 'typeorm'; | ||||
| import { } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
|  | ||||
| import { Announcement } from './entities/announcement.js'; | ||||
| import { AnnouncementRead } from './entities/announcement-read.js'; | ||||
| import { Instance } from './entities/instance.js'; | ||||
| @@ -63,65 +65,65 @@ import { PasswordResetRequest } from './entities/password-reset-request.js'; | ||||
| import { UserPending } from './entities/user-pending.js'; | ||||
| import { InstanceRepository } from './repositories/instance.js'; | ||||
|  | ||||
| export const Announcements = getRepository(Announcement); | ||||
| export const AnnouncementReads = getRepository(AnnouncementRead); | ||||
| export const Apps = getCustomRepository(AppRepository); | ||||
| export const Notes = getCustomRepository(NoteRepository); | ||||
| export const NoteFavorites = getCustomRepository(NoteFavoriteRepository); | ||||
| export const NoteWatchings = getRepository(NoteWatching); | ||||
| export const NoteThreadMutings = getRepository(NoteThreadMuting); | ||||
| export const NoteReactions = getCustomRepository(NoteReactionRepository); | ||||
| export const NoteUnreads = getRepository(NoteUnread); | ||||
| export const Polls = getRepository(Poll); | ||||
| export const PollVotes = getRepository(PollVote); | ||||
| export const Users = getCustomRepository(UserRepository); | ||||
| export const UserProfiles = getRepository(UserProfile); | ||||
| export const UserKeypairs = getRepository(UserKeypair); | ||||
| export const UserPendings = getRepository(UserPending); | ||||
| export const AttestationChallenges = getRepository(AttestationChallenge); | ||||
| export const UserSecurityKeys = getRepository(UserSecurityKey); | ||||
| export const UserPublickeys = getRepository(UserPublickey); | ||||
| export const UserLists = getCustomRepository(UserListRepository); | ||||
| export const UserListJoinings = getRepository(UserListJoining); | ||||
| export const UserGroups = getCustomRepository(UserGroupRepository); | ||||
| export const UserGroupJoinings = getRepository(UserGroupJoining); | ||||
| export const UserGroupInvitations = getCustomRepository(UserGroupInvitationRepository); | ||||
| export const UserNotePinings = getRepository(UserNotePining); | ||||
| export const UsedUsernames = getRepository(UsedUsername); | ||||
| export const Followings = getCustomRepository(FollowingRepository); | ||||
| export const FollowRequests = getCustomRepository(FollowRequestRepository); | ||||
| export const Instances = getCustomRepository(InstanceRepository); | ||||
| export const Emojis = getCustomRepository(EmojiRepository); | ||||
| export const DriveFiles = getCustomRepository(DriveFileRepository); | ||||
| export const DriveFolders = getCustomRepository(DriveFolderRepository); | ||||
| export const Notifications = getCustomRepository(NotificationRepository); | ||||
| export const Metas = getRepository(Meta); | ||||
| export const Mutings = getCustomRepository(MutingRepository); | ||||
| export const Blockings = getCustomRepository(BlockingRepository); | ||||
| export const SwSubscriptions = getRepository(SwSubscription); | ||||
| export const Hashtags = getCustomRepository(HashtagRepository); | ||||
| export const AbuseUserReports = getCustomRepository(AbuseUserReportRepository); | ||||
| export const RegistrationTickets = getRepository(RegistrationTicket); | ||||
| export const AuthSessions = getCustomRepository(AuthSessionRepository); | ||||
| export const AccessTokens = getRepository(AccessToken); | ||||
| export const Signins = getCustomRepository(SigninRepository); | ||||
| export const MessagingMessages = getCustomRepository(MessagingMessageRepository); | ||||
| export const Pages = getCustomRepository(PageRepository); | ||||
| export const PageLikes = getCustomRepository(PageLikeRepository); | ||||
| export const GalleryPosts = getCustomRepository(GalleryPostRepository); | ||||
| export const GalleryLikes = getCustomRepository(GalleryLikeRepository); | ||||
| export const ModerationLogs = getCustomRepository(ModerationLogRepository); | ||||
| export const Clips = getCustomRepository(ClipRepository); | ||||
| export const ClipNotes = getRepository(ClipNote); | ||||
| export const Antennas = getCustomRepository(AntennaRepository); | ||||
| export const AntennaNotes = getRepository(AntennaNote); | ||||
| export const PromoNotes = getRepository(PromoNote); | ||||
| export const PromoReads = getRepository(PromoRead); | ||||
| export const Relays = getCustomRepository(RelayRepository); | ||||
| export const MutedNotes = getRepository(MutedNote); | ||||
| export const Channels = getCustomRepository(ChannelRepository); | ||||
| export const ChannelFollowings = getRepository(ChannelFollowing); | ||||
| export const ChannelNotePinings = getRepository(ChannelNotePining); | ||||
| export const RegistryItems = getRepository(RegistryItem); | ||||
| export const Ads = getRepository(Ad); | ||||
| export const PasswordResetRequests = getRepository(PasswordResetRequest); | ||||
| export const Announcements = db.getRepository(Announcement); | ||||
| export const AnnouncementReads = db.getRepository(AnnouncementRead); | ||||
| export const Apps = (AppRepository); | ||||
| export const Notes = (NoteRepository); | ||||
| export const NoteFavorites = (NoteFavoriteRepository); | ||||
| export const NoteWatchings = db.getRepository(NoteWatching); | ||||
| export const NoteThreadMutings = db.getRepository(NoteThreadMuting); | ||||
| export const NoteReactions = (NoteReactionRepository); | ||||
| export const NoteUnreads = db.getRepository(NoteUnread); | ||||
| export const Polls = db.getRepository(Poll); | ||||
| export const PollVotes = db.getRepository(PollVote); | ||||
| export const Users = (UserRepository); | ||||
| export const UserProfiles = db.getRepository(UserProfile); | ||||
| export const UserKeypairs = db.getRepository(UserKeypair); | ||||
| export const UserPendings = db.getRepository(UserPending); | ||||
| export const AttestationChallenges = db.getRepository(AttestationChallenge); | ||||
| export const UserSecurityKeys = db.getRepository(UserSecurityKey); | ||||
| export const UserPublickeys = db.getRepository(UserPublickey); | ||||
| export const UserLists = (UserListRepository); | ||||
| export const UserListJoinings = db.getRepository(UserListJoining); | ||||
| export const UserGroups = (UserGroupRepository); | ||||
| export const UserGroupJoinings = db.getRepository(UserGroupJoining); | ||||
| export const UserGroupInvitations = (UserGroupInvitationRepository); | ||||
| export const UserNotePinings = db.getRepository(UserNotePining); | ||||
| export const UsedUsernames = db.getRepository(UsedUsername); | ||||
| export const Followings = (FollowingRepository); | ||||
| export const FollowRequests = (FollowRequestRepository); | ||||
| export const Instances = (InstanceRepository); | ||||
| export const Emojis = (EmojiRepository); | ||||
| export const DriveFiles = (DriveFileRepository); | ||||
| export const DriveFolders = (DriveFolderRepository); | ||||
| export const Notifications = (NotificationRepository); | ||||
| export const Metas = db.getRepository(Meta); | ||||
| export const Mutings = (MutingRepository); | ||||
| export const Blockings = (BlockingRepository); | ||||
| export const SwSubscriptions = db.getRepository(SwSubscription); | ||||
| export const Hashtags = (HashtagRepository); | ||||
| export const AbuseUserReports = (AbuseUserReportRepository); | ||||
| export const RegistrationTickets = db.getRepository(RegistrationTicket); | ||||
| export const AuthSessions = (AuthSessionRepository); | ||||
| export const AccessTokens = db.getRepository(AccessToken); | ||||
| export const Signins = (SigninRepository); | ||||
| export const MessagingMessages = (MessagingMessageRepository); | ||||
| export const Pages = (PageRepository); | ||||
| export const PageLikes = (PageLikeRepository); | ||||
| export const GalleryPosts = (GalleryPostRepository); | ||||
| export const GalleryLikes = (GalleryLikeRepository); | ||||
| export const ModerationLogs = (ModerationLogRepository); | ||||
| export const Clips = (ClipRepository); | ||||
| export const ClipNotes = db.getRepository(ClipNote); | ||||
| export const Antennas = (AntennaRepository); | ||||
| export const AntennaNotes = db.getRepository(AntennaNote); | ||||
| export const PromoNotes = db.getRepository(PromoNote); | ||||
| export const PromoReads = db.getRepository(PromoRead); | ||||
| export const Relays = (RelayRepository); | ||||
| export const MutedNotes = db.getRepository(MutedNote); | ||||
| export const Channels = (ChannelRepository); | ||||
| export const ChannelFollowings = db.getRepository(ChannelFollowing); | ||||
| export const ChannelNotePinings = db.getRepository(ChannelNotePining); | ||||
| export const RegistryItems = db.getRepository(RegistryItem); | ||||
| export const Ads = db.getRepository(Ad); | ||||
| export const PasswordResetRequests = db.getRepository(PasswordResetRequest); | ||||
|   | ||||
| @@ -1,14 +1,13 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { Users } from '../index.js'; | ||||
| import { AbuseUserReport } from '@/models/entities/abuse-user-report.js'; | ||||
| import { awaitAll } from '@/prelude/await-all.js'; | ||||
|  | ||||
| @EntityRepository(AbuseUserReport) | ||||
| export class AbuseUserReportRepository extends Repository<AbuseUserReport> { | ||||
| 	public async pack( | ||||
| export const AbuseUserReportRepository = db.getRepository(AbuseUserReport).extend({ | ||||
| 	async pack( | ||||
| 		src: AbuseUserReport['id'] | AbuseUserReport, | ||||
| 	) { | ||||
| 		const report = typeof src === 'object' ? src : await this.findOneOrFail(src); | ||||
| 		const report = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); | ||||
|  | ||||
| 		return await awaitAll({ | ||||
| 			id: report.id, | ||||
| @@ -29,11 +28,11 @@ export class AbuseUserReportRepository extends Repository<AbuseUserReport> { | ||||
| 			}) : null, | ||||
| 			forwarded: report.forwarded, | ||||
| 		}); | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public packMany( | ||||
| 	packMany( | ||||
| 		reports: any[], | ||||
| 	) { | ||||
| 		return Promise.all(reports.map(x => this.pack(x))); | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,17 +1,16 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { Antenna } from '@/models/entities/antenna.js'; | ||||
| import { Packed } from '@/misc/schema.js'; | ||||
| import { AntennaNotes, UserGroupJoinings } from '../index.js'; | ||||
|  | ||||
| @EntityRepository(Antenna) | ||||
| export class AntennaRepository extends Repository<Antenna> { | ||||
| 	public async pack( | ||||
| export const AntennaRepository = db.getRepository(Antenna).extend({ | ||||
| 	async pack( | ||||
| 		src: Antenna['id'] | Antenna, | ||||
| 	): Promise<Packed<'Antenna'>> { | ||||
| 		const antenna = typeof src === 'object' ? src : await this.findOneOrFail(src); | ||||
| 		const antenna = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); | ||||
|  | ||||
| 		const hasUnreadNote = (await AntennaNotes.findOne({ antennaId: antenna.id, read: false })) != null; | ||||
| 		const userGroupJoining = antenna.userGroupJoiningId ? await UserGroupJoinings.findOne(antenna.userGroupJoiningId) : null; | ||||
| 		const hasUnreadNote = (await AntennaNotes.findOneBy({ antennaId: antenna.id, read: false })) != null; | ||||
| 		const userGroupJoining = antenna.userGroupJoiningId ? await UserGroupJoinings.findOneBy({ id: antenna.userGroupJoiningId }) : null; | ||||
|  | ||||
| 		return { | ||||
| 			id: antenna.id, | ||||
| @@ -29,5 +28,5 @@ export class AntennaRepository extends Repository<Antenna> { | ||||
| 			withFile: antenna.withFile, | ||||
| 			hasUnreadNote, | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,12 +1,11 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { App } from '@/models/entities/app.js'; | ||||
| import { AccessTokens } from '../index.js'; | ||||
| import { Packed } from '@/misc/schema.js'; | ||||
| import { User } from '../entities/user.js'; | ||||
|  | ||||
| @EntityRepository(App) | ||||
| export class AppRepository extends Repository<App> { | ||||
| 	public async pack( | ||||
| export const AppRepository = db.getRepository(App).extend({ | ||||
| 	async pack( | ||||
| 		src: App['id'] | App, | ||||
| 		me?: { id: User['id'] } | null | undefined, | ||||
| 		options?: { | ||||
| @@ -21,7 +20,7 @@ export class AppRepository extends Repository<App> { | ||||
| 			includeProfileImageIds: false, | ||||
| 		}, options); | ||||
|  | ||||
| 		const app = typeof src === 'object' ? src : await this.findOneOrFail(src); | ||||
| 		const app = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); | ||||
|  | ||||
| 		return { | ||||
| 			id: app.id, | ||||
| @@ -30,11 +29,11 @@ export class AppRepository extends Repository<App> { | ||||
| 			permission: app.permission, | ||||
| 			...(opts.includeSecret ? { secret: app.secret } : {}), | ||||
| 			...(me ? { | ||||
| 				isAuthorized: await AccessTokens.count({ | ||||
| 				isAuthorized: await AccessTokens.countBy({ | ||||
| 					appId: app.id, | ||||
| 					userId: me.id, | ||||
| 				}).then(count => count > 0), | ||||
| 			} : {}), | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,21 +1,20 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { Apps } from '../index.js'; | ||||
| import { AuthSession } from '@/models/entities/auth-session.js'; | ||||
| import { awaitAll } from '@/prelude/await-all.js'; | ||||
| import { User } from '@/models/entities/user.js'; | ||||
|  | ||||
| @EntityRepository(AuthSession) | ||||
| export class AuthSessionRepository extends Repository<AuthSession> { | ||||
| 	public async pack( | ||||
| export const AuthSessionRepository = db.getRepository(AuthSession).extend({ | ||||
| 	async pack( | ||||
| 		src: AuthSession['id'] | AuthSession, | ||||
| 		me?: { id: User['id'] } | null | undefined | ||||
| 	) { | ||||
| 		const session = typeof src === 'object' ? src : await this.findOneOrFail(src); | ||||
| 		const session = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); | ||||
|  | ||||
| 		return await awaitAll({ | ||||
| 			id: session.id, | ||||
| 			app: Apps.pack(session.appId, me), | ||||
| 			token: session.token, | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,17 +1,16 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { Users } from '../index.js'; | ||||
| import { Blocking } from '@/models/entities/blocking.js'; | ||||
| import { awaitAll } from '@/prelude/await-all.js'; | ||||
| import { Packed } from '@/misc/schema.js'; | ||||
| import { User } from '@/models/entities/user.js'; | ||||
|  | ||||
| @EntityRepository(Blocking) | ||||
| export class BlockingRepository extends Repository<Blocking> { | ||||
| 	public async pack( | ||||
| export const BlockingRepository = db.getRepository(Blocking).extend({ | ||||
| 	async pack( | ||||
| 		src: Blocking['id'] | Blocking, | ||||
| 		me?: { id: User['id'] } | null | undefined | ||||
| 	): Promise<Packed<'Blocking'>> { | ||||
| 		const blocking = typeof src === 'object' ? src : await this.findOneOrFail(src); | ||||
| 		const blocking = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); | ||||
|  | ||||
| 		return await awaitAll({ | ||||
| 			id: blocking.id, | ||||
| @@ -21,12 +20,12 @@ export class BlockingRepository extends Repository<Blocking> { | ||||
| 				detail: true, | ||||
| 			}), | ||||
| 		}); | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public packMany( | ||||
| 	packMany( | ||||
| 		blockings: any[], | ||||
| 		me: { id: User['id'] } | ||||
| 	) { | ||||
| 		return Promise.all(blockings.map(x => this.pack(x, me))); | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,23 +1,22 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { Channel } from '@/models/entities/channel.js'; | ||||
| import { Packed } from '@/misc/schema.js'; | ||||
| import { DriveFiles, ChannelFollowings, NoteUnreads } from '../index.js'; | ||||
| import { User } from '@/models/entities/user.js'; | ||||
|  | ||||
| @EntityRepository(Channel) | ||||
| export class ChannelRepository extends Repository<Channel> { | ||||
| 	public async pack( | ||||
| export const ChannelRepository = db.getRepository(Channel).extend({ | ||||
| 	async pack( | ||||
| 		src: Channel['id'] | Channel, | ||||
| 		me?: { id: User['id'] } | null | undefined, | ||||
| 	): Promise<Packed<'Channel'>> { | ||||
| 		const channel = typeof src === 'object' ? src : await this.findOneOrFail(src); | ||||
| 		const channel = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); | ||||
| 		const meId = me ? me.id : null; | ||||
|  | ||||
| 		const banner = channel.bannerId ? await DriveFiles.findOne(channel.bannerId) : null; | ||||
| 		const banner = channel.bannerId ? await DriveFiles.findOneBy({ id: channel.bannerId }) : null; | ||||
|  | ||||
| 		const hasUnreadNote = meId ? (await NoteUnreads.findOne({ noteChannelId: channel.id, userId: meId })) != null : undefined; | ||||
| 		const hasUnreadNote = meId ? (await NoteUnreads.findOneBy({ noteChannelId: channel.id, userId: meId })) != null : undefined; | ||||
|  | ||||
| 		const following = meId ? await ChannelFollowings.findOne({ | ||||
| 		const following = meId ? await ChannelFollowings.findOneBy({ | ||||
| 			followerId: meId, | ||||
| 			followeeId: channel.id, | ||||
| 		}) : null; | ||||
| @@ -38,5 +37,5 @@ export class ChannelRepository extends Repository<Channel> { | ||||
| 				hasUnreadNote, | ||||
| 			} : {}), | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,15 +1,14 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { Clip } from '@/models/entities/clip.js'; | ||||
| import { Packed } from '@/misc/schema.js'; | ||||
| import { Users } from '../index.js'; | ||||
| import { awaitAll } from '@/prelude/await-all.js'; | ||||
|  | ||||
| @EntityRepository(Clip) | ||||
| export class ClipRepository extends Repository<Clip> { | ||||
| 	public async pack( | ||||
| export const ClipRepository = db.getRepository(Clip).extend({ | ||||
| 	async pack( | ||||
| 		src: Clip['id'] | Clip, | ||||
| 	): Promise<Packed<'Clip'>> { | ||||
| 		const clip = typeof src === 'object' ? src : await this.findOneOrFail(src); | ||||
| 		const clip = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); | ||||
|  | ||||
| 		return await awaitAll({ | ||||
| 			id: clip.id, | ||||
| @@ -20,12 +19,12 @@ export class ClipRepository extends Repository<Clip> { | ||||
| 			description: clip.description, | ||||
| 			isPublic: clip.isPublic, | ||||
| 		}); | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public packMany( | ||||
| 	packMany( | ||||
| 		clips: Clip[], | ||||
| 	) { | ||||
| 		return Promise.all(clips.map(x => this.pack(x))); | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|  | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { DriveFile } from '@/models/entities/drive-file.js'; | ||||
| import { Users, DriveFolders } from '../index.js'; | ||||
| import { User } from '@/models/entities/user.js'; | ||||
| @@ -16,9 +16,8 @@ type PackOptions = { | ||||
| 	withUser?: boolean, | ||||
| }; | ||||
|  | ||||
| @EntityRepository(DriveFile) | ||||
| export class DriveFileRepository extends Repository<DriveFile> { | ||||
| 	public validateFileName(name: string): boolean { | ||||
| export const DriveFileRepository = db.getRepository(DriveFile).extend({ | ||||
| 	validateFileName(name: string): boolean { | ||||
| 		return ( | ||||
| 			(name.trim().length > 0) && | ||||
| 			(name.length <= 200) && | ||||
| @@ -26,9 +25,9 @@ export class DriveFileRepository extends Repository<DriveFile> { | ||||
| 			(name.indexOf('/') === -1) && | ||||
| 			(name.indexOf('..') === -1) | ||||
| 		); | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public getPublicProperties(file: DriveFile): DriveFile['properties'] { | ||||
| 	getPublicProperties(file: DriveFile): DriveFile['properties'] { | ||||
| 		if (file.properties.orientation != null) { | ||||
| 			const properties = JSON.parse(JSON.stringify(file.properties)); | ||||
| 			if (file.properties.orientation >= 5) { | ||||
| @@ -39,9 +38,9 @@ export class DriveFileRepository extends Repository<DriveFile> { | ||||
| 		} | ||||
|  | ||||
| 		return file.properties; | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public getPublicUrl(file: DriveFile, thumbnail = false): string | null { | ||||
| 	getPublicUrl(file: DriveFile, thumbnail = false): string | null { | ||||
| 		// リモートかつメディアプロキシ | ||||
| 		if (file.uri != null && file.userHost != null && config.mediaProxy != null) { | ||||
| 			return appendQuery(config.mediaProxy, query({ | ||||
| @@ -62,9 +61,9 @@ export class DriveFileRepository extends Repository<DriveFile> { | ||||
| 		const isImage = file.type && ['image/png', 'image/apng', 'image/gif', 'image/jpeg', 'image/webp', 'image/svg+xml'].includes(file.type); | ||||
|  | ||||
| 		return thumbnail ? (file.thumbnailUrl || (isImage ? (file.webpublicUrl || file.url) : null)) : (file.webpublicUrl || file.url); | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public async calcDriveUsageOf(user: User['id'] | { id: User['id'] }): Promise<number> { | ||||
| 	async calcDriveUsageOf(user: User['id'] | { id: User['id'] }): Promise<number> { | ||||
| 		const id = typeof user === 'object' ? user.id : user; | ||||
|  | ||||
| 		const { sum } = await this | ||||
| @@ -75,9 +74,9 @@ export class DriveFileRepository extends Repository<DriveFile> { | ||||
| 			.getRawOne(); | ||||
|  | ||||
| 		return parseInt(sum, 10) || 0; | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public async calcDriveUsageOfHost(host: string): Promise<number> { | ||||
| 	async calcDriveUsageOfHost(host: string): Promise<number> { | ||||
| 		const { sum } = await this | ||||
| 			.createQueryBuilder('file') | ||||
| 			.where('file.userHost = :host', { host: toPuny(host) }) | ||||
| @@ -86,9 +85,9 @@ export class DriveFileRepository extends Repository<DriveFile> { | ||||
| 			.getRawOne(); | ||||
|  | ||||
| 		return parseInt(sum, 10) || 0; | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public async calcDriveUsageOfLocal(): Promise<number> { | ||||
| 	async calcDriveUsageOfLocal(): Promise<number> { | ||||
| 		const { sum } = await this | ||||
| 			.createQueryBuilder('file') | ||||
| 			.where('file.userHost IS NULL') | ||||
| @@ -97,9 +96,9 @@ export class DriveFileRepository extends Repository<DriveFile> { | ||||
| 			.getRawOne(); | ||||
|  | ||||
| 		return parseInt(sum, 10) || 0; | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public async calcDriveUsageOfRemote(): Promise<number> { | ||||
| 	async calcDriveUsageOfRemote(): Promise<number> { | ||||
| 		const { sum } = await this | ||||
| 			.createQueryBuilder('file') | ||||
| 			.where('file.userHost IS NOT NULL') | ||||
| @@ -108,11 +107,9 @@ export class DriveFileRepository extends Repository<DriveFile> { | ||||
| 			.getRawOne(); | ||||
|  | ||||
| 		return parseInt(sum, 10) || 0; | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public async pack(src: DriveFile['id'], options?: PackOptions): Promise<Packed<'DriveFile'> | null>; | ||||
| 	public async pack(src: DriveFile, options?: PackOptions): Promise<Packed<'DriveFile'>>; | ||||
| 	public async pack( | ||||
| 	async pack( | ||||
| 		src: DriveFile['id'] | DriveFile, | ||||
| 		options?: PackOptions | ||||
| 	): Promise<Packed<'DriveFile'> | null> { | ||||
| @@ -121,11 +118,9 @@ export class DriveFileRepository extends Repository<DriveFile> { | ||||
| 			self: false, | ||||
| 		}, options); | ||||
|  | ||||
| 		const file = typeof src === 'object' ? src : await this.findOne(src); | ||||
| 		const file = typeof src === 'object' ? src : await this.findOneBy({ id: src }); | ||||
| 		if (file == null) return null; | ||||
|  | ||||
| 		const meta = await fetchMeta(); | ||||
|  | ||||
| 		return await awaitAll<Packed<'DriveFile'>>({ | ||||
| 			id: file.id, | ||||
| 			createdAt: file.createdAt.toISOString(), | ||||
| @@ -146,13 +141,13 @@ export class DriveFileRepository extends Repository<DriveFile> { | ||||
| 			userId: opts.withUser ? file.userId : null, | ||||
| 			user: (opts.withUser && file.userId) ? Users.pack(file.userId) : null, | ||||
| 		}); | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public async packMany( | ||||
| 	async packMany( | ||||
| 		files: (DriveFile['id'] | DriveFile)[], | ||||
| 		options?: PackOptions | ||||
| 	) { | ||||
| 		const items = await Promise.all(files.map(f => this.pack(f, options))); | ||||
| 		return items.filter(x => x != null); | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,12 +1,11 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { DriveFolders, DriveFiles } from '../index.js'; | ||||
| import { DriveFolder } from '@/models/entities/drive-folder.js'; | ||||
| import { awaitAll } from '@/prelude/await-all.js'; | ||||
| import { Packed } from '@/misc/schema.js'; | ||||
|  | ||||
| @EntityRepository(DriveFolder) | ||||
| export class DriveFolderRepository extends Repository<DriveFolder> { | ||||
| 	public async pack( | ||||
| export const DriveFolderRepository = db.getRepository(DriveFolder).extend({ | ||||
| 	async pack( | ||||
| 		src: DriveFolder['id'] | DriveFolder, | ||||
| 		options?: { | ||||
| 			detail: boolean | ||||
| @@ -16,7 +15,7 @@ export class DriveFolderRepository extends Repository<DriveFolder> { | ||||
| 			detail: false, | ||||
| 		}, options); | ||||
|  | ||||
| 		const folder = typeof src === 'object' ? src : await this.findOneOrFail(src); | ||||
| 		const folder = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); | ||||
|  | ||||
| 		return await awaitAll({ | ||||
| 			id: folder.id, | ||||
| @@ -25,10 +24,10 @@ export class DriveFolderRepository extends Repository<DriveFolder> { | ||||
| 			parentId: folder.parentId, | ||||
|  | ||||
| 			...(opts.detail ? { | ||||
| 				foldersCount: DriveFolders.count({ | ||||
| 				foldersCount: DriveFolders.countBy({ | ||||
| 					parentId: folder.id, | ||||
| 				}), | ||||
| 				filesCount: DriveFiles.count({ | ||||
| 				filesCount: DriveFiles.countBy({ | ||||
| 					folderId: folder.id, | ||||
| 				}), | ||||
|  | ||||
| @@ -39,5 +38,5 @@ export class DriveFolderRepository extends Repository<DriveFolder> { | ||||
| 				} : {}), | ||||
| 			} : {}), | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,13 +1,12 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { Emoji } from '@/models/entities/emoji.js'; | ||||
| import { Packed } from '@/misc/schema.js'; | ||||
|  | ||||
| @EntityRepository(Emoji) | ||||
| export class EmojiRepository extends Repository<Emoji> { | ||||
| 	public async pack( | ||||
| export const EmojiRepository = db.getRepository(Emoji).extend({ | ||||
| 	async pack( | ||||
| 		src: Emoji['id'] | Emoji, | ||||
| 	): Promise<Packed<'Emoji'>> { | ||||
| 		const emoji = typeof src === 'object' ? src : await this.findOneOrFail(src); | ||||
| 		const emoji = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); | ||||
|  | ||||
| 		return { | ||||
| 			id: emoji.id, | ||||
| @@ -18,11 +17,11 @@ export class EmojiRepository extends Repository<Emoji> { | ||||
| 			// || emoji.originalUrl してるのは後方互換性のため | ||||
| 			url: emoji.publicUrl || emoji.originalUrl, | ||||
| 		}; | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public packMany( | ||||
| 	packMany( | ||||
| 		emojis: any[], | ||||
| 	) { | ||||
| 		return Promise.all(emojis.map(x => this.pack(x))); | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,20 +1,19 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { FollowRequest } from '@/models/entities/follow-request.js'; | ||||
| import { Users } from '../index.js'; | ||||
| import { User } from '@/models/entities/user.js'; | ||||
|  | ||||
| @EntityRepository(FollowRequest) | ||||
| export class FollowRequestRepository extends Repository<FollowRequest> { | ||||
| 	public async pack( | ||||
| export const FollowRequestRepository = db.getRepository(FollowRequest).extend({ | ||||
| 	async pack( | ||||
| 		src: FollowRequest['id'] | FollowRequest, | ||||
| 		me?: { id: User['id'] } | null | undefined | ||||
| 	) { | ||||
| 		const request = typeof src === 'object' ? src : await this.findOneOrFail(src); | ||||
| 		const request = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); | ||||
|  | ||||
| 		return { | ||||
| 			id: request.id, | ||||
| 			follower: await Users.pack(request.followerId, me), | ||||
| 			followee: await Users.pack(request.followeeId, me), | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { Users } from '../index.js'; | ||||
| import { Following } from '@/models/entities/following.js'; | ||||
| import { awaitAll } from '@/prelude/await-all.js'; | ||||
| @@ -29,25 +29,24 @@ type RemoteFolloweeFollowing = Following & { | ||||
| 	followeeSharedInbox: string; | ||||
| }; | ||||
|  | ||||
| @EntityRepository(Following) | ||||
| export class FollowingRepository extends Repository<Following> { | ||||
| 	public isLocalFollower(following: Following): following is LocalFollowerFollowing { | ||||
| export const FollowingRepository = db.getRepository(Following).extend({ | ||||
| 	isLocalFollower(following: Following): following is LocalFollowerFollowing { | ||||
| 		return following.followerHost == null; | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public isRemoteFollower(following: Following): following is RemoteFollowerFollowing { | ||||
| 	isRemoteFollower(following: Following): following is RemoteFollowerFollowing { | ||||
| 		return following.followerHost != null; | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public isLocalFollowee(following: Following): following is LocalFolloweeFollowing { | ||||
| 	isLocalFollowee(following: Following): following is LocalFolloweeFollowing { | ||||
| 		return following.followeeHost == null; | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public isRemoteFollowee(following: Following): following is RemoteFolloweeFollowing { | ||||
| 	isRemoteFollowee(following: Following): following is RemoteFolloweeFollowing { | ||||
| 		return following.followeeHost != null; | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public async pack( | ||||
| 	async pack( | ||||
| 		src: Following['id'] | Following, | ||||
| 		me?: { id: User['id'] } | null | undefined, | ||||
| 		opts?: { | ||||
| @@ -55,7 +54,7 @@ export class FollowingRepository extends Repository<Following> { | ||||
| 			populateFollower?: boolean; | ||||
| 		} | ||||
| 	): Promise<Packed<'Following'>> { | ||||
| 		const following = typeof src === 'object' ? src : await this.findOneOrFail(src); | ||||
| 		const following = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); | ||||
|  | ||||
| 		if (opts == null) opts = {}; | ||||
|  | ||||
| @@ -71,9 +70,9 @@ export class FollowingRepository extends Repository<Following> { | ||||
| 				detail: true, | ||||
| 			}) : undefined, | ||||
| 		}); | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public packMany( | ||||
| 	packMany( | ||||
| 		followings: any[], | ||||
| 		me?: { id: User['id'] } | null | undefined, | ||||
| 		opts?: { | ||||
| @@ -82,5 +81,5 @@ export class FollowingRepository extends Repository<Following> { | ||||
| 		} | ||||
| 	) { | ||||
| 		return Promise.all(followings.map(x => this.pack(x, me, opts))); | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,25 +1,24 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { GalleryLike } from '@/models/entities/gallery-like.js'; | ||||
| import { GalleryPosts } from '../index.js'; | ||||
|  | ||||
| @EntityRepository(GalleryLike) | ||||
| export class GalleryLikeRepository extends Repository<GalleryLike> { | ||||
| 	public async pack( | ||||
| export const GalleryLikeRepository = db.getRepository(GalleryLike).extend({ | ||||
| 	async pack( | ||||
| 		src: GalleryLike['id'] | GalleryLike, | ||||
| 		me?: any | ||||
| 	) { | ||||
| 		const like = typeof src === 'object' ? src : await this.findOneOrFail(src); | ||||
| 		const like = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); | ||||
|  | ||||
| 		return { | ||||
| 			id: like.id, | ||||
| 			post: await GalleryPosts.pack(like.post || like.postId, me), | ||||
| 		}; | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public packMany( | ||||
| 	packMany( | ||||
| 		likes: any[], | ||||
| 		me: any | ||||
| 	) { | ||||
| 		return Promise.all(likes.map(x => this.pack(x, me))); | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,18 +1,17 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { GalleryPost } from '@/models/entities/gallery-post.js'; | ||||
| import { Packed } from '@/misc/schema.js'; | ||||
| import { Users, DriveFiles, GalleryLikes } from '../index.js'; | ||||
| import { awaitAll } from '@/prelude/await-all.js'; | ||||
| import { User } from '@/models/entities/user.js'; | ||||
|  | ||||
| @EntityRepository(GalleryPost) | ||||
| export class GalleryPostRepository extends Repository<GalleryPost> { | ||||
| 	public async pack( | ||||
| export const GalleryPostRepository = db.getRepository(GalleryPost).extend({ | ||||
| 	async pack( | ||||
| 		src: GalleryPost['id'] | GalleryPost, | ||||
| 		me?: { id: User['id'] } | null | undefined, | ||||
| 	): Promise<Packed<'GalleryPost'>> { | ||||
| 		const meId = me ? me.id : null; | ||||
| 		const post = typeof src === 'object' ? src : await this.findOneOrFail(src); | ||||
| 		const post = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); | ||||
|  | ||||
| 		return await awaitAll({ | ||||
| 			id: post.id, | ||||
| @@ -27,14 +26,14 @@ export class GalleryPostRepository extends Repository<GalleryPost> { | ||||
| 			tags: post.tags.length > 0 ? post.tags : undefined, | ||||
| 			isSensitive: post.isSensitive, | ||||
| 			likedCount: post.likedCount, | ||||
| 			isLiked: meId ? await GalleryLikes.findOne({ postId: post.id, userId: meId }).then(x => x != null) : undefined, | ||||
| 			isLiked: meId ? await GalleryLikes.findOneBy({ postId: post.id, userId: meId }).then(x => x != null) : undefined, | ||||
| 		}); | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public packMany( | ||||
| 	packMany( | ||||
| 		posts: GalleryPost[], | ||||
| 		me?: { id: User['id'] } | null | undefined, | ||||
| 	) { | ||||
| 		return Promise.all(posts.map(x => this.pack(x, me))); | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,10 +1,9 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { Hashtag } from '@/models/entities/hashtag.js'; | ||||
| import { Packed } from '@/misc/schema.js'; | ||||
|  | ||||
| @EntityRepository(Hashtag) | ||||
| export class HashtagRepository extends Repository<Hashtag> { | ||||
| 	public async pack( | ||||
| export const HashtagRepository = db.getRepository(Hashtag).extend({ | ||||
| 	async pack( | ||||
| 		src: Hashtag, | ||||
| 	): Promise<Packed<'Hashtag'>> { | ||||
| 		return { | ||||
| @@ -16,11 +15,11 @@ export class HashtagRepository extends Repository<Hashtag> { | ||||
| 			attachedLocalUsersCount: src.attachedLocalUsersCount, | ||||
| 			attachedRemoteUsersCount: src.attachedRemoteUsersCount, | ||||
| 		}; | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public packMany( | ||||
| 	packMany( | ||||
| 		hashtags: Hashtag[], | ||||
| 	) { | ||||
| 		return Promise.all(hashtags.map(x => this.pack(x))); | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,10 +1,9 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { Instance } from '@/models/entities/instance.js'; | ||||
| import { Packed } from '@/misc/schema.js'; | ||||
|  | ||||
| @EntityRepository(Instance) | ||||
| export class InstanceRepository extends Repository<Instance> { | ||||
| 	public async pack( | ||||
| export const InstanceRepository = db.getRepository(Instance).extend({ | ||||
| 	async pack( | ||||
| 		instance: Instance, | ||||
| 	): Promise<Packed<'FederationInstance'>> { | ||||
| 		return { | ||||
| @@ -29,11 +28,11 @@ export class InstanceRepository extends Repository<Instance> { | ||||
| 			iconUrl: instance.iconUrl, | ||||
| 			infoUpdatedAt: instance.infoUpdatedAt ? instance.infoUpdatedAt.toISOString() : null, | ||||
| 		}; | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public packMany( | ||||
| 	packMany( | ||||
| 		instances: Instance[], | ||||
| 	) { | ||||
| 		return Promise.all(instances.map(x => this.pack(x))); | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,12 +1,11 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { MessagingMessage } from '@/models/entities/messaging-message.js'; | ||||
| import { Users, DriveFiles, UserGroups } from '../index.js'; | ||||
| import { Packed } from '@/misc/schema.js'; | ||||
| import { User } from '@/models/entities/user.js'; | ||||
|  | ||||
| @EntityRepository(MessagingMessage) | ||||
| export class MessagingMessageRepository extends Repository<MessagingMessage> { | ||||
| 	public async pack( | ||||
| export const MessagingMessageRepository = db.getRepository(MessagingMessage).extend({ | ||||
| 	async pack( | ||||
| 		src: MessagingMessage['id'] | MessagingMessage, | ||||
| 		me?: { id: User['id'] } | null | undefined, | ||||
| 		options?: { | ||||
| @@ -19,7 +18,7 @@ export class MessagingMessageRepository extends Repository<MessagingMessage> { | ||||
| 			populateGroup: true, | ||||
| 		}; | ||||
|  | ||||
| 		const message = typeof src === 'object' ? src : await this.findOneOrFail(src); | ||||
| 		const message = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); | ||||
|  | ||||
| 		return { | ||||
| 			id: message.id, | ||||
| @@ -36,5 +35,5 @@ export class MessagingMessageRepository extends Repository<MessagingMessage> { | ||||
| 			isRead: message.isRead, | ||||
| 			reads: message.reads, | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,14 +1,13 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { Users } from '../index.js'; | ||||
| import { ModerationLog } from '@/models/entities/moderation-log.js'; | ||||
| import { awaitAll } from '@/prelude/await-all.js'; | ||||
|  | ||||
| @EntityRepository(ModerationLog) | ||||
| export class ModerationLogRepository extends Repository<ModerationLog> { | ||||
| 	public async pack( | ||||
| export const ModerationLogRepository = db.getRepository(ModerationLog).extend({ | ||||
| 	async pack( | ||||
| 		src: ModerationLog['id'] | ModerationLog, | ||||
| 	) { | ||||
| 		const log = typeof src === 'object' ? src : await this.findOneOrFail(src); | ||||
| 		const log = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); | ||||
|  | ||||
| 		return await awaitAll({ | ||||
| 			id: log.id, | ||||
| @@ -20,11 +19,11 @@ export class ModerationLogRepository extends Repository<ModerationLog> { | ||||
| 				detail: true, | ||||
| 			}), | ||||
| 		}); | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public packMany( | ||||
| 	packMany( | ||||
| 		reports: any[], | ||||
| 	) { | ||||
| 		return Promise.all(reports.map(x => this.pack(x))); | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,17 +1,16 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { Users } from '../index.js'; | ||||
| import { Muting } from '@/models/entities/muting.js'; | ||||
| import { awaitAll } from '@/prelude/await-all.js'; | ||||
| import { Packed } from '@/misc/schema.js'; | ||||
| import { User } from '@/models/entities/user.js'; | ||||
|  | ||||
| @EntityRepository(Muting) | ||||
| export class MutingRepository extends Repository<Muting> { | ||||
| 	public async pack( | ||||
| export const MutingRepository = db.getRepository(Muting).extend({ | ||||
| 	async pack( | ||||
| 		src: Muting['id'] | Muting, | ||||
| 		me?: { id: User['id'] } | null | undefined | ||||
| 	): Promise<Packed<'Muting'>> { | ||||
| 		const muting = typeof src === 'object' ? src : await this.findOneOrFail(src); | ||||
| 		const muting = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); | ||||
|  | ||||
| 		return await awaitAll({ | ||||
| 			id: muting.id, | ||||
| @@ -22,12 +21,12 @@ export class MutingRepository extends Repository<Muting> { | ||||
| 				detail: true, | ||||
| 			}), | ||||
| 		}); | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public packMany( | ||||
| 	packMany( | ||||
| 		mutings: any[], | ||||
| 		me: { id: User['id'] } | ||||
| 	) { | ||||
| 		return Promise.all(mutings.map(x => this.pack(x, me))); | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,15 +1,14 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { NoteFavorite } from '@/models/entities/note-favorite.js'; | ||||
| import { Notes } from '../index.js'; | ||||
| import { User } from '@/models/entities/user.js'; | ||||
|  | ||||
| @EntityRepository(NoteFavorite) | ||||
| export class NoteFavoriteRepository extends Repository<NoteFavorite> { | ||||
| 	public async pack( | ||||
| export const NoteFavoriteRepository = db.getRepository(NoteFavorite).extend({ | ||||
| 	async pack( | ||||
| 		src: NoteFavorite['id'] | NoteFavorite, | ||||
| 		me?: { id: User['id'] } | null | undefined | ||||
| 	) { | ||||
| 		const favorite = typeof src === 'object' ? src : await this.findOneOrFail(src); | ||||
| 		const favorite = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); | ||||
|  | ||||
| 		return { | ||||
| 			id: favorite.id, | ||||
| @@ -17,12 +16,12 @@ export class NoteFavoriteRepository extends Repository<NoteFavorite> { | ||||
| 			noteId: favorite.noteId, | ||||
| 			note: await Notes.pack(favorite.note || favorite.noteId, me), | ||||
| 		}; | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public packMany( | ||||
| 	packMany( | ||||
| 		favorites: any[], | ||||
| 		me: { id: User['id'] } | ||||
| 	) { | ||||
| 		return Promise.all(favorites.map(x => this.pack(x, me))); | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,13 +1,12 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { NoteReaction } from '@/models/entities/note-reaction.js'; | ||||
| import { Notes, Users } from '../index.js'; | ||||
| import { Packed } from '@/misc/schema.js'; | ||||
| import { convertLegacyReaction } from '@/misc/reaction-lib.js'; | ||||
| import { User } from '@/models/entities/user.js'; | ||||
|  | ||||
| @EntityRepository(NoteReaction) | ||||
| export class NoteReactionRepository extends Repository<NoteReaction> { | ||||
| 	public async pack( | ||||
| export const NoteReactionRepository = db.getRepository(NoteReaction).extend({ | ||||
| 	async pack( | ||||
| 		src: NoteReaction['id'] | NoteReaction, | ||||
| 		me?: { id: User['id'] } | null | undefined, | ||||
| 		options?: { | ||||
| @@ -18,7 +17,7 @@ export class NoteReactionRepository extends Repository<NoteReaction> { | ||||
| 			withNote: false, | ||||
| 		}, options); | ||||
|  | ||||
| 		const reaction = typeof src === 'object' ? src : await this.findOneOrFail(src); | ||||
| 		const reaction = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); | ||||
|  | ||||
| 		return { | ||||
| 			id: reaction.id, | ||||
| @@ -29,5 +28,5 @@ export class NoteReactionRepository extends Repository<NoteReaction> { | ||||
| 				note: await Notes.pack(reaction.note ?? reaction.noteId, me), | ||||
| 			} : {}), | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| import { EntityRepository, Repository, In } from 'typeorm'; | ||||
| import { In } from 'typeorm'; | ||||
| import * as mfm from 'mfm-js'; | ||||
| import { Note } from '@/models/entities/note.js'; | ||||
| import { User } from '@/models/entities/user.js'; | ||||
| @@ -9,10 +9,70 @@ import { awaitAll } from '@/prelude/await-all.js'; | ||||
| import { convertLegacyReaction, convertLegacyReactions, decodeReaction } from '@/misc/reaction-lib.js'; | ||||
| import { NoteReaction } from '@/models/entities/note-reaction.js'; | ||||
| import { aggregateNoteEmojis, populateEmojis, prefetchEmojis } from '@/misc/populate-emojis.js'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
|  | ||||
| @EntityRepository(Note) | ||||
| export class NoteRepository extends Repository<Note> { | ||||
| 	public async isVisibleForMe(note: Note, meId: User['id'] | null): Promise<boolean> { | ||||
| async function hideNote(packedNote: Packed<'Note'>, meId: User['id'] | null) { | ||||
| 	// TODO: isVisibleForMe を使うようにしても良さそう(型違うけど) | ||||
| 	let hide = false; | ||||
|  | ||||
| 	// visibility が specified かつ自分が指定されていなかったら非表示 | ||||
| 	if (packedNote.visibility === 'specified') { | ||||
| 		if (meId == null) { | ||||
| 			hide = true; | ||||
| 		} else if (meId === packedNote.userId) { | ||||
| 			hide = false; | ||||
| 		} else { | ||||
| 			// 指定されているかどうか | ||||
| 			const specified = packedNote.visibleUserIds!.some((id: any) => meId === id); | ||||
|  | ||||
| 			if (specified) { | ||||
| 				hide = false; | ||||
| 			} else { | ||||
| 				hide = true; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// visibility が followers かつ自分が投稿者のフォロワーでなかったら非表示 | ||||
| 	if (packedNote.visibility === 'followers') { | ||||
| 		if (meId == null) { | ||||
| 			hide = true; | ||||
| 		} else if (meId === packedNote.userId) { | ||||
| 			hide = false; | ||||
| 		} else if (packedNote.reply && (meId === packedNote.reply.userId)) { | ||||
| 			// 自分の投稿に対するリプライ | ||||
| 			hide = false; | ||||
| 		} else if (packedNote.mentions && packedNote.mentions.some(id => meId === id)) { | ||||
| 			// 自分へのメンション | ||||
| 			hide = false; | ||||
| 		} else { | ||||
| 			// フォロワーかどうか | ||||
| 			const following = await Followings.findOneBy({ | ||||
| 				followeeId: packedNote.userId, | ||||
| 				followerId: meId, | ||||
| 			}); | ||||
|  | ||||
| 			if (following == null) { | ||||
| 				hide = true; | ||||
| 			} else { | ||||
| 				hide = false; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (hide) { | ||||
| 		packedNote.visibleUserIds = undefined; | ||||
| 		packedNote.fileIds = []; | ||||
| 		packedNote.files = []; | ||||
| 		packedNote.text = null; | ||||
| 		packedNote.poll = undefined; | ||||
| 		packedNote.cw = null; | ||||
| 		packedNote.isHidden = true; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export const NoteRepository = db.getRepository(Note).extend({ | ||||
| 	async isVisibleForMe(note: Note, meId: User['id'] | null): Promise<boolean> { | ||||
| 		// visibility が specified かつ自分が指定されていなかったら非表示 | ||||
| 		if (note.visibility === 'specified') { | ||||
| 			if (meId == null) { | ||||
| @@ -45,7 +105,7 @@ export class NoteRepository extends Repository<Note> { | ||||
| 				return true; | ||||
| 			} else { | ||||
| 				// フォロワーかどうか | ||||
| 				const following = await Followings.findOne({ | ||||
| 				const following = await Followings.findOneBy({ | ||||
| 					followeeId: note.userId, | ||||
| 					followerId: meId, | ||||
| 				}); | ||||
| @@ -59,69 +119,9 @@ export class NoteRepository extends Repository<Note> { | ||||
| 		} | ||||
|  | ||||
| 		return true; | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	private async hideNote(packedNote: Packed<'Note'>, meId: User['id'] | null) { | ||||
| 		// TODO: isVisibleForMe を使うようにしても良さそう(型違うけど) | ||||
| 		let hide = false; | ||||
|  | ||||
| 		// visibility が specified かつ自分が指定されていなかったら非表示 | ||||
| 		if (packedNote.visibility === 'specified') { | ||||
| 			if (meId == null) { | ||||
| 				hide = true; | ||||
| 			} else if (meId === packedNote.userId) { | ||||
| 				hide = false; | ||||
| 			} else { | ||||
| 				// 指定されているかどうか | ||||
| 				const specified = packedNote.visibleUserIds!.some((id: any) => meId === id); | ||||
|  | ||||
| 				if (specified) { | ||||
| 					hide = false; | ||||
| 				} else { | ||||
| 					hide = true; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// visibility が followers かつ自分が投稿者のフォロワーでなかったら非表示 | ||||
| 		if (packedNote.visibility === 'followers') { | ||||
| 			if (meId == null) { | ||||
| 				hide = true; | ||||
| 			} else if (meId === packedNote.userId) { | ||||
| 				hide = false; | ||||
| 			} else if (packedNote.reply && (meId === packedNote.reply.userId)) { | ||||
| 				// 自分の投稿に対するリプライ | ||||
| 				hide = false; | ||||
| 			} else if (packedNote.mentions && packedNote.mentions.some(id => meId === id)) { | ||||
| 				// 自分へのメンション | ||||
| 				hide = false; | ||||
| 			} else { | ||||
| 				// フォロワーかどうか | ||||
| 				const following = await Followings.findOne({ | ||||
| 					followeeId: packedNote.userId, | ||||
| 					followerId: meId, | ||||
| 				}); | ||||
|  | ||||
| 				if (following == null) { | ||||
| 					hide = true; | ||||
| 				} else { | ||||
| 					hide = false; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if (hide) { | ||||
| 			packedNote.visibleUserIds = undefined; | ||||
| 			packedNote.fileIds = []; | ||||
| 			packedNote.files = []; | ||||
| 			packedNote.text = null; | ||||
| 			packedNote.poll = undefined; | ||||
| 			packedNote.cw = null; | ||||
| 			packedNote.isHidden = true; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public async pack( | ||||
| 	async pack( | ||||
| 		src: Note['id'] | Note, | ||||
| 		me?: { id: User['id'] } | null | undefined, | ||||
| 		options?: { | ||||
| @@ -138,11 +138,11 @@ export class NoteRepository extends Repository<Note> { | ||||
| 		}, options); | ||||
|  | ||||
| 		const meId = me ? me.id : null; | ||||
| 		const note = typeof src === 'object' ? src : await this.findOneOrFail(src); | ||||
| 		const note = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); | ||||
| 		const host = note.userHost; | ||||
|  | ||||
| 		async function populatePoll() { | ||||
| 			const poll = await Polls.findOneOrFail(note.id); | ||||
| 			const poll = await Polls.findOneByOrFail({ noteId: note.id }); | ||||
| 			const choices = poll.choices.map(c => ({ | ||||
| 				text: c, | ||||
| 				votes: poll.votes[poll.choices.indexOf(c)], | ||||
| @@ -150,7 +150,7 @@ export class NoteRepository extends Repository<Note> { | ||||
| 			})); | ||||
|  | ||||
| 			if (poll.multiple) { | ||||
| 				const votes = await PollVotes.find({ | ||||
| 				const votes = await PollVotes.findBy({ | ||||
| 					userId: meId!, | ||||
| 					noteId: note.id, | ||||
| 				}); | ||||
| @@ -160,7 +160,7 @@ export class NoteRepository extends Repository<Note> { | ||||
| 					choices[myChoice].isVoted = true; | ||||
| 				} | ||||
| 			} else { | ||||
| 				const vote = await PollVotes.findOne({ | ||||
| 				const vote = await PollVotes.findOneBy({ | ||||
| 					userId: meId!, | ||||
| 					noteId: note.id, | ||||
| 				}); | ||||
| @@ -188,7 +188,7 @@ export class NoteRepository extends Repository<Note> { | ||||
| 				// 実装上抜けがあるだけかもしれないので、「ヒントに含まれてなかったら(=undefinedなら)return」のようにはしない | ||||
| 			} | ||||
|  | ||||
| 			const reaction = await NoteReactions.findOne({ | ||||
| 			const reaction = await NoteReactions.findOneBy({ | ||||
| 				userId: meId!, | ||||
| 				noteId: note.id, | ||||
| 			}); | ||||
| @@ -209,7 +209,7 @@ export class NoteRepository extends Repository<Note> { | ||||
| 		const channel = note.channelId | ||||
| 			? note.channel | ||||
| 				? note.channel | ||||
| 				: await Channels.findOne(note.channelId) | ||||
| 				: await Channels.findOneBy({ id: note.channelId }) | ||||
| 			: null; | ||||
|  | ||||
| 		const reactionEmojiNames = Object.keys(note.reactions).filter(x => x?.startsWith(':')).map(x => decodeReaction(x).reaction).map(x => x.replace(/:/g, '')); | ||||
| @@ -275,13 +275,13 @@ export class NoteRepository extends Repository<Note> { | ||||
| 		} | ||||
|  | ||||
| 		if (!opts.skipHide) { | ||||
| 			await this.hideNote(packed, meId); | ||||
| 			await hideNote(packed, meId); | ||||
| 		} | ||||
|  | ||||
| 		return packed; | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public async packMany( | ||||
| 	async packMany( | ||||
| 		notes: Note[], | ||||
| 		me?: { id: User['id'] } | null | undefined, | ||||
| 		options?: { | ||||
| @@ -296,7 +296,7 @@ export class NoteRepository extends Repository<Note> { | ||||
| 		if (meId) { | ||||
| 			const renoteIds = notes.filter(n => n.renoteId != null).map(n => n.renoteId!); | ||||
| 			const targets = [...notes.map(n => n.id), ...renoteIds]; | ||||
| 			const myReactions = await NoteReactions.find({ | ||||
| 			const myReactions = await NoteReactions.findBy({ | ||||
| 				userId: meId, | ||||
| 				noteId: In(targets), | ||||
| 			}); | ||||
| @@ -314,5 +314,5 @@ export class NoteRepository extends Repository<Note> { | ||||
| 				myReactions: myReactionsMap, | ||||
| 			}, | ||||
| 		}))); | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| import { EntityRepository, In, Repository } from 'typeorm'; | ||||
| import { In, Repository } from 'typeorm'; | ||||
| import { Users, Notes, UserGroupInvitations, AccessTokens, NoteReactions } from '../index.js'; | ||||
| import { Notification } from '@/models/entities/notification.js'; | ||||
| import { awaitAll } from '@/prelude/await-all.js'; | ||||
| @@ -8,10 +8,10 @@ import { NoteReaction } from '@/models/entities/note-reaction.js'; | ||||
| import { User } from '@/models/entities/user.js'; | ||||
| import { aggregateNoteEmojis, prefetchEmojis } from '@/misc/populate-emojis.js'; | ||||
| import { notificationTypes } from '@/types.js'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
|  | ||||
| @EntityRepository(Notification) | ||||
| export class NotificationRepository extends Repository<Notification> { | ||||
| 	public async pack( | ||||
| export const NotificationRepository = db.getRepository(Notification).extend({ | ||||
| 	async pack( | ||||
| 		src: Notification['id'] | Notification, | ||||
| 		options: { | ||||
| 			_hintForEachNotes_?: { | ||||
| @@ -19,8 +19,8 @@ export class NotificationRepository extends Repository<Notification> { | ||||
| 			}; | ||||
| 		} | ||||
| 	): Promise<Packed<'Notification'>> { | ||||
| 		const notification = typeof src === 'object' ? src : await this.findOneOrFail(src); | ||||
| 		const token = notification.appAccessTokenId ? await AccessTokens.findOneOrFail(notification.appAccessTokenId) : null; | ||||
| 		const notification = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); | ||||
| 		const token = notification.appAccessTokenId ? await AccessTokens.findOneByOrFail({ id: notification.appAccessTokenId }) : null; | ||||
|  | ||||
| 		return await awaitAll({ | ||||
| 			id: notification.id, | ||||
| @@ -82,9 +82,9 @@ export class NotificationRepository extends Repository<Notification> { | ||||
| 				icon: notification.customIcon || token?.iconUrl, | ||||
| 			} : {}), | ||||
| 		}); | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public async packMany( | ||||
| 	async packMany( | ||||
| 		notifications: Notification[], | ||||
| 		meId: User['id'] | ||||
| 	) { | ||||
| @@ -95,7 +95,7 @@ export class NotificationRepository extends Repository<Notification> { | ||||
| 		const myReactionsMap = new Map<Note['id'], NoteReaction | null>(); | ||||
| 		const renoteIds = notes.filter(n => n.renoteId != null).map(n => n.renoteId!); | ||||
| 		const targets = [...noteIds, ...renoteIds]; | ||||
| 		const myReactions = await NoteReactions.find({ | ||||
| 		const myReactions = await NoteReactions.findBy({ | ||||
| 			userId: meId, | ||||
| 			noteId: In(targets), | ||||
| 		}); | ||||
| @@ -111,5 +111,5 @@ export class NotificationRepository extends Repository<Notification> { | ||||
| 				myReactions: myReactionsMap, | ||||
| 			}, | ||||
| 		}))); | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,26 +1,25 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { PageLike } from '@/models/entities/page-like.js'; | ||||
| import { Pages } from '../index.js'; | ||||
| import { User } from '@/models/entities/user.js'; | ||||
|  | ||||
| @EntityRepository(PageLike) | ||||
| export class PageLikeRepository extends Repository<PageLike> { | ||||
| 	public async pack( | ||||
| export const PageLikeRepository = db.getRepository(PageLike).extend({ | ||||
| 	async pack( | ||||
| 		src: PageLike['id'] | PageLike, | ||||
| 		me?: { id: User['id'] } | null | undefined | ||||
| 	) { | ||||
| 		const like = typeof src === 'object' ? src : await this.findOneOrFail(src); | ||||
| 		const like = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); | ||||
|  | ||||
| 		return { | ||||
| 			id: like.id, | ||||
| 			page: await Pages.pack(like.page || like.pageId, me), | ||||
| 		}; | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public packMany( | ||||
| 	packMany( | ||||
| 		likes: any[], | ||||
| 		me: { id: User['id'] } | ||||
| 	) { | ||||
| 		return Promise.all(likes.map(x => this.pack(x, me))); | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { Page } from '@/models/entities/page.js'; | ||||
| import { Packed } from '@/misc/schema.js'; | ||||
| import { Users, DriveFiles, PageLikes } from '../index.js'; | ||||
| @@ -6,20 +6,19 @@ import { awaitAll } from '@/prelude/await-all.js'; | ||||
| import { DriveFile } from '@/models/entities/drive-file.js'; | ||||
| import { User } from '@/models/entities/user.js'; | ||||
|  | ||||
| @EntityRepository(Page) | ||||
| export class PageRepository extends Repository<Page> { | ||||
| 	public async pack( | ||||
| export const PageRepository = db.getRepository(Page).extend({ | ||||
| 	async pack( | ||||
| 		src: Page['id'] | Page, | ||||
| 		me?: { id: User['id'] } | null | undefined, | ||||
| 	): Promise<Packed<'Page'>> { | ||||
| 		const meId = me ? me.id : null; | ||||
| 		const page = typeof src === 'object' ? src : await this.findOneOrFail(src); | ||||
| 		const page = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); | ||||
|  | ||||
| 		const attachedFiles: Promise<DriveFile | undefined>[] = []; | ||||
| 		const collectFile = (xs: any[]) => { | ||||
| 			for (const x of xs) { | ||||
| 				if (x.type === 'image') { | ||||
| 					attachedFiles.push(DriveFiles.findOne({ | ||||
| 					attachedFiles.push(DriveFiles.findOneBy({ | ||||
| 						id: x.fileId, | ||||
| 						userId: page.userId, | ||||
| 					})); | ||||
| @@ -76,14 +75,14 @@ export class PageRepository extends Repository<Page> { | ||||
| 			eyeCatchingImage: page.eyeCatchingImageId ? await DriveFiles.pack(page.eyeCatchingImageId) : null, | ||||
| 			attachedFiles: DriveFiles.packMany(await Promise.all(attachedFiles)), | ||||
| 			likedCount: page.likedCount, | ||||
| 			isLiked: meId ? await PageLikes.findOne({ pageId: page.id, userId: meId }).then(x => x != null) : undefined, | ||||
| 			isLiked: meId ? await PageLikes.findOneBy({ pageId: page.id, userId: meId }).then(x => x != null) : undefined, | ||||
| 		}); | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public packMany( | ||||
| 	packMany( | ||||
| 		pages: Page[], | ||||
| 		me?: { id: User['id'] } | null | undefined, | ||||
| 	) { | ||||
| 		return Promise.all(pages.map(x => this.pack(x, me))); | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,6 +1,5 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { Relay } from '@/models/entities/relay.js'; | ||||
|  | ||||
| @EntityRepository(Relay) | ||||
| export class RelayRepository extends Repository<Relay> { | ||||
| } | ||||
| export const RelayRepository = db.getRepository(Relay).extend({ | ||||
| }); | ||||
|   | ||||
| @@ -1,11 +1,10 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { Signin } from '@/models/entities/signin.js'; | ||||
|  | ||||
| @EntityRepository(Signin) | ||||
| export class SigninRepository extends Repository<Signin> { | ||||
| 	public async pack( | ||||
| export const SigninRepository = db.getRepository(Signin).extend({ | ||||
| 	async pack( | ||||
| 		src: Signin, | ||||
| 	) { | ||||
| 		return src; | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,23 +1,22 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { UserGroupInvitation } from '@/models/entities/user-group-invitation.js'; | ||||
| import { UserGroups } from '../index.js'; | ||||
|  | ||||
| @EntityRepository(UserGroupInvitation) | ||||
| export class UserGroupInvitationRepository extends Repository<UserGroupInvitation> { | ||||
| 	public async pack( | ||||
| export const UserGroupInvitationRepository = db.getRepository(UserGroupInvitation).extend({ | ||||
| 	async pack( | ||||
| 		src: UserGroupInvitation['id'] | UserGroupInvitation, | ||||
| 	) { | ||||
| 		const invitation = typeof src === 'object' ? src : await this.findOneOrFail(src); | ||||
| 		const invitation = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); | ||||
|  | ||||
| 		return { | ||||
| 			id: invitation.id, | ||||
| 			group: await UserGroups.pack(invitation.userGroup || invitation.userGroupId), | ||||
| 		}; | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public packMany( | ||||
| 	packMany( | ||||
| 		invitations: any[], | ||||
| 	) { | ||||
| 		return Promise.all(invitations.map(x => this.pack(x))); | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,16 +1,15 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { UserGroup } from '@/models/entities/user-group.js'; | ||||
| import { UserGroupJoinings } from '../index.js'; | ||||
| import { Packed } from '@/misc/schema.js'; | ||||
|  | ||||
| @EntityRepository(UserGroup) | ||||
| export class UserGroupRepository extends Repository<UserGroup> { | ||||
| 	public async pack( | ||||
| export const UserGroupRepository = db.getRepository(UserGroup).extend({ | ||||
| 	async pack( | ||||
| 		src: UserGroup['id'] | UserGroup, | ||||
| 	): Promise<Packed<'UserGroup'>> { | ||||
| 		const userGroup = typeof src === 'object' ? src : await this.findOneOrFail(src); | ||||
| 		const userGroup = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); | ||||
|  | ||||
| 		const users = await UserGroupJoinings.find({ | ||||
| 		const users = await UserGroupJoinings.findBy({ | ||||
| 			userGroupId: userGroup.id, | ||||
| 		}); | ||||
|  | ||||
| @@ -21,5 +20,5 @@ export class UserGroupRepository extends Repository<UserGroup> { | ||||
| 			ownerId: userGroup.userId, | ||||
| 			userIds: users.map(x => x.userId), | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -1,16 +1,15 @@ | ||||
| import { EntityRepository, Repository } from 'typeorm'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
| import { UserList } from '@/models/entities/user-list.js'; | ||||
| import { UserListJoinings } from '../index.js'; | ||||
| import { Packed } from '@/misc/schema.js'; | ||||
|  | ||||
| @EntityRepository(UserList) | ||||
| export class UserListRepository extends Repository<UserList> { | ||||
| 	public async pack( | ||||
| export const UserListRepository = db.getRepository(UserList).extend({ | ||||
| 	async pack( | ||||
| 		src: UserList['id'] | UserList, | ||||
| 	): Promise<Packed<'UserList'>> { | ||||
| 		const userList = typeof src === 'object' ? src : await this.findOneOrFail(src); | ||||
| 		const userList = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); | ||||
|  | ||||
| 		const users = await UserListJoinings.find({ | ||||
| 		const users = await UserListJoinings.findBy({ | ||||
| 			userListId: userList.id, | ||||
| 		}); | ||||
|  | ||||
| @@ -20,5 +19,5 @@ export class UserListRepository extends Repository<UserList> { | ||||
| 			name: userList.name, | ||||
| 			userIds: users.map(x => x.userId), | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
| 	}, | ||||
| }); | ||||
|   | ||||
| @@ -10,6 +10,7 @@ import { getAntennas } from '@/misc/antenna-cache.js'; | ||||
| import { USER_ACTIVE_THRESHOLD, USER_ONLINE_THRESHOLD } from '@/const.js'; | ||||
| import { Cache } from '@/misc/cache.js'; | ||||
| import { Instance } from '../entities/instance.js'; | ||||
| import { db } from '@/db/postgre.js'; | ||||
|  | ||||
| const userInstanceCache = new Cache<Instance | null>(1000 * 60 * 60 * 3); | ||||
|  | ||||
| @@ -23,51 +24,69 @@ type IsMeAndIsUserDetailed<ExpectsMe extends boolean | null, Detailed extends bo | ||||
|  | ||||
| const ajv = new Ajv(); | ||||
|  | ||||
| @EntityRepository(User) | ||||
| export class UserRepository extends Repository<User> { | ||||
| 	public localUsernameSchema = { type: 'string', pattern: /^\w{1,20}$/.toString().slice(1, -1) } as const; | ||||
| 	public passwordSchema = { type: 'string', minLength: 1 } as const; | ||||
| 	public nameSchema = { type: 'string', minLength: 1, maxLength: 50 } as const; | ||||
| 	public descriptionSchema = { type: 'string', minLength: 1, maxLength: 500 } as const; | ||||
| 	public locationSchema = { type: 'string', minLength: 1, maxLength: 50 } as const; | ||||
| 	public birthdaySchema = { type: 'string', pattern: /^([0-9]{4})-([0-9]{2})-([0-9]{2})$/.toString().slice(1, -1) } as const; | ||||
| const localUsernameSchema = { type: 'string', pattern: /^\w{1,20}$/.toString().slice(1, -1) } as const; | ||||
| const passwordSchema = { type: 'string', minLength: 1 } as const; | ||||
| const nameSchema = { type: 'string', minLength: 1, maxLength: 50 } as const; | ||||
| const descriptionSchema = { type: 'string', minLength: 1, maxLength: 500 } as const; | ||||
| const locationSchema = { type: 'string', minLength: 1, maxLength: 50 } as const; | ||||
| const birthdaySchema = { type: 'string', pattern: /^([0-9]{4})-([0-9]{2})-([0-9]{2})$/.toString().slice(1, -1) } as const; | ||||
|  | ||||
| function isLocalUser(user: User): user is ILocalUser; | ||||
| function isLocalUser<T extends { host: User['host'] }>(user: T): user is T & { host: null; }; | ||||
| function isLocalUser(user: User | { host: User['host'] }): boolean { | ||||
| 	return user.host == null; | ||||
| } | ||||
|  | ||||
| function isRemoteUser(user: User): user is IRemoteUser; | ||||
| function isRemoteUser<T extends { host: User['host'] }>(user: T): user is T & { host: string; }; | ||||
| function isRemoteUser(user: User | { host: User['host'] }): boolean { | ||||
| 	return !isLocalUser(user); | ||||
| } | ||||
|  | ||||
| export const UserRepository = db.getRepository(User).extend({ | ||||
| 	localUsernameSchema, | ||||
| 	passwordSchema, | ||||
| 	nameSchema, | ||||
| 	descriptionSchema, | ||||
| 	locationSchema, | ||||
| 	birthdaySchema, | ||||
|  | ||||
| 	//#region Validators | ||||
| 	public validateLocalUsername = ajv.compile(this.localUsernameSchema); | ||||
| 	public validatePassword = ajv.compile(this.passwordSchema); | ||||
| 	public validateName = ajv.compile(this.nameSchema); | ||||
| 	public validateDescription = ajv.compile(this.descriptionSchema); | ||||
| 	public validateLocation = ajv.compile(this.locationSchema); | ||||
| 	public validateBirthday = ajv.compile(this.birthdaySchema); | ||||
| 	validateLocalUsername: ajv.compile(localUsernameSchema), | ||||
| 	validatePassword: ajv.compile(passwordSchema), | ||||
| 	validateName: ajv.compile(nameSchema), | ||||
| 	validateDescription: ajv.compile(descriptionSchema), | ||||
| 	validateLocation: ajv.compile(locationSchema), | ||||
| 	validateBirthday: ajv.compile(birthdaySchema), | ||||
| 	//#endregion | ||||
|  | ||||
| 	public async getRelation(me: User['id'], target: User['id']) { | ||||
| 	async getRelation(me: User['id'], target: User['id']) { | ||||
| 		const [following1, following2, followReq1, followReq2, toBlocking, fromBlocked, mute] = await Promise.all([ | ||||
| 			Followings.findOne({ | ||||
| 			Followings.findOneBy({ | ||||
| 				followerId: me, | ||||
| 				followeeId: target, | ||||
| 			}), | ||||
| 			Followings.findOne({ | ||||
| 			Followings.findOneBy({ | ||||
| 				followerId: target, | ||||
| 				followeeId: me, | ||||
| 			}), | ||||
| 			FollowRequests.findOne({ | ||||
| 			FollowRequests.findOneBy({ | ||||
| 				followerId: me, | ||||
| 				followeeId: target, | ||||
| 			}), | ||||
| 			FollowRequests.findOne({ | ||||
| 			FollowRequests.findOneBy({ | ||||
| 				followerId: target, | ||||
| 				followeeId: me, | ||||
| 			}), | ||||
| 			Blockings.findOne({ | ||||
| 			Blockings.findOneBy({ | ||||
| 				blockerId: me, | ||||
| 				blockeeId: target, | ||||
| 			}), | ||||
| 			Blockings.findOne({ | ||||
| 			Blockings.findOneBy({ | ||||
| 				blockerId: target, | ||||
| 				blockeeId: me, | ||||
| 			}), | ||||
| 			Mutings.findOne({ | ||||
| 			Mutings.findOneBy({ | ||||
| 				muterId: me, | ||||
| 				muteeId: target, | ||||
| 			}), | ||||
| @@ -83,14 +102,14 @@ export class UserRepository extends Repository<User> { | ||||
| 			isBlocked: fromBlocked != null, | ||||
| 			isMuted: mute != null, | ||||
| 		}; | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public async getHasUnreadMessagingMessage(userId: User['id']): Promise<boolean> { | ||||
| 		const mute = await Mutings.find({ | ||||
| 	async getHasUnreadMessagingMessage(userId: User['id']): Promise<boolean> { | ||||
| 		const mute = await Mutings.findBy({ | ||||
| 			muterId: userId, | ||||
| 		}); | ||||
|  | ||||
| 		const joinings = await UserGroupJoinings.find({ userId: userId }); | ||||
| 		const joinings = await UserGroupJoinings.findBy({ userId: userId }); | ||||
|  | ||||
| 		const groupQs = Promise.all(joinings.map(j => MessagingMessages.createQueryBuilder('message') | ||||
| 			.where(`message.groupId = :groupId`, { groupId: j.userGroupId }) | ||||
| @@ -112,44 +131,44 @@ export class UserRepository extends Repository<User> { | ||||
| 		]); | ||||
|  | ||||
| 		return withUser || withGroups.some(x => x); | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public async getHasUnreadAnnouncement(userId: User['id']): Promise<boolean> { | ||||
| 		const reads = await AnnouncementReads.find({ | ||||
| 	async getHasUnreadAnnouncement(userId: User['id']): Promise<boolean> { | ||||
| 		const reads = await AnnouncementReads.findBy({ | ||||
| 			userId: userId, | ||||
| 		}); | ||||
|  | ||||
| 		const count = await Announcements.count(reads.length > 0 ? { | ||||
| 		const count = await Announcements.countBy(reads.length > 0 ? { | ||||
| 			id: Not(In(reads.map(read => read.announcementId))), | ||||
| 		} : {}); | ||||
|  | ||||
| 		return count > 0; | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public async getHasUnreadAntenna(userId: User['id']): Promise<boolean> { | ||||
| 	async getHasUnreadAntenna(userId: User['id']): Promise<boolean> { | ||||
| 		const myAntennas = (await getAntennas()).filter(a => a.userId === userId); | ||||
|  | ||||
| 		const unread = myAntennas.length > 0 ? await AntennaNotes.findOne({ | ||||
| 		const unread = myAntennas.length > 0 ? await AntennaNotes.findOneBy({ | ||||
| 			antennaId: In(myAntennas.map(x => x.id)), | ||||
| 			read: false, | ||||
| 		}) : null; | ||||
|  | ||||
| 		return unread != null; | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public async getHasUnreadChannel(userId: User['id']): Promise<boolean> { | ||||
| 		const channels = await ChannelFollowings.find({ followerId: userId }); | ||||
| 	async getHasUnreadChannel(userId: User['id']): Promise<boolean> { | ||||
| 		const channels = await ChannelFollowings.findBy({ followerId: userId }); | ||||
|  | ||||
| 		const unread = channels.length > 0 ? await NoteUnreads.findOne({ | ||||
| 		const unread = channels.length > 0 ? await NoteUnreads.findOneBy({ | ||||
| 			userId: userId, | ||||
| 			noteChannelId: In(channels.map(x => x.followeeId)), | ||||
| 		}) : null; | ||||
|  | ||||
| 		return unread != null; | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public async getHasUnreadNotification(userId: User['id']): Promise<boolean> { | ||||
| 		const mute = await Mutings.find({ | ||||
| 	async getHasUnreadNotification(userId: User['id']): Promise<boolean> { | ||||
| 		const mute = await Mutings.findBy({ | ||||
| 			muterId: userId, | ||||
| 		}); | ||||
| 		const mutedUserIds = mute.map(m => m.muteeId); | ||||
| @@ -164,17 +183,17 @@ export class UserRepository extends Repository<User> { | ||||
| 		}); | ||||
|  | ||||
| 		return count > 0; | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public async getHasPendingReceivedFollowRequest(userId: User['id']): Promise<boolean> { | ||||
| 		const count = await FollowRequests.count({ | ||||
| 	async getHasPendingReceivedFollowRequest(userId: User['id']): Promise<boolean> { | ||||
| 		const count = await FollowRequests.countBy({ | ||||
| 			followeeId: userId, | ||||
| 		}); | ||||
|  | ||||
| 		return count > 0; | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public getOnlineStatus(user: User): 'unknown' | 'online' | 'active' | 'offline' { | ||||
| 	getOnlineStatus(user: User): 'unknown' | 'online' | 'active' | 'offline' { | ||||
| 		if (user.hideOnlineStatus) return 'unknown'; | ||||
| 		if (user.lastActiveDate == null) return 'unknown'; | ||||
| 		const elapsed = Date.now() - user.lastActiveDate.getTime(); | ||||
| @@ -183,22 +202,22 @@ export class UserRepository extends Repository<User> { | ||||
| 			elapsed < USER_ACTIVE_THRESHOLD ? 'active' : | ||||
| 			'offline' | ||||
| 		); | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public getAvatarUrl(user: User): string { | ||||
| 	getAvatarUrl(user: User): string { | ||||
| 		// TODO: avatarIdがあるがavatarがない(JOINされてない)場合のハンドリング | ||||
| 		if (user.avatar) { | ||||
| 			return DriveFiles.getPublicUrl(user.avatar, true) || this.getIdenticonUrl(user.id); | ||||
| 		} else { | ||||
| 			return this.getIdenticonUrl(user.id); | ||||
| 		} | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public getIdenticonUrl(userId: User['id']): string { | ||||
| 	getIdenticonUrl(userId: User['id']): string { | ||||
| 		return `${config.url}/identicon/${userId}`; | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public async pack<ExpectsMe extends boolean | null = null, D extends boolean = false>( | ||||
| 	async pack<ExpectsMe extends boolean | null = null, D extends boolean = false>( | ||||
| 		src: User['id'] | User, | ||||
| 		me?: { id: User['id'] } | null | undefined, | ||||
| 		options?: { | ||||
| @@ -215,11 +234,15 @@ export class UserRepository extends Repository<User> { | ||||
|  | ||||
| 		if (typeof src === 'object') { | ||||
| 			user = src; | ||||
| 			if (src.avatar === undefined && src.avatarId) src.avatar = await DriveFiles.findOne(src.avatarId) ?? null; | ||||
| 			if (src.banner === undefined && src.bannerId) src.banner = await DriveFiles.findOne(src.bannerId) ?? null; | ||||
| 			if (src.avatar === undefined && src.avatarId) src.avatar = await DriveFiles.findOneBy({ id: src.avatarId }) ?? null; | ||||
| 			if (src.banner === undefined && src.bannerId) src.banner = await DriveFiles.findOneBy({ id: src.bannerId }) ?? null; | ||||
| 		} else { | ||||
| 			user = await this.findOneOrFail(src, { | ||||
| 				relations: ['avatar', 'banner'], | ||||
| 			user = await this.findOneOrFail({ | ||||
| 				where: { id: src }, | ||||
| 				relations: { | ||||
| 					avatar: true, | ||||
| 					banner: true, | ||||
| 				}, | ||||
| 			}); | ||||
| 		} | ||||
|  | ||||
| @@ -232,7 +255,7 @@ export class UserRepository extends Repository<User> { | ||||
| 			.innerJoinAndSelect('pin.note', 'note') | ||||
| 			.orderBy('pin.id', 'DESC') | ||||
| 			.getMany() : []; | ||||
| 		const profile = opts.detail ? await UserProfiles.findOneOrFail(user.id) : null; | ||||
| 		const profile = opts.detail ? await UserProfiles.findOneByOrFail({ userId: user.id }) : null; | ||||
|  | ||||
| 		const followingCount = profile == null ? null : | ||||
| 			(profile.ffVisibility === 'public') || isMe ? user.followingCount : | ||||
| @@ -258,9 +281,8 @@ export class UserRepository extends Repository<User> { | ||||
| 			isModerator: user.isModerator || falsy, | ||||
| 			isBot: user.isBot || falsy, | ||||
| 			isCat: user.isCat || falsy, | ||||
| 			// TODO: typeorm 3.0にしたら .then(x => x || null) は消せる | ||||
| 			instance: user.host ? userInstanceCache.fetch(user.host, | ||||
| 				() => Instances.findOne({ host: user.host }).then(x => x || null), | ||||
| 				() => Instances.findOneBy({ host: user.host! }), | ||||
| 				v => v != null | ||||
| 			).then(instance => instance ? { | ||||
| 				name: instance.name, | ||||
| @@ -304,7 +326,7 @@ export class UserRepository extends Repository<User> { | ||||
| 				twoFactorEnabled: profile!.twoFactorEnabled, | ||||
| 				usePasswordLessLogin: profile!.usePasswordLessLogin, | ||||
| 				securityKeys: profile!.twoFactorEnabled | ||||
| 					? UserSecurityKeys.count({ | ||||
| 					? UserSecurityKeys.countBy({ | ||||
| 						userId: user.id, | ||||
| 					}).then(result => result >= 1) | ||||
| 					: false, | ||||
| @@ -352,7 +374,11 @@ export class UserRepository extends Repository<User> { | ||||
| 						where: { | ||||
| 							userId: user.id, | ||||
| 						}, | ||||
| 						select: ['id', 'name', 'lastUsed'], | ||||
| 						select: { | ||||
| 							id: true, | ||||
| 							name: true, | ||||
| 							lastUsed: true, | ||||
| 						}, | ||||
| 					}) | ||||
| 					: [], | ||||
| 			} : {}), | ||||
| @@ -369,9 +395,9 @@ export class UserRepository extends Repository<User> { | ||||
| 		} as Promiseable<Packed<'User'>> as Promiseable<IsMeAndIsUserDetailed<ExpectsMe, D>>; | ||||
|  | ||||
| 		return await awaitAll(packed); | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public packMany<D extends boolean = false>( | ||||
| 	packMany<D extends boolean = false>( | ||||
| 		users: (User['id'] | User)[], | ||||
| 		me?: { id: User['id'] } | null | undefined, | ||||
| 		options?: { | ||||
| @@ -380,17 +406,8 @@ export class UserRepository extends Repository<User> { | ||||
| 		} | ||||
| 	): Promise<IsUserDetailed<D>[]> { | ||||
| 		return Promise.all(users.map(u => this.pack(u, me, options))); | ||||
| 	} | ||||
| 	}, | ||||
|  | ||||
| 	public isLocalUser(user: User): user is ILocalUser; | ||||
| 	public isLocalUser<T extends { host: User['host'] }>(user: T): user is T & { host: null; }; | ||||
| 	public isLocalUser(user: User | { host: User['host'] }): boolean { | ||||
| 		return user.host == null; | ||||
| 	} | ||||
|  | ||||
| 	public isRemoteUser(user: User): user is IRemoteUser; | ||||
| 	public isRemoteUser<T extends { host: User['host'] }>(user: T): user is T & { host: string; }; | ||||
| 	public isRemoteUser(user: User | { host: User['host'] }): boolean { | ||||
| 		return !this.isLocalUser(user); | ||||
| 	} | ||||
| } | ||||
| 	isLocalUser, | ||||
| 	isRemoteUser, | ||||
| }); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 syuilo
					syuilo