fix(api): let single community setup work without email verification (#1683)

This commit is contained in:
Hampus authored and GitHub committed 2026-08-16 22:14:59 +02:00
1 parent 30a1271774
commit 45289b5531
3 files changed
+68 -2

No files matched your search

@@ -16,6 +16,7 @@ import {
} from '@fluxer/schema/src/domains/guild/GuildRequestSchemas';
import {GuildResponse, GuildVanityURLResponse} from '@fluxer/schema/src/domains/guild/GuildResponseSchemas';
import {z} from 'zod';
import {requireEmailVerified} from '../../auth/EmailVerificationUtils';
import {requireSudoMode} from '../../auth/services/SudoVerificationService';
import {createGuildID} from '../../BrandedTypes';
import {LoginRequired} from '../../middleware/AuthMiddleware';
@@ -49,6 +50,7 @@ export function GuildBaseController(app: HonoApp) {
if (policy.single_community_enabled) {
throw new SingleCommunityCannotCreateGuildsError();
}
requireEmailVerified(user, 'guild_creation');
const auditLogReason = ctx.get('auditLogReason') ?? null;
const locale = ctx.get('requestLocale') ?? null;
return ctx.json(await ctx.get('guildService').data.createGuild({user, data, locale}, auditLogReason));
@@ -36,7 +36,6 @@ import type {
TemplateSerializedGuild,
} from '@fluxer/schema/src/domains/guild/GuildTemplateSchemas';
import {extractTimestamp} from '@fluxer/snowflake/src/SnowflakeUtils';
import {requireEmailVerified} from '../../../auth/EmailVerificationUtils';
import type {ChannelID, GuildID, RoleID, UserID} from '../../../BrandedTypes';
import {createChannelID, createGuildID, createRoleID, guildIdToRoleId} from '../../../BrandedTypes';
import type {IChannelRepository} from '../../../channel/IChannelRepository';
@@ -257,7 +256,6 @@ export class GuildOperationsService {
if (user.isUnclaimedAccount()) {
throw new UnclaimedAccountCannotCreateGuildsError();
}
requireEmailVerified(user, 'guild_creation');
const currentGuildCount = await this.guildRepository.countUserGuilds(user.id);
const ctx = createLimitMatchContext({user});
const maxGuilds = resolveLimitSafe(
@@ -0,0 +1,66 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {APIErrorCodes} from '@fluxer/constants/src/ApiErrorCodes';
import {describe, expect, it} from 'vitest';
import type {User} from '../../models/User';
import {GuildOperationsService} from '../services/data/GuildOperationsService';
const REACHED_GUILD_COUNT = new Error('reached guild count lookup');
function createServiceStoppingAtGuildCount(): GuildOperationsService {
const guildRepository = {
countUserGuilds: (): never => {
throw REACHED_GUILD_COUNT;
},
};
const unused = null as never;
return new GuildOperationsService(
guildRepository as never,
unused,
unused,
unused,
unused,
unused,
unused,
unused,
unused,
unused,
unused,
unused,
);
}
function createUser(overrides: {emailVerified: boolean; isBot?: boolean}): User {
return {
id: 1n,
isBot: overrides.isBot ?? false,
emailVerified: overrides.emailVerified,
isUnclaimedAccount: () => false,
} as unknown as User;
}
describe('guild creation email verification', () => {
it('does not gate guild creation on email verification inside the domain operation', async () => {
const service = createServiceStoppingAtGuildCount();
await expect(
service.createGuild({user: createUser({emailVerified: false}), data: {name: 'Stock Community'} as never}),
).rejects.toBe(REACHED_GUILD_COUNT);
});
it('reaches the same point for a verified user', async () => {
const service = createServiceStoppingAtGuildCount();
await expect(
service.createGuild({user: createUser({emailVerified: true}), data: {name: 'Stock Community'} as never}),
).rejects.toBe(REACHED_GUILD_COUNT);
});
it('still rejects bots before any guild count lookup', async () => {
const service = createServiceStoppingAtGuildCount();
await expect(
service.createGuild({
user: createUser({emailVerified: true, isBot: true}),
data: {name: 'Stock Community'} as never,
}),
).rejects.toMatchObject({code: APIErrorCodes.BOTS_CANNOT_CREATE_GUILDS});
});
});