Merge remote-tracking branch 'misskey-dev/develop' into io
This commit is contained in:
		| @@ -40,6 +40,8 @@ export class EmailService { | ||||
| 	public async sendEmail(to: string, subject: string, html: string, text: string) { | ||||
| 		const meta = await this.metaService.fetch(true); | ||||
|  | ||||
| 		if (!meta.enableEmail) return; | ||||
|  | ||||
| 		const iconUrl = `${this.config.url}/static-assets/mi-white.png`; | ||||
| 		const emailSettingUrl = `${this.config.url}/settings/email`; | ||||
|  | ||||
|   | ||||
| @@ -4,7 +4,7 @@ | ||||
|  */ | ||||
|  | ||||
| import { Inject, Injectable } from '@nestjs/common'; | ||||
| import { IsNull } from 'typeorm'; | ||||
| import { IsNull, Not } from 'typeorm'; | ||||
| import type { MiLocalUser } from '@/models/User.js'; | ||||
| import type { UsersRepository } from '@/models/_.js'; | ||||
| import { MemorySingleCache } from '@/misc/cache.js'; | ||||
| @@ -27,6 +27,14 @@ export class InstanceActorService { | ||||
| 		this.cache = new MemorySingleCache<MiLocalUser>(Infinity); | ||||
| 	} | ||||
|  | ||||
| 	@bindThis | ||||
| 	public async realLocalUsersPresent(): Promise<boolean> { | ||||
| 		return await this.usersRepository.existsBy({ | ||||
| 			host: IsNull(), | ||||
| 			username: Not(ACTOR_USERNAME), | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| 	@bindThis | ||||
| 	public async getInstanceActor(): Promise<MiLocalUser> { | ||||
| 		const cached = this.cache.get(); | ||||
|   | ||||
| @@ -16,6 +16,7 @@ import { MiUserKeypair } from '@/models/UserKeypair.js'; | ||||
| import { MiUsedUsername } from '@/models/UsedUsername.js'; | ||||
| import generateUserToken from '@/misc/generate-native-user-token.js'; | ||||
| import { UserEntityService } from '@/core/entities/UserEntityService.js'; | ||||
| import { InstanceActorService } from '@/core/InstanceActorService.js'; | ||||
| import { bindThis } from '@/decorators.js'; | ||||
| import UsersChart from '@/core/chart/charts/users.js'; | ||||
| import { UtilityService } from '@/core/UtilityService.js'; | ||||
| @@ -37,6 +38,7 @@ export class SignupService { | ||||
| 		private userEntityService: UserEntityService, | ||||
| 		private idService: IdService, | ||||
| 		private metaService: MetaService, | ||||
| 		private instanceActorService: InstanceActorService, | ||||
| 		private usersChart: UsersChart, | ||||
| 	) { | ||||
| 	} | ||||
| @@ -81,7 +83,7 @@ export class SignupService { | ||||
| 			throw new Error('USED_USERNAME'); | ||||
| 		} | ||||
|  | ||||
| 		const isTheFirstUser = (await this.usersRepository.countBy({ host: IsNull() })) === 0; | ||||
| 		const isTheFirstUser = !await this.instanceActorService.realLocalUsersPresent(); | ||||
|  | ||||
| 		if (!opts.ignorePreservedUsernames && !isTheFirstUser) { | ||||
| 			const instance = await this.metaService.fetch(true); | ||||
|   | ||||
| @@ -243,20 +243,37 @@ export class ApPersonService implements OnModuleInit { | ||||
| 		return null; | ||||
| 	} | ||||
|  | ||||
| 	private async resolveAvatarAndBanner(user: MiRemoteUser, icon: any, image: any): Promise<Pick<MiRemoteUser, 'avatarId' | 'bannerId' | 'avatarUrl' | 'bannerUrl' | 'avatarBlurhash' | 'bannerBlurhash'>> { | ||||
| 	private async resolveAvatarAndBanner(user: MiRemoteUser, icon: any, image: any): Promise<Partial<Pick<MiRemoteUser, 'avatarId' | 'bannerId' | 'avatarUrl' | 'bannerUrl' | 'avatarBlurhash' | 'bannerBlurhash'>>> { | ||||
| 		if (user == null) throw new Error('failed to create user: user is null'); | ||||
|  | ||||
| 		const [avatar, banner] = await Promise.all([icon, image].map(img => { | ||||
| 			if (img == null) return null; | ||||
| 			if (user == null) throw new Error('failed to create user: user is null'); | ||||
| 			// if we have an explicitly missing image, return an | ||||
| 			// explicitly-null set of values | ||||
| 			if ((img == null) || (typeof img === 'object' && img.url == null)) { | ||||
| 				return { id: null, url: null, blurhash: null }; | ||||
| 			} | ||||
|  | ||||
| 			return this.apImageService.resolveImage(user, img).catch(() => null); | ||||
| 		})); | ||||
|  | ||||
| 		/* | ||||
| 			we don't want to return nulls on errors! if the database fields | ||||
| 			are already null, nothing changes; if the database has old | ||||
| 			values, we should keep those. The exception is if the remote has | ||||
| 			actually removed the images: in that case, the block above | ||||
| 			returns the special {id:null}&c value, and we return those | ||||
| 		*/ | ||||
| 		return { | ||||
| 			avatarId: avatar?.id ?? null, | ||||
| 			bannerId: banner?.id ?? null, | ||||
| 			avatarUrl: avatar ? this.driveFileEntityService.getPublicUrl(avatar, 'avatar') : null, | ||||
| 			bannerUrl: banner ? this.driveFileEntityService.getPublicUrl(banner) : null, | ||||
| 			avatarBlurhash: avatar?.blurhash ?? null, | ||||
| 			bannerBlurhash: banner?.blurhash ?? null, | ||||
| 			...( avatar ? { | ||||
| 				avatarId: avatar.id, | ||||
| 				avatarUrl: avatar.url ? this.driveFileEntityService.getPublicUrl(avatar, 'avatar') : null, | ||||
| 				avatarBlurhash: avatar.blurhash, | ||||
| 			} : {}), | ||||
| 			...( banner ? { | ||||
| 				bannerId: banner.id, | ||||
| 				bannerUrl: banner.url ? this.driveFileEntityService.getPublicUrl(banner) : null, | ||||
| 				bannerBlurhash: banner.blurhash, | ||||
| 			} : {}), | ||||
| 		}; | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -9,6 +9,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js'; | ||||
| import type { UsersRepository } from '@/models/_.js'; | ||||
| import { SignupService } from '@/core/SignupService.js'; | ||||
| import { UserEntityService } from '@/core/entities/UserEntityService.js'; | ||||
| import { InstanceActorService } from '@/core/InstanceActorService.js'; | ||||
| import { localUsernameSchema, passwordSchema } from '@/models/User.js'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
| import { Packed } from '@/misc/json-schema.js'; | ||||
| @@ -46,13 +47,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | ||||
|  | ||||
| 		private userEntityService: UserEntityService, | ||||
| 		private signupService: SignupService, | ||||
| 		private instanceActorService: InstanceActorService, | ||||
| 	) { | ||||
| 		super(meta, paramDef, async (ps, _me, token) => { | ||||
| 			const me = _me ? await this.usersRepository.findOneByOrFail({ id: _me.id }) : null; | ||||
| 			const noUsers = (await this.usersRepository.countBy({ | ||||
| 				host: IsNull(), | ||||
| 			})) === 0; | ||||
| 			if ((!noUsers && !me?.isRoot) || token !== null) throw new Error('access denied'); | ||||
| 			const realUsers = await this.instanceActorService.realLocalUsersPresent(); | ||||
| 			if ((realUsers && !me?.isRoot) || token !== null) throw new Error('access denied'); | ||||
|  | ||||
| 			const { account, secret } = await this.signupService.signup({ | ||||
| 				username: ps.username, | ||||
|   | ||||
| @@ -6,11 +6,12 @@ | ||||
| import { IsNull, LessThanOrEqual, MoreThan, Brackets } from 'typeorm'; | ||||
| import { Inject, Injectable } from '@nestjs/common'; | ||||
| import JSON5 from 'json5'; | ||||
| import type { AdsRepository, UsersRepository } from '@/models/_.js'; | ||||
| import type { AdsRepository } from '@/models/_.js'; | ||||
| import { MAX_NOTE_TEXT_LENGTH } from '@/const.js'; | ||||
| import { Endpoint } from '@/server/api/endpoint-base.js'; | ||||
| import { UserEntityService } from '@/core/entities/UserEntityService.js'; | ||||
| import { MetaService } from '@/core/MetaService.js'; | ||||
| import { InstanceActorService } from '@/core/InstanceActorService.js'; | ||||
| import type { Config } from '@/config.js'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
| import { DEFAULT_POLICIES } from '@/core/RoleService.js'; | ||||
| @@ -327,14 +328,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | ||||
| 		@Inject(DI.config) | ||||
| 		private config: Config, | ||||
|  | ||||
| 		@Inject(DI.usersRepository) | ||||
| 		private usersRepository: UsersRepository, | ||||
|  | ||||
| 		@Inject(DI.adsRepository) | ||||
| 		private adsRepository: AdsRepository, | ||||
|  | ||||
| 		private userEntityService: UserEntityService, | ||||
| 		private metaService: MetaService, | ||||
| 		private instanceActorService: InstanceActorService, | ||||
| 	) { | ||||
| 		super(meta, paramDef, async (ps, me) => { | ||||
| 			const instance = await this.metaService.fetch(true); | ||||
| @@ -413,9 +412,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | ||||
| 				...(ps.detail ? { | ||||
| 					cacheRemoteFiles: instance.cacheRemoteFiles, | ||||
| 					cacheRemoteSensitiveFiles: instance.cacheRemoteSensitiveFiles, | ||||
| 					requireSetup: (await this.usersRepository.countBy({ | ||||
| 						host: IsNull(), | ||||
| 					})) === 0, | ||||
| 					requireSetup: !await this.instanceActorService.realLocalUsersPresent(), | ||||
| 				} : {}), | ||||
| 			}; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 まっちゃとーにゅ
					まっちゃとーにゅ