mirror of
https://github.com/spacebarchat/server.git
synced 2026-11-04 11:18:37 +00:00
Automod schemas: factor out WithTrigger to fix typescript discarding half the types
This commit is contained in:
1 parent
0d43fbc054
commit
107f503b7f
7 files changed
+37
-26
No files matched your search
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
@@ -107,6 +107,7 @@ public class AutomodTests(ITestOutputHelper testOutputHelper, TestFixture fixtur
|
||||
|
||||
automodRule.Name = Guid.NewGuid().ToString();
|
||||
|
||||
_testOutputHelper.WriteLine(automodRule.ToJson());
|
||||
var r = await Assert.HttpSuccess(await Client.ApiHttpClient.PostAsJsonAsync(
|
||||
$"guilds/{Guild.Id}/auto-moderation/rules",
|
||||
automodRule,
|
||||
|
||||
@@ -20,6 +20,7 @@ import { NextFunction, Request, Response } from "express";
|
||||
import { HTTPError } from "lambert-server/HTTPError";
|
||||
import { ApiError, FieldError, FieldErrors } from "@spacebar/util";
|
||||
import { StringLengthOutOfBoundsException } from "@spacebar/extensions";
|
||||
import { getInvalidSchemaValues } from "@spacebar/schemas";
|
||||
const EntityNotFoundErrorRegex = /"(\w+)"/;
|
||||
|
||||
export function ErrorHandler(error: Error & { type?: string }, req: Request, res: Response, next: NextFunction) {
|
||||
@@ -75,7 +76,14 @@ export function ErrorHandler(error: Error & { type?: string }, req: Request, res
|
||||
|
||||
if (httpcode > 511) httpcode = 400;
|
||||
|
||||
res.status(httpcode).json({ code, message, errors, _ajvErrors, request: `${req.method} ${req.url}` });
|
||||
res.status(httpcode).json({
|
||||
code,
|
||||
message,
|
||||
errors,
|
||||
_ajvErrors,
|
||||
_ajvResolved: _ajvErrors == undefined ? undefined : getInvalidSchemaValues(req.body, _ajvErrors),
|
||||
request: `${req.method} ${req.url}`,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(`[Internal Server Error] 500`, error);
|
||||
return res.status(500).json({ code: 500, message: `Internal server error while handling error`, request: `${req.method} ${req.url}` });
|
||||
|
||||
@@ -177,7 +177,10 @@ export function route(opts: RouteOptions) {
|
||||
message: x.message || "",
|
||||
}),
|
||||
);
|
||||
if (process.env.LOG_VALIDATION_ERRORS) console.log(`[VALIDATION ERROR] ${req.method} ${req.originalUrl} - SCHEMA='${opts.requestBody}' -`, validate?.errors);
|
||||
if (process.env.LOG_VALIDATION_ERRORS) {
|
||||
console.log(`[VALIDATION ERROR] ${req.method} ${req.originalUrl} - SCHEMA='${opts.requestBody}' -`, validate?.errors);
|
||||
if (process.env.LOG_VALIDATION_ERROR_SCHEMAS) console.log(validate.schema);
|
||||
}
|
||||
throw FieldErrors(fields, validate.errors!);
|
||||
}
|
||||
}
|
||||
|
||||
+16
-11
@@ -52,7 +52,7 @@ export const ajv = (function () {
|
||||
strict: true,
|
||||
strictRequired: true,
|
||||
allowUnionTypes: true,
|
||||
discriminator: true
|
||||
discriminator: true,
|
||||
});
|
||||
|
||||
addFormats(_ajv);
|
||||
@@ -70,23 +70,28 @@ export function validateSchema<G extends object>(schema: string, data: G): G {
|
||||
return data;
|
||||
}
|
||||
|
||||
export function getInvalidSchemaValues(data: object, errors: typeof ajv.errors) {
|
||||
export function getInvalidSchemaValues(data: object, errors: typeof ajv.errors): { instancePath: string; value: unknown; keyword: string }[] {
|
||||
if (errors == null) return [];
|
||||
return errors.map((e) => {
|
||||
let instancePath = e.instancePath;
|
||||
if (e.keyword == "additionalProperties") instancePath += `/${e.params.additionalProperty}`;
|
||||
return errors
|
||||
.map((e) => {
|
||||
let instancePath = e.instancePath;
|
||||
if (e.keyword == "additionalProperties") instancePath += `/${e.params.additionalProperty}`;
|
||||
else if (e.keyword == "required") return { instancePath: instancePath + `/${e.params.missingProperty}`, value: "<<undefined>>", keyword: e.keyword };
|
||||
else if (e.keyword == "anyOf") return { instancePath: instancePath, value: "<<irrelevant>>", keyword: e.keyword };
|
||||
|
||||
console.log("Resolving:", { instancePath, eInstancePath: e.instancePath, eKeyword: e.keyword, eParams: e.params });
|
||||
return getInvalidSchemaValue(data, instancePath);
|
||||
});
|
||||
console.log("Resolving:", { instancePath, eInstancePath: e.instancePath, eKeyword: e.keyword, eParams: e.params });
|
||||
return { ...getInvalidSchemaValue(data, instancePath), keyword: e.keyword };
|
||||
})
|
||||
.filter((x) => x != undefined);
|
||||
}
|
||||
|
||||
function getInvalidSchemaValue(data: object, instancePath: string) {
|
||||
function getInvalidSchemaValue(data: object, instancePath: string): { instancePath: string; value: unknown } {
|
||||
const actualInstancePath = instancePath.startsWith("/") ? instancePath.slice(1) : instancePath;
|
||||
if (actualInstancePath.includes("/")) {
|
||||
if (actualInstancePath.trim().length > 0) {
|
||||
// includes("/")
|
||||
const nextProp = actualInstancePath.split("/")[0];
|
||||
const nextPath = actualInstancePath.split("/").slice(1).join("/");
|
||||
return getInvalidSchemaValue((<Record<string, object>>data)[nextProp], nextPath);
|
||||
return { instancePath, value: getInvalidSchemaValue((<Record<string, object>>data)[nextProp], nextPath).value };
|
||||
}
|
||||
return { instancePath, value: data };
|
||||
}
|
||||
@@ -27,19 +27,13 @@ interface BaseAutomodRuleSchema {
|
||||
actions: AutomodAction[];
|
||||
}
|
||||
|
||||
type WithTrigger<T, M> = BaseAutomodRuleSchema & {
|
||||
trigger_type: T;
|
||||
} & M extends never
|
||||
? { trigger_metadata?: never }
|
||||
: { trigger_metadata: M };
|
||||
|
||||
type KeywordRule = WithTrigger<AutomodRuleTriggerType.KEYWORD, AutomodCustomWordsRuleMetadata>;
|
||||
type HarmfulLinkRule = WithTrigger<AutomodRuleTriggerType.HARMFUL_LINK, never>;
|
||||
type SpamRule = WithTrigger<AutomodRuleTriggerType.SPAM, never>;
|
||||
type KeywordPresetRule = WithTrigger<AutomodRuleTriggerType.KEYWORD_PRESET, AutomodKeywordPresetRuleMetadata>;
|
||||
type MentionSpamRule = WithTrigger<AutomodRuleTriggerType.MENTION_SPAM, AutomodMentionSpamRuleMetadata>;
|
||||
type UserProfileRule = WithTrigger<AutomodRuleTriggerType.USER_PROFILE, AutomodUserProfileRuleMetadata>;
|
||||
type GuildPolicyRule = WithTrigger<AutomodRuleTriggerType.GUILD_POLICY, never>;
|
||||
type KeywordRule = BaseAutomodRuleSchema & { trigger_type: AutomodRuleTriggerType.KEYWORD; trigger_metadata: AutomodCustomWordsRuleMetadata };
|
||||
type KeywordPresetRule = BaseAutomodRuleSchema & { trigger_type: AutomodRuleTriggerType.KEYWORD_PRESET; trigger_metadata: AutomodKeywordPresetRuleMetadata };
|
||||
type MentionSpamRule = BaseAutomodRuleSchema & { trigger_type: AutomodRuleTriggerType.MENTION_SPAM; trigger_metadata: AutomodMentionSpamRuleMetadata };
|
||||
type UserProfileRule = BaseAutomodRuleSchema & { trigger_type: AutomodRuleTriggerType.USER_PROFILE; trigger_metadata: AutomodUserProfileRuleMetadata };
|
||||
type HarmfulLinkRule = BaseAutomodRuleSchema & { trigger_type: AutomodRuleTriggerType.HARMFUL_LINK; trigger_metadata?: never };
|
||||
type GuildPolicyRule = BaseAutomodRuleSchema & { trigger_type: AutomodRuleTriggerType.GUILD_POLICY; trigger_metadata?: never };
|
||||
type SpamRule = BaseAutomodRuleSchema & { trigger_type: AutomodRuleTriggerType.SPAM; trigger_metadata?: never };
|
||||
|
||||
export type AutomodRuleSchema = KeywordRule | HarmfulLinkRule | SpamRule | KeywordPresetRule | MentionSpamRule | UserProfileRule | GuildPolicyRule;
|
||||
|
||||
|
||||
Reference in new issue
Block a user