Repository: directus/directus
File: api/src/services/users.ts (TypeScript)

Code before:
		if (otherAdminUsersCount === 0) {
			throw new UnprocessableContentError({ reason: `You can't change the active status of the last admin user` });
		}
	}

	/**
	 * Get basic information of user identified by email
	 */
	private async getUserByEmail(
		email: string,
	): Promise<{ id: string; role: string; status: string; password: string; email: string } | undefined> {
		return await this.knex
			.select('id', 'role', 'status', 'password', 'email')
			.from('directus_users')
			.whereRaw(`LOWER(??) = ?`, ['email', email.toLowerCase()])
			.first();
	}

	/**
	 * Create URL for inviting users
	 */
	private inviteUrl(email: string, url: string | null): string {
		const payload = { email, scope: 'invite' };

		const token = jwt.sign(payload, getSecret(), {
			expiresIn: (env['USER_INVITE_TOKEN_TTL'] as string) ?? '7d',
			issuer: 'directus',
		});

		return (url ? new Url(url) : new Url(env['PUBLIC_URL'] as string).addPath('admin', 'accept-invite'))
			.setQuery('token', token)
			.toString();
	}

	/**
	 * Validate array of emails. Intended to be used with create/update users
	 */
	private validateEmail(input: string | string[]) {
		const emails = Array.isArray(input) ? input : [input];

		const schema = Joi.string().email().required();

		for (const email of emails) {
			const { error } = schema.validate(email);

			if (error) {
				throw new FailedValidationError({
					field: 'email',
					type: 'email',
				});
			}

Review comment (suggestion):
Default is already defined in `@directus/env` 👍 

```suggestion
			expiresIn: env['USER_INVITE_TOKEN_TTL'] as string,
```

Code after:
		const emails = Array.isArray(input) ? input : [input];

		const schema = Joi.string().email().required();

		for (const email of emails) {
			const { error } = schema.validate(email);

			if (error) {
				throw new FailedValidationError({
					field: 'email',
					type: 'email',
				});
			}
		}
	}

	/**
	 * Create a new user
	 */
	override async createOne(data: Partial<Item>, opts: MutationOptions = {}): Promise<PrimaryKey> {
		try {
			if ('email' in data) {
				this.validateEmail(data['email']);
				await this.checkUniqueEmails([data['email']]);
			}

			if ('password' in data) {
				await this.checkPasswordPolicy([data['password']]);
			}
		} catch (err: any) {
			opts.preMutationError = err;
		}

		if (!('status' in data) || data['status'] === 'active') {
			// Creating a user only requires checking user limits if the user is active, no need to care about the role
			opts.userIntegrityCheckFlags =
				(opts.userIntegrityCheckFlags ?? UserIntegrityCheckFlag.None) | UserIntegrityCheckFlag.UserLimits;

			opts.onRequireUserIntegrityCheck?.(opts.userIntegrityCheckFlags);
		}

		return await super.createOne(data, opts);
	}

	/**
	 * Create multiple new users
	 */
	override async createMany(data: Partial<Item>[], opts: MutationOptions = {}): Promise<PrimaryKey[]> {
		const emails = data.map((payload) => payload['email']).filter((email) => email);
		const passwords = data.map((payload) => payload['password']).filter((password) => password);
		const someActive = data.some((payload) => !('status' in payload) || payload['status'] === 'active');