fix(api)!: align error codes with throw sites and image bounds (#2488)

This commit is contained in:
Hampus authored and GitHub committed 2026-09-06 15:21:38 +02:00
1 parent 4534822355
commit d5bfa5a73d
99 files changed
+857 -4853

No files matched your search

@@ -4,7 +4,6 @@ import {
DISCOVERY_DEFAULT_LANGUAGE,
DISCOVERY_MAX_TAGS,
DiscoveryApplicationStatus,
DiscoveryCategories,
type DiscoveryCategory,
isValidDiscoveryLanguage,
isValidDiscoveryTag,
@@ -16,7 +15,6 @@ import {DiscoveryAlreadyAppliedError} from '@fluxer/errors/src/domains/discovery
import {DiscoveryApplicationAlreadyReviewedError} from '@fluxer/errors/src/domains/discovery/DiscoveryApplicationAlreadyReviewedError';
import {DiscoveryApplicationNotFoundError} from '@fluxer/errors/src/domains/discovery/DiscoveryApplicationNotFoundError';
import {DiscoveryInsufficientMembersError} from '@fluxer/errors/src/domains/discovery/DiscoveryInsufficientMembersError';
import {DiscoveryInvalidCategoryError} from '@fluxer/errors/src/domains/discovery/DiscoveryInvalidCategoryError';
import {DiscoveryNotDiscoverableError} from '@fluxer/errors/src/domains/discovery/DiscoveryNotDiscoverableError';
import type {GuildSearchFilters} from '@fluxer/schema/src/contracts/search/SearchDocumentTypes.jsx';
import type {DiscoveryApplicationPatchRequest} from '@fluxer/schema/src/domains/guild/GuildDiscoverySchemas';
@@ -31,8 +29,6 @@ import {mapGuildToGuildResponse} from '../GuildModel';
import type {IGuildDiscoveryRepository} from '../repositories/GuildDiscoveryRepository';
import type {IGuildRepositoryAggregate} from '../repositories/IGuildRepositoryAggregate';
const VALID_CATEGORY_TYPES = new Set<number>(Object.values(DiscoveryCategories));
function sanitizeTags(tags: ReadonlyArray<string> | null | undefined): Array<string> {
if (!tags || tags.length === 0) return [];
const seen = new Set<string>();
@@ -169,9 +165,6 @@ export class GuildDiscoveryService extends IGuildDiscoveryService {
messageId: null,
surface: 'profile_field',
});
if (!VALID_CATEGORY_TYPES.has(categoryId)) {
throw new DiscoveryInvalidCategoryError();
}
const guild = await this.guildRepository.findUnique(guildId);
if (!guild) {
throw new DiscoveryApplicationNotFoundError();
@@ -251,9 +244,6 @@ export class GuildDiscoveryService extends IGuildDiscoveryService {
) {
throw new DiscoveryApplicationAlreadyReviewedError();
}
if (data.category_type !== undefined && !VALID_CATEGORY_TYPES.has(data.category_type)) {
throw new DiscoveryInvalidCategoryError();
}
const updatedRow: GuildDiscoveryRow = {
...existing,
description: data.description ?? existing.description,
@@ -112,6 +112,7 @@ export class EmojiService {
const {animated, imageBuffer, contentType} = await this.avatarService.processEmoji({
errorPath: 'image',
base64Image: image,
guildFeatures,
});
const emojiId = createEmojiID(await this.snowflakeService.generate());
await this.avatarService.uploadEmoji({
@@ -243,6 +244,7 @@ export class EmojiService {
const {animated, imageBuffer, contentType} = await this.avatarService.processEmoji({
errorPath: `emojis[${success.length + failed.length}].image`,
base64Image: emojiData.image,
guildFeatures,
});
const emojiId = createEmojiID(await this.snowflakeService.generate());
await this.avatarService.uploadEmoji({
@@ -129,6 +129,7 @@ export class StickerService {
const {animated, imageBuffer} = await this.avatarService.processSticker({
errorPath: 'image',
base64Image: image,
guildFeatures,
});
const stickerId = createStickerID(await this.snowflakeService.generate());
await this.avatarService.uploadSticker({prefix: 'stickers', stickerId, imageBuffer});
@@ -272,6 +273,7 @@ export class StickerService {
const {animated, imageBuffer} = await this.avatarService.processSticker({
errorPath: `stickers[${success.length + failed.length}].image`,
base64Image: stickerData.image,
guildFeatures,
});
const stickerId = createStickerID(await this.snowflakeService.generate());
await this.avatarService.uploadSticker({prefix: 'stickers', stickerId, imageBuffer});
@@ -2,6 +2,7 @@
import {APIErrorCodes} from '@fluxer/constants/src/ApiErrorCodes';
import {DiscoveryCategories} from '@fluxer/constants/src/DiscoveryConstants';
import {ValidationErrorCodes} from '@fluxer/constants/src/ValidationErrorCodes';
import type {
DiscoveryApplicationResponse,
DiscoveryStatusResponse,
@@ -13,6 +14,21 @@ import {HTTP_STATUS, TEST_IDS} from '../../test/TestConstants';
import {createBuilder, createBuilderWithoutAuth} from '../../test/TestRequestBuilder';
import {createGuild, setupTestGuildWithMembers} from './GuildTestUtils';
type FormBodyError = {
code: string;
errors: Array<{
path: string;
code: string;
}>;
};
function expectCategoryTypeFormatError(json: FormBodyError): void {
expect(json.code).toBe(APIErrorCodes.INVALID_FORM_BODY);
const categoryError = json.errors.find((entry) => entry.path.includes('category_type'));
expect(categoryError).toBeDefined();
expect(categoryError?.code).toBe(ValidationErrorCodes.INVALID_FORMAT);
}
async function setGuildMemberCount(harness: ApiTestHarness, guildId: string, memberCount: number): Promise<void> {
await createBuilder(harness, '')
.post(`/test/guilds/${guildId}/member-count`)
@@ -56,21 +72,23 @@ describe('Discovery Application Validation', () => {
const owner = await createTestAccount(harness);
const guild = await createGuild(harness, owner.token, 'Bad Category Guild');
await setGuildMemberCount(harness, guild.id, 1);
await createBuilder(harness, owner.token)
const {json} = await createBuilder<FormBodyError>(harness, owner.token)
.post(`/guilds/${guild.id}/discovery`)
.body({description: 'Valid description here', category_type: 99})
.expect(HTTP_STATUS.BAD_REQUEST)
.execute();
.executeWithResponse();
expectCategoryTypeFormatError(json);
});
test('should reject negative category ID', async () => {
const owner = await createTestAccount(harness);
const guild = await createGuild(harness, owner.token, 'Negative Cat Guild');
await setGuildMemberCount(harness, guild.id, 1);
await createBuilder(harness, owner.token)
const {json} = await createBuilder<FormBodyError>(harness, owner.token)
.post(`/guilds/${guild.id}/discovery`)
.body({description: 'Valid description here', category_type: -1})
.expect(HTTP_STATUS.BAD_REQUEST)
.execute();
.executeWithResponse();
expectCategoryTypeFormatError(json);
});
test('should reject invalid category on edit', async () => {
const owner = await createTestAccount(harness);
@@ -81,11 +99,12 @@ describe('Discovery Application Validation', () => {
.body({description: 'Valid description here', category_type: DiscoveryCategories.GAMING})
.expect(HTTP_STATUS.OK)
.execute();
await createBuilder(harness, owner.token)
const {json} = await createBuilder<FormBodyError>(harness, owner.token)
.patch(`/guilds/${guild.id}/discovery`)
.body({category_type: 99})
.expect(HTTP_STATUS.BAD_REQUEST)
.execute();
.executeWithResponse();
expectCategoryTypeFormatError(json);
});
});
describe('description validation', () => {