Fix avatar/banner proxy (#8346)
* Fix avatar/banner proxy Co-authored-by: mei23 <m@m544.net> * use getAvatarUrl * fix * join avatar and banner to improve performance * join * Update hybrid-timeline.ts * fix Co-authored-by: mei23 <m@m544.net> Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
This commit is contained in:
		
							parent
							
								
									d071d18dd7
								
							
						
					
					
						commit
						e314be5b59
					
				
					 34 changed files with 180 additions and 99 deletions
				
			
		|  | @ -155,6 +155,9 @@ id: 'aid' | ||||||
| # Media Proxy | # Media Proxy | ||||||
| #mediaProxy: https://example.com/proxy | #mediaProxy: https://example.com/proxy | ||||||
| 
 | 
 | ||||||
|  | # Proxy remote files (default: false) | ||||||
|  | #proxyRemoteFiles: true | ||||||
|  | 
 | ||||||
| # Sign to ActivityPub GET request (default: false) | # Sign to ActivityPub GET request (default: false) | ||||||
| #signToActivityPubGet: true | #signToActivityPubGet: true | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -325,8 +325,6 @@ disablingTimelinesInfo: "これらのタイムラインを無効化しても、 | ||||||
| registration: "登録" | registration: "登録" | ||||||
| enableRegistration: "誰でも新規登録できるようにする" | enableRegistration: "誰でも新規登録できるようにする" | ||||||
| invite: "招待" | invite: "招待" | ||||||
| proxyRemoteFiles: "リモートのファイルをプロキシする" |  | ||||||
| proxyRemoteFilesDescription: "この設定を有効にすると、未保存または保存容量超過で削除されたリモートファイルをローカルでプロキシし、サムネイルも生成するようになります。サーバーのストレージには影響しません、" |  | ||||||
| driveCapacityPerLocalAccount: "ローカルユーザーひとりあたりのドライブ容量" | driveCapacityPerLocalAccount: "ローカルユーザーひとりあたりのドライブ容量" | ||||||
| driveCapacityPerRemoteAccount: "リモートユーザーひとりあたりのドライブ容量" | driveCapacityPerRemoteAccount: "リモートユーザーひとりあたりのドライブ容量" | ||||||
| inMb: "メガバイト単位" | inMb: "メガバイト単位" | ||||||
|  |  | ||||||
|  | @ -0,0 +1,23 @@ | ||||||
|  | "use strict"; | ||||||
|  | Object.defineProperty(exports, "__esModule", { value: true }); | ||||||
|  | class fixRemoteFileProxy1626509500668 { | ||||||
|  |     constructor() { | ||||||
|  |         this.name = 'fixRemoteFileProxy1626509500668'; | ||||||
|  |     } | ||||||
|  |     async up(queryRunner) { | ||||||
|  |         await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "avatarUrl"`); | ||||||
|  |         await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "bannerUrl"`); | ||||||
|  |         await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "avatarBlurhash"`); | ||||||
|  |         await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "bannerBlurhash"`); | ||||||
|  |         await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "proxyRemoteFiles"`); | ||||||
|  |     } | ||||||
|  |     async down(queryRunner) { | ||||||
|  |         await queryRunner.query(`ALTER TABLE "meta" ADD "proxyRemoteFiles" boolean NOT NULL DEFAULT false`); | ||||||
|  |         await queryRunner.query(`ALTER TABLE "user" ADD "bannerBlurhash" character varying(128)`); | ||||||
|  |         await queryRunner.query(`ALTER TABLE "user" ADD "avatarBlurhash" character varying(128)`); | ||||||
|  |         await queryRunner.query(`ALTER TABLE "user" ADD "bannerUrl" character varying(512)`); | ||||||
|  |         await queryRunner.query(`ALTER TABLE "user" ADD "avatarUrl" character varying(512)`); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | exports.fixRemoteFileProxy1626509500668 = fixRemoteFileProxy1626509500668; | ||||||
|  | @ -62,6 +62,7 @@ export type Source = { | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	mediaProxy?: string; | 	mediaProxy?: string; | ||||||
|  | 	proxyRemoteFiles?: boolean; | ||||||
| 
 | 
 | ||||||
| 	signToActivityPubGet?: boolean; | 	signToActivityPubGet?: boolean; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -137,11 +137,6 @@ export class Meta { | ||||||
| 	}) | 	}) | ||||||
| 	public cacheRemoteFiles: boolean; | 	public cacheRemoteFiles: boolean; | ||||||
| 
 | 
 | ||||||
| 	@Column('boolean', { |  | ||||||
| 		default: false, |  | ||||||
| 	}) |  | ||||||
| 	public proxyRemoteFiles: boolean; |  | ||||||
| 
 |  | ||||||
| 	@Column({ | 	@Column({ | ||||||
| 		...id(), | 		...id(), | ||||||
| 		nullable: true, | 		nullable: true, | ||||||
|  |  | ||||||
|  | @ -106,26 +106,6 @@ export class User { | ||||||
| 	}) | 	}) | ||||||
| 	public tags: string[]; | 	public tags: string[]; | ||||||
| 
 | 
 | ||||||
| 	@Column('varchar', { |  | ||||||
| 		length: 512, nullable: true, |  | ||||||
| 	}) |  | ||||||
| 	public avatarUrl: string | null; |  | ||||||
| 
 |  | ||||||
| 	@Column('varchar', { |  | ||||||
| 		length: 512, nullable: true, |  | ||||||
| 	}) |  | ||||||
| 	public bannerUrl: string | null; |  | ||||||
| 
 |  | ||||||
| 	@Column('varchar', { |  | ||||||
| 		length: 128, nullable: true, |  | ||||||
| 	}) |  | ||||||
| 	public avatarBlurhash: string | null; |  | ||||||
| 
 |  | ||||||
| 	@Column('varchar', { |  | ||||||
| 		length: 128, nullable: true, |  | ||||||
| 	}) |  | ||||||
| 	public bannerBlurhash: string | null; |  | ||||||
| 
 |  | ||||||
| 	@Column('boolean', { | 	@Column('boolean', { | ||||||
| 		default: false, | 		default: false, | ||||||
| 		comment: 'Whether the User is suspended.', | 		comment: 'Whether the User is suspended.', | ||||||
|  |  | ||||||
|  | @ -41,7 +41,7 @@ export class DriveFileRepository extends Repository<DriveFile> { | ||||||
| 		return file.properties; | 		return file.properties; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	public getPublicUrl(file: DriveFile, thumbnail = false, meta?: Meta): string | null { | 	public getPublicUrl(file: DriveFile, thumbnail = false): string | null { | ||||||
| 		// リモートかつメディアプロキシ
 | 		// リモートかつメディアプロキシ
 | ||||||
| 		if (file.uri != null && file.userHost != null && config.mediaProxy != null) { | 		if (file.uri != null && file.userHost != null && config.mediaProxy != null) { | ||||||
| 			return appendQuery(config.mediaProxy, query({ | 			return appendQuery(config.mediaProxy, query({ | ||||||
|  | @ -51,7 +51,7 @@ export class DriveFileRepository extends Repository<DriveFile> { | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// リモートかつ期限切れはローカルプロキシを試みる
 | 		// リモートかつ期限切れはローカルプロキシを試みる
 | ||||||
| 		if (file.uri != null && file.isLink && meta && meta.proxyRemoteFiles) { | 		if (file.uri != null && file.isLink && config.proxyRemoteFiles) { | ||||||
| 			const key = thumbnail ? file.thumbnailAccessKey : file.webpublicAccessKey; | 			const key = thumbnail ? file.thumbnailAccessKey : file.webpublicAccessKey; | ||||||
| 
 | 
 | ||||||
| 			if (key && !key.match('/')) {	// 古いものはここにオブジェクトストレージキーが入ってるので除外
 | 			if (key && !key.match('/')) {	// 古いものはここにオブジェクトストレージキーが入ってるので除外
 | ||||||
|  | @ -136,8 +136,8 @@ export class DriveFileRepository extends Repository<DriveFile> { | ||||||
| 			isSensitive: file.isSensitive, | 			isSensitive: file.isSensitive, | ||||||
| 			blurhash: file.blurhash, | 			blurhash: file.blurhash, | ||||||
| 			properties: opts.self ? file.properties : this.getPublicProperties(file), | 			properties: opts.self ? file.properties : this.getPublicProperties(file), | ||||||
| 			url: opts.self ? file.url : this.getPublicUrl(file, false, meta), | 			url: opts.self ? file.url : this.getPublicUrl(file, false), | ||||||
| 			thumbnailUrl: this.getPublicUrl(file, true, meta), | 			thumbnailUrl: this.getPublicUrl(file, true), | ||||||
| 			comment: file.comment, | 			comment: file.comment, | ||||||
| 			folderId: file.folderId, | 			folderId: file.folderId, | ||||||
| 			folder: opts.detail && file.folderId ? DriveFolders.pack(file.folderId, { | 			folder: opts.detail && file.folderId ? DriveFolders.pack(file.folderId, { | ||||||
|  |  | ||||||
|  | @ -23,10 +23,10 @@ export class NoteReactionRepository extends Repository<NoteReaction> { | ||||||
| 		return { | 		return { | ||||||
| 			id: reaction.id, | 			id: reaction.id, | ||||||
| 			createdAt: reaction.createdAt.toISOString(), | 			createdAt: reaction.createdAt.toISOString(), | ||||||
| 			user: await Users.pack(reaction.userId, me), | 			user: await Users.pack(reaction.user ?? reaction.userId, me), | ||||||
| 			type: convertLegacyReaction(reaction.reaction), | 			type: convertLegacyReaction(reaction.reaction), | ||||||
| 			...(opts.withNote ? { | 			...(opts.withNote ? { | ||||||
| 				note: await Notes.pack(reaction.noteId, me), | 				note: await Notes.pack(reaction.note ?? reaction.noteId, me), | ||||||
| 			} : {}), | 			} : {}), | ||||||
| 		}; | 		}; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| import { EntityRepository, Repository, In, Not } from 'typeorm'; | import { EntityRepository, Repository, In, Not } from 'typeorm'; | ||||||
| import Ajv from 'ajv'; | import Ajv from 'ajv'; | ||||||
| import { User, ILocalUser, IRemoteUser } from '@/models/entities/user.js'; | import { User, ILocalUser, IRemoteUser } from '@/models/entities/user.js'; | ||||||
| import { Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, UserProfiles, UserSecurityKeys, UserGroupJoinings, Pages, Announcements, AnnouncementReads, Antennas, AntennaNotes, ChannelFollowings, Instances } from '../index.js'; | import { Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, UserProfiles, UserSecurityKeys, UserGroupJoinings, Pages, Announcements, AnnouncementReads, Antennas, AntennaNotes, ChannelFollowings, Instances, DriveFiles } from '../index.js'; | ||||||
| import config from '@/config/index.js'; | import config from '@/config/index.js'; | ||||||
| import { Packed } from '@/misc/schema.js'; | import { Packed } from '@/misc/schema.js'; | ||||||
| import { awaitAll, Promiseable } from '@/prelude/await-all.js'; | import { awaitAll, Promiseable } from '@/prelude/await-all.js'; | ||||||
|  | @ -182,13 +182,18 @@ export class UserRepository extends Repository<User> { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	public getAvatarUrl(user: User): string { | 	public getAvatarUrl(user: User): string { | ||||||
| 		if (user.avatarUrl) { | 		// TODO: avatarIdがあるがavatarがない(JOINされてない)場合のハンドリング
 | ||||||
| 			return user.avatarUrl; | 		if (user.avatar) { | ||||||
|  | 			return DriveFiles.getPublicUrl(user.avatar, true) || this.getIdenticonUrl(user.id); | ||||||
| 		} else { | 		} else { | ||||||
| 			return `${config.url}/identicon/${user.id}`; | 			return this.getIdenticonUrl(user.id); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	public getIdenticonUrl(userId: User['id']): string { | ||||||
|  | 		return `${config.url}/identicon/${userId}`; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	public async pack<ExpectsMe extends boolean | null = null, D extends boolean = false>( | 	public async pack<ExpectsMe extends boolean | null = null, D extends boolean = false>( | ||||||
| 		src: User['id'] | User, | 		src: User['id'] | User, | ||||||
| 		me?: { id: User['id'] } | null | undefined, | 		me?: { id: User['id'] } | null | undefined, | ||||||
|  | @ -202,7 +207,18 @@ export class UserRepository extends Repository<User> { | ||||||
| 			includeSecrets: false, | 			includeSecrets: false, | ||||||
| 		}, options); | 		}, options); | ||||||
| 
 | 
 | ||||||
| 		const user = typeof src === 'object' ? src : await this.findOneOrFail(src); | 		let user: 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; | ||||||
|  | 		} else { | ||||||
|  | 			user = await this.findOneOrFail(src, { | ||||||
|  | 				relations: ['avatar', 'banner'], | ||||||
|  | 			}); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		const meId = me ? me.id : null; | 		const meId = me ? me.id : null; | ||||||
| 		const isMe = meId === user.id; | 		const isMe = meId === user.id; | ||||||
| 
 | 
 | ||||||
|  | @ -232,7 +248,7 @@ export class UserRepository extends Repository<User> { | ||||||
| 			username: user.username, | 			username: user.username, | ||||||
| 			host: user.host, | 			host: user.host, | ||||||
| 			avatarUrl: this.getAvatarUrl(user), | 			avatarUrl: this.getAvatarUrl(user), | ||||||
| 			avatarBlurhash: user.avatarBlurhash, | 			avatarBlurhash: user.avatar?.blurhash || null, | ||||||
| 			avatarColor: null, // 後方互換性のため
 | 			avatarColor: null, // 後方互換性のため
 | ||||||
| 			isAdmin: user.isAdmin || falsy, | 			isAdmin: user.isAdmin || falsy, | ||||||
| 			isModerator: user.isModerator || falsy, | 			isModerator: user.isModerator || falsy, | ||||||
|  | @ -256,8 +272,8 @@ export class UserRepository extends Repository<User> { | ||||||
| 				createdAt: user.createdAt.toISOString(), | 				createdAt: user.createdAt.toISOString(), | ||||||
| 				updatedAt: user.updatedAt ? user.updatedAt.toISOString() : null, | 				updatedAt: user.updatedAt ? user.updatedAt.toISOString() : null, | ||||||
| 				lastFetchedAt: user.lastFetchedAt ? user.lastFetchedAt.toISOString() : null, | 				lastFetchedAt: user.lastFetchedAt ? user.lastFetchedAt.toISOString() : null, | ||||||
| 				bannerUrl: user.bannerUrl, | 				bannerUrl: user.banner ? DriveFiles.getPublicUrl(user.banner, false) : null, | ||||||
| 				bannerBlurhash: user.bannerBlurhash, | 				bannerBlurhash: user.banner?.blurhash || null, | ||||||
| 				bannerColor: null, // 後方互換性のため
 | 				bannerColor: null, // 後方互換性のため
 | ||||||
| 				isLocked: user.isLocked, | 				isLocked: user.isLocked, | ||||||
| 				isSilenced: user.isSilenced || falsy, | 				isSilenced: user.isSilenced || falsy, | ||||||
|  |  | ||||||
|  | @ -228,26 +228,14 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise<Us | ||||||
| 
 | 
 | ||||||
| 	const avatarId = avatar ? avatar.id : null; | 	const avatarId = avatar ? avatar.id : null; | ||||||
| 	const bannerId = banner ? banner.id : null; | 	const bannerId = banner ? banner.id : null; | ||||||
| 	const avatarUrl = avatar ? DriveFiles.getPublicUrl(avatar, true) : null; |  | ||||||
| 	const bannerUrl = banner ? DriveFiles.getPublicUrl(banner) : null; |  | ||||||
| 	const avatarBlurhash = avatar ? avatar.blurhash : null; |  | ||||||
| 	const bannerBlurhash = banner ? banner.blurhash : null; |  | ||||||
| 
 | 
 | ||||||
| 	await Users.update(user!.id, { | 	await Users.update(user!.id, { | ||||||
| 		avatarId, | 		avatarId, | ||||||
| 		bannerId, | 		bannerId, | ||||||
| 		avatarUrl, |  | ||||||
| 		bannerUrl, |  | ||||||
| 		avatarBlurhash, |  | ||||||
| 		bannerBlurhash, |  | ||||||
| 	}); | 	}); | ||||||
| 
 | 
 | ||||||
| 	user!.avatarId = avatarId; | 	user!.avatarId = avatarId; | ||||||
| 	user!.bannerId = bannerId; | 	user!.bannerId = bannerId; | ||||||
| 	user!.avatarUrl = avatarUrl; |  | ||||||
| 	user!.bannerUrl = bannerUrl; |  | ||||||
| 	user!.avatarBlurhash = avatarBlurhash; |  | ||||||
| 	user!.bannerBlurhash = bannerBlurhash; |  | ||||||
| 	//#endregion
 | 	//#endregion
 | ||||||
| 
 | 
 | ||||||
| 	//#region カスタム絵文字取得
 | 	//#region カスタム絵文字取得
 | ||||||
|  | @ -340,14 +328,10 @@ export async function updatePerson(uri: string, resolver?: Resolver | null, hint | ||||||
| 
 | 
 | ||||||
| 	if (avatar) { | 	if (avatar) { | ||||||
| 		updates.avatarId = avatar.id; | 		updates.avatarId = avatar.id; | ||||||
| 		updates.avatarUrl = DriveFiles.getPublicUrl(avatar, true); |  | ||||||
| 		updates.avatarBlurhash = avatar.blurhash; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (banner) { | 	if (banner) { | ||||||
| 		updates.bannerId = banner.id; | 		updates.bannerId = banner.id; | ||||||
| 		updates.bannerUrl = DriveFiles.getPublicUrl(banner); |  | ||||||
| 		updates.bannerBlurhash = banner.blurhash; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Update user
 | 	// Update user
 | ||||||
|  |  | ||||||
|  | @ -39,7 +39,6 @@ export const paramDef = { | ||||||
| 		localDriveCapacityMb: { type: 'integer' }, | 		localDriveCapacityMb: { type: 'integer' }, | ||||||
| 		remoteDriveCapacityMb: { type: 'integer' }, | 		remoteDriveCapacityMb: { type: 'integer' }, | ||||||
| 		cacheRemoteFiles: { type: 'boolean' }, | 		cacheRemoteFiles: { type: 'boolean' }, | ||||||
| 		proxyRemoteFiles: { type: 'boolean' }, |  | ||||||
| 		emailRequiredForSignup: { type: 'boolean' }, | 		emailRequiredForSignup: { type: 'boolean' }, | ||||||
| 		enableHcaptcha: { type: 'boolean' }, | 		enableHcaptcha: { type: 'boolean' }, | ||||||
| 		hcaptchaSiteKey: { type: 'string', nullable: true }, | 		hcaptchaSiteKey: { type: 'string', nullable: true }, | ||||||
|  | @ -175,10 +174,6 @@ export default define(meta, paramDef, async (ps, me) => { | ||||||
| 		set.cacheRemoteFiles = ps.cacheRemoteFiles; | 		set.cacheRemoteFiles = ps.cacheRemoteFiles; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (ps.proxyRemoteFiles !== undefined) { |  | ||||||
| 		set.proxyRemoteFiles = ps.proxyRemoteFiles; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (ps.emailRequiredForSignup !== undefined) { | 	if (ps.emailRequiredForSignup !== undefined) { | ||||||
| 		set.emailRequiredForSignup = ps.emailRequiredForSignup; | 		set.emailRequiredForSignup = ps.emailRequiredForSignup; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -65,10 +65,16 @@ export default define(meta, paramDef, async (ps, user) => { | ||||||
| 			ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) | 			ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) | ||||||
| 		.andWhere(`note.id IN (${ antennaQuery.getQuery() })`) | 		.andWhere(`note.id IN (${ antennaQuery.getQuery() })`) | ||||||
| 		.innerJoinAndSelect('note.user', 'user') | 		.innerJoinAndSelect('note.user', 'user') | ||||||
|  | 		.leftJoinAndSelect('user.avatar', 'avatar') | ||||||
|  | 		.leftJoinAndSelect('user.banner', 'banner') | ||||||
| 		.leftJoinAndSelect('note.reply', 'reply') | 		.leftJoinAndSelect('note.reply', 'reply') | ||||||
| 		.leftJoinAndSelect('note.renote', 'renote') | 		.leftJoinAndSelect('note.renote', 'renote') | ||||||
| 		.leftJoinAndSelect('reply.user', 'replyUser') | 		.leftJoinAndSelect('reply.user', 'replyUser') | ||||||
|  | 		.leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('replyUser.banner', 'replyUserBanner') | ||||||
| 		.leftJoinAndSelect('renote.user', 'renoteUser') | 		.leftJoinAndSelect('renote.user', 'renoteUser') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner') | ||||||
| 		.setParameters(antennaQuery.getParameters()); | 		.setParameters(antennaQuery.getParameters()); | ||||||
| 
 | 
 | ||||||
| 	generateVisibilityQuery(query, user); | 	generateVisibilityQuery(query, user); | ||||||
|  |  | ||||||
|  | @ -55,10 +55,16 @@ export default define(meta, paramDef, async (ps, user) => { | ||||||
| 	const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) | 	const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) | ||||||
| 		.andWhere('note.channelId = :channelId', { channelId: channel.id }) | 		.andWhere('note.channelId = :channelId', { channelId: channel.id }) | ||||||
| 		.innerJoinAndSelect('note.user', 'user') | 		.innerJoinAndSelect('note.user', 'user') | ||||||
|  | 		.leftJoinAndSelect('user.avatar', 'avatar') | ||||||
|  | 		.leftJoinAndSelect('user.banner', 'banner') | ||||||
| 		.leftJoinAndSelect('note.reply', 'reply') | 		.leftJoinAndSelect('note.reply', 'reply') | ||||||
| 		.leftJoinAndSelect('note.renote', 'renote') | 		.leftJoinAndSelect('note.renote', 'renote') | ||||||
| 		.leftJoinAndSelect('reply.user', 'replyUser') | 		.leftJoinAndSelect('reply.user', 'replyUser') | ||||||
|  | 		.leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('replyUser.banner', 'replyUserBanner') | ||||||
| 		.leftJoinAndSelect('renote.user', 'renoteUser') | 		.leftJoinAndSelect('renote.user', 'renoteUser') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner') | ||||||
| 		.leftJoinAndSelect('note.channel', 'channel'); | 		.leftJoinAndSelect('note.channel', 'channel'); | ||||||
| 	//#endregion
 | 	//#endregion
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -64,10 +64,16 @@ export default define(meta, paramDef, async (ps, user) => { | ||||||
| 	const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) | 	const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) | ||||||
| 		.andWhere(`note.id IN (${ clipQuery.getQuery() })`) | 		.andWhere(`note.id IN (${ clipQuery.getQuery() })`) | ||||||
| 		.innerJoinAndSelect('note.user', 'user') | 		.innerJoinAndSelect('note.user', 'user') | ||||||
|  | 		.leftJoinAndSelect('user.avatar', 'avatar') | ||||||
|  | 		.leftJoinAndSelect('user.banner', 'banner') | ||||||
| 		.leftJoinAndSelect('note.reply', 'reply') | 		.leftJoinAndSelect('note.reply', 'reply') | ||||||
| 		.leftJoinAndSelect('note.renote', 'renote') | 		.leftJoinAndSelect('note.renote', 'renote') | ||||||
| 		.leftJoinAndSelect('reply.user', 'replyUser') | 		.leftJoinAndSelect('reply.user', 'replyUser') | ||||||
|  | 		.leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('replyUser.banner', 'replyUserBanner') | ||||||
| 		.leftJoinAndSelect('renote.user', 'renoteUser') | 		.leftJoinAndSelect('renote.user', 'renoteUser') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner') | ||||||
| 		.setParameters(clipQuery.getParameters()); | 		.setParameters(clipQuery.getParameters()); | ||||||
| 
 | 
 | ||||||
| 	if (user) { | 	if (user) { | ||||||
|  |  | ||||||
|  | @ -71,10 +71,16 @@ export default define(meta, paramDef, async (ps, user) => { | ||||||
| 		.leftJoinAndSelect('notification.notifier', 'notifier') | 		.leftJoinAndSelect('notification.notifier', 'notifier') | ||||||
| 		.leftJoinAndSelect('notification.note', 'note') | 		.leftJoinAndSelect('notification.note', 'note') | ||||||
| 		.leftJoinAndSelect('note.user', 'user') | 		.leftJoinAndSelect('note.user', 'user') | ||||||
|  | 		.leftJoinAndSelect('user.avatar', 'avatar') | ||||||
|  | 		.leftJoinAndSelect('user.banner', 'banner') | ||||||
| 		.leftJoinAndSelect('note.reply', 'reply') | 		.leftJoinAndSelect('note.reply', 'reply') | ||||||
| 		.leftJoinAndSelect('note.renote', 'renote') | 		.leftJoinAndSelect('note.renote', 'renote') | ||||||
| 		.leftJoinAndSelect('reply.user', 'replyUser') | 		.leftJoinAndSelect('reply.user', 'replyUser') | ||||||
| 		.leftJoinAndSelect('renote.user', 'renoteUser'); | 		.leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('replyUser.banner', 'replyUserBanner') | ||||||
|  | 		.leftJoinAndSelect('renote.user', 'renoteUser') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); | ||||||
| 
 | 
 | ||||||
| 	query.andWhere(new Brackets(qb => { qb | 	query.andWhere(new Brackets(qb => { qb | ||||||
| 		.where(`notification.notifierId NOT IN (${ mutingQuery.getQuery() })`) | 		.where(`notification.notifierId NOT IN (${ mutingQuery.getQuery() })`) | ||||||
|  |  | ||||||
|  | @ -175,12 +175,6 @@ export default define(meta, paramDef, async (ps, _user, token) => { | ||||||
| 
 | 
 | ||||||
| 		if (avatar == null || avatar.userId !== user.id) throw new ApiError(meta.errors.noSuchAvatar); | 		if (avatar == null || avatar.userId !== user.id) throw new ApiError(meta.errors.noSuchAvatar); | ||||||
| 		if (!avatar.type.startsWith('image/')) throw new ApiError(meta.errors.avatarNotAnImage); | 		if (!avatar.type.startsWith('image/')) throw new ApiError(meta.errors.avatarNotAnImage); | ||||||
| 
 |  | ||||||
| 		updates.avatarUrl = DriveFiles.getPublicUrl(avatar, true); |  | ||||||
| 
 |  | ||||||
| 		if (avatar.blurhash) { |  | ||||||
| 			updates.avatarBlurhash = avatar.blurhash; |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (ps.bannerId) { | 	if (ps.bannerId) { | ||||||
|  | @ -188,12 +182,6 @@ export default define(meta, paramDef, async (ps, _user, token) => { | ||||||
| 
 | 
 | ||||||
| 		if (banner == null || banner.userId !== user.id) throw new ApiError(meta.errors.noSuchBanner); | 		if (banner == null || banner.userId !== user.id) throw new ApiError(meta.errors.noSuchBanner); | ||||||
| 		if (!banner.type.startsWith('image/')) throw new ApiError(meta.errors.bannerNotAnImage); | 		if (!banner.type.startsWith('image/')) throw new ApiError(meta.errors.bannerNotAnImage); | ||||||
| 
 |  | ||||||
| 		updates.bannerUrl = DriveFiles.getPublicUrl(banner, false); |  | ||||||
| 
 |  | ||||||
| 		if (banner.blurhash) { |  | ||||||
| 			updates.bannerBlurhash = banner.blurhash; |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (ps.pinnedPageId) { | 	if (ps.pinnedPageId) { | ||||||
|  |  | ||||||
|  | @ -93,10 +93,6 @@ export const meta = { | ||||||
| 				type: 'boolean', | 				type: 'boolean', | ||||||
| 				optional: false, nullable: false, | 				optional: false, nullable: false, | ||||||
| 			}, | 			}, | ||||||
| 			proxyRemoteFiles: { |  | ||||||
| 				type: 'boolean', |  | ||||||
| 				optional: false, nullable: false, |  | ||||||
| 			}, |  | ||||||
| 			emailRequiredForSignup: { | 			emailRequiredForSignup: { | ||||||
| 				type: 'boolean', | 				type: 'boolean', | ||||||
| 				optional: false, nullable: false, | 				optional: false, nullable: false, | ||||||
|  | @ -529,7 +525,6 @@ export default define(meta, paramDef, async (ps, me) => { | ||||||
| 			pinnedPages: instance.pinnedPages, | 			pinnedPages: instance.pinnedPages, | ||||||
| 			pinnedClipId: instance.pinnedClipId, | 			pinnedClipId: instance.pinnedClipId, | ||||||
| 			cacheRemoteFiles: instance.cacheRemoteFiles, | 			cacheRemoteFiles: instance.cacheRemoteFiles, | ||||||
| 			proxyRemoteFiles: instance.proxyRemoteFiles, |  | ||||||
| 			requireSetup: (await Users.count({ | 			requireSetup: (await Users.count({ | ||||||
| 				host: null, | 				host: null, | ||||||
| 			})) === 0, | 			})) === 0, | ||||||
|  |  | ||||||
|  | @ -37,10 +37,16 @@ export default define(meta, paramDef, async (ps) => { | ||||||
| 		.andWhere(`note.visibility = 'public'`) | 		.andWhere(`note.visibility = 'public'`) | ||||||
| 		.andWhere(`note.localOnly = FALSE`) | 		.andWhere(`note.localOnly = FALSE`) | ||||||
| 		.innerJoinAndSelect('note.user', 'user') | 		.innerJoinAndSelect('note.user', 'user') | ||||||
|  | 		.leftJoinAndSelect('user.avatar', 'avatar') | ||||||
|  | 		.leftJoinAndSelect('user.banner', 'banner') | ||||||
| 		.leftJoinAndSelect('note.reply', 'reply') | 		.leftJoinAndSelect('note.reply', 'reply') | ||||||
| 		.leftJoinAndSelect('note.renote', 'renote') | 		.leftJoinAndSelect('note.renote', 'renote') | ||||||
| 		.leftJoinAndSelect('reply.user', 'replyUser') | 		.leftJoinAndSelect('reply.user', 'replyUser') | ||||||
| 		.leftJoinAndSelect('renote.user', 'renoteUser'); | 		.leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('replyUser.banner', 'replyUserBanner') | ||||||
|  | 		.leftJoinAndSelect('renote.user', 'renoteUser') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); | ||||||
| 
 | 
 | ||||||
| 	if (ps.local) { | 	if (ps.local) { | ||||||
| 		query.andWhere('note.userHost IS NULL'); | 		query.andWhere('note.userHost IS NULL'); | ||||||
|  |  | ||||||
|  | @ -49,10 +49,16 @@ export default define(meta, paramDef, async (ps, user) => { | ||||||
| 			})); | 			})); | ||||||
| 		})) | 		})) | ||||||
| 		.innerJoinAndSelect('note.user', 'user') | 		.innerJoinAndSelect('note.user', 'user') | ||||||
|  | 		.leftJoinAndSelect('user.avatar', 'avatar') | ||||||
|  | 		.leftJoinAndSelect('user.banner', 'banner') | ||||||
| 		.leftJoinAndSelect('note.reply', 'reply') | 		.leftJoinAndSelect('note.reply', 'reply') | ||||||
| 		.leftJoinAndSelect('note.renote', 'renote') | 		.leftJoinAndSelect('note.renote', 'renote') | ||||||
| 		.leftJoinAndSelect('reply.user', 'replyUser') | 		.leftJoinAndSelect('reply.user', 'replyUser') | ||||||
| 		.leftJoinAndSelect('renote.user', 'renoteUser'); | 		.leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('replyUser.banner', 'replyUserBanner') | ||||||
|  | 		.leftJoinAndSelect('renote.user', 'renoteUser') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); | ||||||
| 
 | 
 | ||||||
| 	generateVisibilityQuery(query, user); | 	generateVisibilityQuery(query, user); | ||||||
| 	if (user) generateMutedUserQuery(query, user); | 	if (user) generateMutedUserQuery(query, user); | ||||||
|  |  | ||||||
|  | @ -40,10 +40,16 @@ export default define(meta, paramDef, async (ps, user) => { | ||||||
| 		.andWhere(`note.createdAt > :date`, { date: new Date(Date.now() - day) }) | 		.andWhere(`note.createdAt > :date`, { date: new Date(Date.now() - day) }) | ||||||
| 		.andWhere(`note.visibility = 'public'`) | 		.andWhere(`note.visibility = 'public'`) | ||||||
| 		.innerJoinAndSelect('note.user', 'user') | 		.innerJoinAndSelect('note.user', 'user') | ||||||
|  | 		.leftJoinAndSelect('user.avatar', 'avatar') | ||||||
|  | 		.leftJoinAndSelect('user.banner', 'banner') | ||||||
| 		.leftJoinAndSelect('note.reply', 'reply') | 		.leftJoinAndSelect('note.reply', 'reply') | ||||||
| 		.leftJoinAndSelect('note.renote', 'renote') | 		.leftJoinAndSelect('note.renote', 'renote') | ||||||
| 		.leftJoinAndSelect('reply.user', 'replyUser') | 		.leftJoinAndSelect('reply.user', 'replyUser') | ||||||
| 		.leftJoinAndSelect('renote.user', 'renoteUser'); | 		.leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('replyUser.banner', 'replyUserBanner') | ||||||
|  | 		.leftJoinAndSelect('renote.user', 'renoteUser') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); | ||||||
| 
 | 
 | ||||||
| 	if (user) generateMutedUserQuery(query, user); | 	if (user) generateMutedUserQuery(query, user); | ||||||
| 	if (user) generateBlockedUserQuery(query, user); | 	if (user) generateBlockedUserQuery(query, user); | ||||||
|  |  | ||||||
|  | @ -60,10 +60,16 @@ export default define(meta, paramDef, async (ps, user) => { | ||||||
| 		.andWhere('note.visibility = \'public\'') | 		.andWhere('note.visibility = \'public\'') | ||||||
| 		.andWhere('note.channelId IS NULL') | 		.andWhere('note.channelId IS NULL') | ||||||
| 		.innerJoinAndSelect('note.user', 'user') | 		.innerJoinAndSelect('note.user', 'user') | ||||||
|  | 		.leftJoinAndSelect('user.avatar', 'avatar') | ||||||
|  | 		.leftJoinAndSelect('user.banner', 'banner') | ||||||
| 		.leftJoinAndSelect('note.reply', 'reply') | 		.leftJoinAndSelect('note.reply', 'reply') | ||||||
| 		.leftJoinAndSelect('note.renote', 'renote') | 		.leftJoinAndSelect('note.renote', 'renote') | ||||||
| 		.leftJoinAndSelect('reply.user', 'replyUser') | 		.leftJoinAndSelect('reply.user', 'replyUser') | ||||||
| 		.leftJoinAndSelect('renote.user', 'renoteUser'); | 		.leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('replyUser.banner', 'replyUserBanner') | ||||||
|  | 		.leftJoinAndSelect('renote.user', 'renoteUser') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); | ||||||
| 
 | 
 | ||||||
| 	generateRepliesQuery(query, user); | 	generateRepliesQuery(query, user); | ||||||
| 	if (user) generateMutedUserQuery(query, user); | 	if (user) generateMutedUserQuery(query, user); | ||||||
|  |  | ||||||
|  | @ -72,10 +72,16 @@ export default define(meta, paramDef, async (ps, user) => { | ||||||
| 				.orWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)'); | 				.orWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)'); | ||||||
| 		})) | 		})) | ||||||
| 		.innerJoinAndSelect('note.user', 'user') | 		.innerJoinAndSelect('note.user', 'user') | ||||||
|  | 		.leftJoinAndSelect('user.avatar', 'avatar') | ||||||
|  | 		.leftJoinAndSelect('user.banner', 'banner') | ||||||
| 		.leftJoinAndSelect('note.reply', 'reply') | 		.leftJoinAndSelect('note.reply', 'reply') | ||||||
| 		.leftJoinAndSelect('note.renote', 'renote') | 		.leftJoinAndSelect('note.renote', 'renote') | ||||||
| 		.leftJoinAndSelect('reply.user', 'replyUser') | 		.leftJoinAndSelect('reply.user', 'replyUser') | ||||||
|  | 		.leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('replyUser.banner', 'replyUserBanner') | ||||||
| 		.leftJoinAndSelect('renote.user', 'renoteUser') | 		.leftJoinAndSelect('renote.user', 'renoteUser') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner') | ||||||
| 		.setParameters(followingQuery.getParameters()); | 		.setParameters(followingQuery.getParameters()); | ||||||
| 
 | 
 | ||||||
| 	generateChannelQuery(query, user); | 	generateChannelQuery(query, user); | ||||||
|  |  | ||||||
|  | @ -65,10 +65,16 @@ export default define(meta, paramDef, async (ps, user) => { | ||||||
| 			ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) | 			ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) | ||||||
| 		.andWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)') | 		.andWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)') | ||||||
| 		.innerJoinAndSelect('note.user', 'user') | 		.innerJoinAndSelect('note.user', 'user') | ||||||
|  | 		.leftJoinAndSelect('user.avatar', 'avatar') | ||||||
|  | 		.leftJoinAndSelect('user.banner', 'banner') | ||||||
| 		.leftJoinAndSelect('note.reply', 'reply') | 		.leftJoinAndSelect('note.reply', 'reply') | ||||||
| 		.leftJoinAndSelect('note.renote', 'renote') | 		.leftJoinAndSelect('note.renote', 'renote') | ||||||
| 		.leftJoinAndSelect('reply.user', 'replyUser') | 		.leftJoinAndSelect('reply.user', 'replyUser') | ||||||
| 		.leftJoinAndSelect('renote.user', 'renoteUser'); | 		.leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('replyUser.banner', 'replyUserBanner') | ||||||
|  | 		.leftJoinAndSelect('renote.user', 'renoteUser') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); | ||||||
| 
 | 
 | ||||||
| 	generateChannelQuery(query, user); | 	generateChannelQuery(query, user); | ||||||
| 	generateRepliesQuery(query, user); | 	generateRepliesQuery(query, user); | ||||||
|  |  | ||||||
|  | @ -48,10 +48,16 @@ export default define(meta, paramDef, async (ps, user) => { | ||||||
| 			.orWhere(`'{"${user.id}"}' <@ note.visibleUserIds`); | 			.orWhere(`'{"${user.id}"}' <@ note.visibleUserIds`); | ||||||
| 		})) | 		})) | ||||||
| 		.innerJoinAndSelect('note.user', 'user') | 		.innerJoinAndSelect('note.user', 'user') | ||||||
|  | 		.leftJoinAndSelect('user.avatar', 'avatar') | ||||||
|  | 		.leftJoinAndSelect('user.banner', 'banner') | ||||||
| 		.leftJoinAndSelect('note.reply', 'reply') | 		.leftJoinAndSelect('note.reply', 'reply') | ||||||
| 		.leftJoinAndSelect('note.renote', 'renote') | 		.leftJoinAndSelect('note.renote', 'renote') | ||||||
| 		.leftJoinAndSelect('reply.user', 'replyUser') | 		.leftJoinAndSelect('reply.user', 'replyUser') | ||||||
| 		.leftJoinAndSelect('renote.user', 'renoteUser'); | 		.leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('replyUser.banner', 'replyUserBanner') | ||||||
|  | 		.leftJoinAndSelect('renote.user', 'renoteUser') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); | ||||||
| 
 | 
 | ||||||
| 	generateVisibilityQuery(query, user); | 	generateVisibilityQuery(query, user); | ||||||
| 	generateMutedUserQuery(query, user); | 	generateMutedUserQuery(query, user); | ||||||
|  |  | ||||||
|  | @ -68,6 +68,7 @@ export default define(meta, paramDef, async (ps, user) => { | ||||||
| 		order: { | 		order: { | ||||||
| 			id: -1, | 			id: -1, | ||||||
| 		}, | 		}, | ||||||
|  | 		relations: ['user', 'user.avatar', 'user.banner', 'note'], | ||||||
| 	}); | 	}); | ||||||
| 
 | 
 | ||||||
| 	return await Promise.all(reactions.map(reaction => NoteReactions.pack(reaction, user))); | 	return await Promise.all(reactions.map(reaction => NoteReactions.pack(reaction, user))); | ||||||
|  |  | ||||||
|  | @ -52,10 +52,16 @@ export default define(meta, paramDef, async (ps, user) => { | ||||||
| 	const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) | 	const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) | ||||||
| 		.andWhere(`note.renoteId = :renoteId`, { renoteId: note.id }) | 		.andWhere(`note.renoteId = :renoteId`, { renoteId: note.id }) | ||||||
| 		.innerJoinAndSelect('note.user', 'user') | 		.innerJoinAndSelect('note.user', 'user') | ||||||
|  | 		.leftJoinAndSelect('user.avatar', 'avatar') | ||||||
|  | 		.leftJoinAndSelect('user.banner', 'banner') | ||||||
| 		.leftJoinAndSelect('note.reply', 'reply') | 		.leftJoinAndSelect('note.reply', 'reply') | ||||||
| 		.leftJoinAndSelect('note.renote', 'renote') | 		.leftJoinAndSelect('note.renote', 'renote') | ||||||
| 		.leftJoinAndSelect('reply.user', 'replyUser') | 		.leftJoinAndSelect('reply.user', 'replyUser') | ||||||
| 		.leftJoinAndSelect('renote.user', 'renoteUser'); | 		.leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('replyUser.banner', 'replyUserBanner') | ||||||
|  | 		.leftJoinAndSelect('renote.user', 'renoteUser') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); | ||||||
| 
 | 
 | ||||||
| 	generateVisibilityQuery(query, user); | 	generateVisibilityQuery(query, user); | ||||||
| 	if (user) generateMutedUserQuery(query, user); | 	if (user) generateMutedUserQuery(query, user); | ||||||
|  |  | ||||||
|  | @ -37,10 +37,16 @@ export default define(meta, paramDef, async (ps, user) => { | ||||||
| 	const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) | 	const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) | ||||||
| 		.andWhere('note.replyId = :replyId', { replyId: ps.noteId }) | 		.andWhere('note.replyId = :replyId', { replyId: ps.noteId }) | ||||||
| 		.innerJoinAndSelect('note.user', 'user') | 		.innerJoinAndSelect('note.user', 'user') | ||||||
|  | 		.leftJoinAndSelect('user.avatar', 'avatar') | ||||||
|  | 		.leftJoinAndSelect('user.banner', 'banner') | ||||||
| 		.leftJoinAndSelect('note.reply', 'reply') | 		.leftJoinAndSelect('note.reply', 'reply') | ||||||
| 		.leftJoinAndSelect('note.renote', 'renote') | 		.leftJoinAndSelect('note.renote', 'renote') | ||||||
| 		.leftJoinAndSelect('reply.user', 'replyUser') | 		.leftJoinAndSelect('reply.user', 'replyUser') | ||||||
| 		.leftJoinAndSelect('renote.user', 'renoteUser'); | 		.leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('replyUser.banner', 'replyUserBanner') | ||||||
|  | 		.leftJoinAndSelect('renote.user', 'renoteUser') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); | ||||||
| 
 | 
 | ||||||
| 	generateVisibilityQuery(query, user); | 	generateVisibilityQuery(query, user); | ||||||
| 	if (user) generateMutedUserQuery(query, user); | 	if (user) generateMutedUserQuery(query, user); | ||||||
|  |  | ||||||
|  | @ -46,10 +46,16 @@ export const paramDef = { | ||||||
| export default define(meta, paramDef, async (ps, me) => { | export default define(meta, paramDef, async (ps, me) => { | ||||||
| 	const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) | 	const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) | ||||||
| 		.innerJoinAndSelect('note.user', 'user') | 		.innerJoinAndSelect('note.user', 'user') | ||||||
|  | 		.leftJoinAndSelect('user.avatar', 'avatar') | ||||||
|  | 		.leftJoinAndSelect('user.banner', 'banner') | ||||||
| 		.leftJoinAndSelect('note.reply', 'reply') | 		.leftJoinAndSelect('note.reply', 'reply') | ||||||
| 		.leftJoinAndSelect('note.renote', 'renote') | 		.leftJoinAndSelect('note.renote', 'renote') | ||||||
| 		.leftJoinAndSelect('reply.user', 'replyUser') | 		.leftJoinAndSelect('reply.user', 'replyUser') | ||||||
| 		.leftJoinAndSelect('renote.user', 'renoteUser'); | 		.leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('replyUser.banner', 'replyUserBanner') | ||||||
|  | 		.leftJoinAndSelect('renote.user', 'renoteUser') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); | ||||||
| 
 | 
 | ||||||
| 	generateVisibilityQuery(query, me); | 	generateVisibilityQuery(query, me); | ||||||
| 	if (me) generateMutedUserQuery(query, me); | 	if (me) generateMutedUserQuery(query, me); | ||||||
|  |  | ||||||
|  | @ -56,10 +56,16 @@ export default define(meta, paramDef, async (ps, me) => { | ||||||
| 		query | 		query | ||||||
| 			.andWhere('note.text ILIKE :q', { q: `%${ps.query}%` }) | 			.andWhere('note.text ILIKE :q', { q: `%${ps.query}%` }) | ||||||
| 			.innerJoinAndSelect('note.user', 'user') | 			.innerJoinAndSelect('note.user', 'user') | ||||||
|  | 			.leftJoinAndSelect('user.avatar', 'avatar') | ||||||
|  | 			.leftJoinAndSelect('user.banner', 'banner') | ||||||
| 			.leftJoinAndSelect('note.reply', 'reply') | 			.leftJoinAndSelect('note.reply', 'reply') | ||||||
| 			.leftJoinAndSelect('note.renote', 'renote') | 			.leftJoinAndSelect('note.renote', 'renote') | ||||||
| 			.leftJoinAndSelect('reply.user', 'replyUser') | 			.leftJoinAndSelect('reply.user', 'replyUser') | ||||||
| 			.leftJoinAndSelect('renote.user', 'renoteUser'); | 			.leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') | ||||||
|  | 			.leftJoinAndSelect('replyUser.banner', 'replyUserBanner') | ||||||
|  | 			.leftJoinAndSelect('renote.user', 'renoteUser') | ||||||
|  | 			.leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') | ||||||
|  | 			.leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); | ||||||
| 
 | 
 | ||||||
| 		generateVisibilityQuery(query, me); | 		generateVisibilityQuery(query, me); | ||||||
| 		if (me) generateMutedUserQuery(query, me); | 		if (me) generateMutedUserQuery(query, me); | ||||||
|  |  | ||||||
|  | @ -64,10 +64,16 @@ export default define(meta, paramDef, async (ps, user) => { | ||||||
| 			if (hasFollowing) qb.orWhere(`note.userId IN (${ followingQuery.getQuery() })`); | 			if (hasFollowing) qb.orWhere(`note.userId IN (${ followingQuery.getQuery() })`); | ||||||
| 		})) | 		})) | ||||||
| 		.innerJoinAndSelect('note.user', 'user') | 		.innerJoinAndSelect('note.user', 'user') | ||||||
|  | 		.leftJoinAndSelect('user.avatar', 'avatar') | ||||||
|  | 		.leftJoinAndSelect('user.banner', 'banner') | ||||||
| 		.leftJoinAndSelect('note.reply', 'reply') | 		.leftJoinAndSelect('note.reply', 'reply') | ||||||
| 		.leftJoinAndSelect('note.renote', 'renote') | 		.leftJoinAndSelect('note.renote', 'renote') | ||||||
| 		.leftJoinAndSelect('reply.user', 'replyUser') | 		.leftJoinAndSelect('reply.user', 'replyUser') | ||||||
|  | 		.leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('replyUser.banner', 'replyUserBanner') | ||||||
| 		.leftJoinAndSelect('renote.user', 'renoteUser') | 		.leftJoinAndSelect('renote.user', 'renoteUser') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner') | ||||||
| 		.setParameters(followingQuery.getParameters()); | 		.setParameters(followingQuery.getParameters()); | ||||||
| 
 | 
 | ||||||
| 	generateChannelQuery(query, user); | 	generateChannelQuery(query, user); | ||||||
|  |  | ||||||
|  | @ -66,10 +66,16 @@ export default define(meta, paramDef, async (ps, user) => { | ||||||
| 	const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) | 	const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) | ||||||
| 		.andWhere(`note.userId IN (${ listQuery.getQuery() })`) | 		.andWhere(`note.userId IN (${ listQuery.getQuery() })`) | ||||||
| 		.innerJoinAndSelect('note.user', 'user') | 		.innerJoinAndSelect('note.user', 'user') | ||||||
|  | 		.leftJoinAndSelect('user.avatar', 'avatar') | ||||||
|  | 		.leftJoinAndSelect('user.banner', 'banner') | ||||||
| 		.leftJoinAndSelect('note.reply', 'reply') | 		.leftJoinAndSelect('note.reply', 'reply') | ||||||
| 		.leftJoinAndSelect('note.renote', 'renote') | 		.leftJoinAndSelect('note.renote', 'renote') | ||||||
| 		.leftJoinAndSelect('reply.user', 'replyUser') | 		.leftJoinAndSelect('reply.user', 'replyUser') | ||||||
|  | 		.leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('replyUser.banner', 'replyUserBanner') | ||||||
| 		.leftJoinAndSelect('renote.user', 'renoteUser') | 		.leftJoinAndSelect('renote.user', 'renoteUser') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner') | ||||||
| 		.setParameters(listQuery.getParameters()); | 		.setParameters(listQuery.getParameters()); | ||||||
| 
 | 
 | ||||||
| 	generateVisibilityQuery(query, user); | 	generateVisibilityQuery(query, user); | ||||||
|  |  | ||||||
|  | @ -63,10 +63,16 @@ export default define(meta, paramDef, async (ps, me) => { | ||||||
| 	const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) | 	const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) | ||||||
| 		.andWhere('note.userId = :userId', { userId: user.id }) | 		.andWhere('note.userId = :userId', { userId: user.id }) | ||||||
| 		.innerJoinAndSelect('note.user', 'user') | 		.innerJoinAndSelect('note.user', 'user') | ||||||
|  | 		.leftJoinAndSelect('user.avatar', 'avatar') | ||||||
|  | 		.leftJoinAndSelect('user.banner', 'banner') | ||||||
| 		.leftJoinAndSelect('note.reply', 'reply') | 		.leftJoinAndSelect('note.reply', 'reply') | ||||||
| 		.leftJoinAndSelect('note.renote', 'renote') | 		.leftJoinAndSelect('note.renote', 'renote') | ||||||
| 		.leftJoinAndSelect('reply.user', 'replyUser') | 		.leftJoinAndSelect('reply.user', 'replyUser') | ||||||
| 		.leftJoinAndSelect('renote.user', 'renoteUser'); | 		.leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('replyUser.banner', 'replyUserBanner') | ||||||
|  | 		.leftJoinAndSelect('renote.user', 'renoteUser') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') | ||||||
|  | 		.leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); | ||||||
| 
 | 
 | ||||||
| 	generateVisibilityQuery(query, me); | 	generateVisibilityQuery(query, me); | ||||||
| 	if (me) generateMutedUserQuery(query, me, user); | 	if (me) generateMutedUserQuery(query, me, user); | ||||||
|  |  | ||||||
|  | @ -76,6 +76,8 @@ router.get('/avatar/@:acct', async ctx => { | ||||||
| 		usernameLower: username.toLowerCase(), | 		usernameLower: username.toLowerCase(), | ||||||
| 		host: host === config.host ? null : host, | 		host: host === config.host ? null : host, | ||||||
| 		isSuspended: false, | 		isSuspended: false, | ||||||
|  | 	}, { | ||||||
|  | 		relations: ['avatar'], | ||||||
| 	}); | 	}); | ||||||
| 
 | 
 | ||||||
| 	if (user) { | 	if (user) { | ||||||
|  |  | ||||||
|  | @ -76,11 +76,6 @@ | ||||||
| 					<template #caption>{{ $ts.cacheRemoteFilesDescription }}</template> | 					<template #caption>{{ $ts.cacheRemoteFilesDescription }}</template> | ||||||
| 				</FormSwitch> | 				</FormSwitch> | ||||||
| 
 | 
 | ||||||
| 				<FormSwitch v-model="proxyRemoteFiles" class="_formBlock"> |  | ||||||
| 					<template #label>{{ $ts.proxyRemoteFiles }}</template> |  | ||||||
| 					<template #caption>{{ $ts.proxyRemoteFilesDescription }}</template> |  | ||||||
| 				</FormSwitch> |  | ||||||
| 
 |  | ||||||
| 				<FormSplit :min-width="280"> | 				<FormSplit :min-width="280"> | ||||||
| 					<FormInput v-model="localDriveCapacityMb" type="number" class="_formBlock"> | 					<FormInput v-model="localDriveCapacityMb" type="number" class="_formBlock"> | ||||||
| 						<template #label>{{ $ts.driveCapacityPerLocalAccount }}</template> | 						<template #label>{{ $ts.driveCapacityPerLocalAccount }}</template> | ||||||
|  | @ -185,7 +180,6 @@ export default defineComponent({ | ||||||
| 			enableGlobalTimeline: false, | 			enableGlobalTimeline: false, | ||||||
| 			pinnedUsers: '', | 			pinnedUsers: '', | ||||||
| 			cacheRemoteFiles: false, | 			cacheRemoteFiles: false, | ||||||
| 			proxyRemoteFiles: false, |  | ||||||
| 			localDriveCapacityMb: 0, | 			localDriveCapacityMb: 0, | ||||||
| 			remoteDriveCapacityMb: 0, | 			remoteDriveCapacityMb: 0, | ||||||
| 			enableRegistration: false, | 			enableRegistration: false, | ||||||
|  | @ -214,7 +208,6 @@ export default defineComponent({ | ||||||
| 			this.enableGlobalTimeline = !meta.disableGlobalTimeline; | 			this.enableGlobalTimeline = !meta.disableGlobalTimeline; | ||||||
| 			this.pinnedUsers = meta.pinnedUsers.join('\n'); | 			this.pinnedUsers = meta.pinnedUsers.join('\n'); | ||||||
| 			this.cacheRemoteFiles = meta.cacheRemoteFiles; | 			this.cacheRemoteFiles = meta.cacheRemoteFiles; | ||||||
| 			this.proxyRemoteFiles = meta.proxyRemoteFiles; |  | ||||||
| 			this.localDriveCapacityMb = meta.driveCapacityPerLocalUserMb; | 			this.localDriveCapacityMb = meta.driveCapacityPerLocalUserMb; | ||||||
| 			this.remoteDriveCapacityMb = meta.driveCapacityPerRemoteUserMb; | 			this.remoteDriveCapacityMb = meta.driveCapacityPerRemoteUserMb; | ||||||
| 			this.enableRegistration = !meta.disableRegistration; | 			this.enableRegistration = !meta.disableRegistration; | ||||||
|  | @ -241,7 +234,6 @@ export default defineComponent({ | ||||||
| 				disableGlobalTimeline: !this.enableGlobalTimeline, | 				disableGlobalTimeline: !this.enableGlobalTimeline, | ||||||
| 				pinnedUsers: this.pinnedUsers.split('\n'), | 				pinnedUsers: this.pinnedUsers.split('\n'), | ||||||
| 				cacheRemoteFiles: this.cacheRemoteFiles, | 				cacheRemoteFiles: this.cacheRemoteFiles, | ||||||
| 				proxyRemoteFiles: this.proxyRemoteFiles, |  | ||||||
| 				localDriveCapacityMb: parseInt(this.localDriveCapacityMb, 10), | 				localDriveCapacityMb: parseInt(this.localDriveCapacityMb, 10), | ||||||
| 				remoteDriveCapacityMb: parseInt(this.remoteDriveCapacityMb, 10), | 				remoteDriveCapacityMb: parseInt(this.remoteDriveCapacityMb, 10), | ||||||
| 				disableRegistration: !this.enableRegistration, | 				disableRegistration: !this.enableRegistration, | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue