mirror of
https://github.com/spacebarchat/server.git
synced 2026-11-04 06:57:36 +00:00
Fix automod route and schemas
This commit is contained in:
1 parent
4960a62cc1
commit
316e27a08d
8 files changed
+74
-87
No files matched your search
Binary file not shown.
Binary file not shown.
@@ -7,7 +7,9 @@
|
||||
],
|
||||
"includeRe": [
|
||||
"^MessageComponentType\\..*",
|
||||
"^InteractionCallbackType\\..*"
|
||||
"^InteractionCallbackType\\..*",
|
||||
"^AutomodRuleTriggerType\\..*",
|
||||
"^AutomodRuleActionType\\..*"
|
||||
],
|
||||
"manual": [
|
||||
"DefaultSchema",
|
||||
|
||||
@@ -47,7 +47,7 @@ router.get(
|
||||
router.post(
|
||||
"/",
|
||||
route({
|
||||
// requestBody: "AutomodRuleSchema",
|
||||
requestBody: "AutomodRuleSchema",
|
||||
permission: "MANAGE_GUILD",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -63,25 +63,26 @@ router.post(
|
||||
}),
|
||||
async (req: Request, res: Response) => {
|
||||
const { guild_id } = req.params as { [key: string]: string };
|
||||
if (req.user_id !== req.body.creator_id) throw new HTTPError("You can't create a rule for someone else", 403);
|
||||
|
||||
if (guild_id !== req.body.guild_id) throw new HTTPError("You can't create a rule for another guild", 403);
|
||||
|
||||
if (req.body.id) {
|
||||
throw new HTTPError("You can't specify an ID for a new rule", 400);
|
||||
}
|
||||
if ("id" in req.body) throw new HTTPError("You can't specify an ID for a new rule", 400);
|
||||
if ("user_id" in req.body && req.user_id !== req.body.creator_id) throw new HTTPError("You can't create a rule for someone else", 403);
|
||||
if ("guild_id" in req.body && guild_id !== req.body.guild_id) throw new HTTPError("You can't create a rule for another guild", 403);
|
||||
|
||||
const data = req.body as AutomodRuleSchema;
|
||||
|
||||
const created = AutomodRule.create({
|
||||
...{ exempt_roles: [], exempt_channels: [] },
|
||||
...data,
|
||||
creator: await User.findOneOrFail({
|
||||
where: { id: data.creator_id },
|
||||
where: { id: req.user_id },
|
||||
}),
|
||||
guild_id: req.params.guild_id as string,
|
||||
});
|
||||
|
||||
created.position = await AutomodRule.count({ where: { guild_id } });
|
||||
|
||||
const savedRule = await AutomodRule.save(created);
|
||||
console.log(savedRule);
|
||||
return res.json(savedRule);
|
||||
},
|
||||
);
|
||||
@@ -89,7 +90,7 @@ router.post(
|
||||
router.patch(
|
||||
"/:rule_id",
|
||||
route({
|
||||
// requestBody: "AutomodRuleSchema
|
||||
requestBody: "AutomodRuleSchema",
|
||||
permission: "MANAGE_GUILD",
|
||||
responses: {
|
||||
200: {
|
||||
@@ -110,9 +111,13 @@ router.patch(
|
||||
});
|
||||
if (!rule) throw new HTTPError("Automod rule not found", 404);
|
||||
|
||||
if ("id" in req.body) throw new HTTPError("You can't specify an ID for a rule", 400);
|
||||
if ("user_id" in req.body && req.user_id !== req.body.creator_id) throw new HTTPError("You can't modify a rule for someone else", 403);
|
||||
if ("guild_id" in req.body && req.params.guild_id !== req.body.guild_id) throw new HTTPError("You can't modify a rule for another guild", 403);
|
||||
|
||||
const data = req.body as AutomodRuleSchema;
|
||||
|
||||
AutomodRule.merge(rule, data);
|
||||
AutomodRule.merge<AutomodRule>(rule, data);
|
||||
const savedRule = await AutomodRule.save(rule);
|
||||
return res.json(savedRule);
|
||||
},
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
import { BaseClass } from "./BaseClass";
|
||||
import { Entity, JoinColumn, ManyToOne, Column } from "typeorm";
|
||||
import { Entity, JoinColumn, ManyToOne, Column, RelationId } from "typeorm";
|
||||
import { User } from "./User";
|
||||
import { AutomodAction, AutomodRuleEventType, AutomodRuleTriggerMetadata, AutomodRuleTriggerType } from "@spacebar/schemas";
|
||||
|
||||
@@ -25,6 +25,10 @@ import { AutomodAction, AutomodRuleEventType, AutomodRuleTriggerMetadata, Automo
|
||||
name: "automod_rules",
|
||||
})
|
||||
export class AutomodRule extends BaseClass {
|
||||
@Column()
|
||||
@RelationId((automod: AutomodRule) => automod.creator)
|
||||
creator_id: string;
|
||||
|
||||
@JoinColumn({ name: "creator_id", foreignKeyConstraintName: "FK_automod_rule_creator_id" })
|
||||
@ManyToOne(() => User, { onDelete: "CASCADE" })
|
||||
creator: User;
|
||||
@@ -57,8 +61,7 @@ export class AutomodRule extends BaseClass {
|
||||
type: "jsonb",
|
||||
nullable: true,
|
||||
})
|
||||
trigger_metadata?: // this is null for "Block suspected spam content"
|
||||
AutomodRuleTriggerMetadata;
|
||||
trigger_metadata?: AutomodRuleTriggerMetadata | undefined; // may be undefined for trigger types that have no metadata
|
||||
|
||||
@Column({
|
||||
type: "jsonb",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
|
||||
Copyright (C) 2025 Spacebar and Spacebar Contributors
|
||||
Copyright (C) 2026 Spacebar and Spacebar Contributors
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
@@ -18,21 +18,59 @@
|
||||
|
||||
import { Snowflake } from "../../Identifiers";
|
||||
|
||||
export type AutomodRuleTriggerMetadata = AutomodMentionSpamRule | AutomodSuspectedSpamRule | AutomodCommonlyFlaggedWordsRule | AutomodCustomWordsRule;
|
||||
interface BaseAutomodRuleSchema {
|
||||
enabled: boolean;
|
||||
event_type: AutomodRuleEventType;
|
||||
exempt_channels?: Snowflake[];
|
||||
exempt_roles?: Snowflake[];
|
||||
name: string;
|
||||
actions: AutomodAction[];
|
||||
}
|
||||
|
||||
export class AutomodMentionSpamRule {
|
||||
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>;
|
||||
|
||||
export type AutomodRuleSchema = KeywordRule | HarmfulLinkRule | SpamRule | KeywordPresetRule | MentionSpamRule | UserProfileRule | GuildPolicyRule;
|
||||
|
||||
export type AutomodRuleSchemaWithId = AutomodRuleSchema & {
|
||||
id: Snowflake;
|
||||
creator_id: Snowflake;
|
||||
guild_id: Snowflake;
|
||||
position: number;
|
||||
exempt_roles?: Snowflake[];
|
||||
};
|
||||
|
||||
export type AutomodRuleTriggerMetadata = AutomodCustomWordsRuleMetadata | AutomodKeywordPresetRuleMetadata | AutomodMentionSpamRuleMetadata | AutomodUserProfileRuleMetadata;
|
||||
|
||||
export interface AutomodMentionSpamRuleMetadata {
|
||||
mention_total_limit: number;
|
||||
mention_raid_protection_enabled: boolean;
|
||||
}
|
||||
|
||||
export class AutomodSuspectedSpamRule {}
|
||||
|
||||
export class AutomodCommonlyFlaggedWordsRule {
|
||||
export interface AutomodKeywordPresetRuleMetadata {
|
||||
allow_list: string[];
|
||||
presets: AutomodKeywordPresetType[];
|
||||
}
|
||||
|
||||
export class AutomodCustomWordsRule {
|
||||
export interface AutomodCustomWordsRuleMetadata {
|
||||
allow_list: string[];
|
||||
keyword_filter: string[];
|
||||
regex_patterns: string[];
|
||||
}
|
||||
|
||||
// the same as custom words, but separate to allow divergence
|
||||
export interface AutomodUserProfileRuleMetadata {
|
||||
allow_list: string[];
|
||||
keyword_filter: string[];
|
||||
regex_patterns: string[];
|
||||
@@ -42,6 +80,7 @@ export enum AutomodRuleEventType {
|
||||
MESSAGE_SEND = 1,
|
||||
GUILD_MEMBER_EVENT = 2,
|
||||
}
|
||||
|
||||
export enum AutomodRuleTriggerType {
|
||||
KEYWORD = 1,
|
||||
HARMFUL_LINK = 2,
|
||||
@@ -68,27 +107,19 @@ export enum AutomodRuleActionType {
|
||||
export type AutomodAction =
|
||||
| {
|
||||
type: AutomodRuleActionType.BLOCK_MESSAGE;
|
||||
metadata: {
|
||||
custom_message?: string;
|
||||
};
|
||||
metadata: { custom_message?: string };
|
||||
}
|
||||
| {
|
||||
type: AutomodRuleActionType.SEND_ALERT_MESSAGE;
|
||||
metadata: {
|
||||
channel_id: Snowflake;
|
||||
};
|
||||
metadata: { channel_id: Snowflake };
|
||||
}
|
||||
| {
|
||||
type: AutomodRuleActionType.TIMEOUT_USER;
|
||||
metadata: {
|
||||
duration_seconds: number;
|
||||
};
|
||||
metadata: { duration_seconds: number };
|
||||
}
|
||||
| {
|
||||
type: AutomodRuleActionType.QUARANTINE_USER;
|
||||
metadata: {
|
||||
duration_seconds: number;
|
||||
};
|
||||
metadata: { duration_seconds: number };
|
||||
};
|
||||
|
||||
// TODO
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
|
||||
Copyright (C) 2024 Spacebar and Spacebar Contributors
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export interface AutomodMentionSpamRuleSchema {
|
||||
mention_total_limit: number;
|
||||
mention_raid_protection_enabled: boolean;
|
||||
}
|
||||
|
||||
// export interface AutomodSuspectedSpamRuleSchema {}
|
||||
export type AutomodSuspectedSpamRuleSchema = Record<string, never>; // hack to represent an empty object
|
||||
|
||||
export interface AutomodCommonlyFlaggedWordsRuleSchema {
|
||||
allow_list: [string];
|
||||
presets: [number];
|
||||
}
|
||||
|
||||
export interface AutomodCustomWordsRuleSchema {
|
||||
allow_list: [string];
|
||||
keyword_filter: [string];
|
||||
regex_patterns: [string];
|
||||
}
|
||||
|
||||
export interface AutomodRuleSchema {
|
||||
creator_id: string;
|
||||
enabled: boolean;
|
||||
event_type: number; // No idea...
|
||||
exempt_channels: [string];
|
||||
exempt_roles: [string];
|
||||
guild_id: string;
|
||||
name: string;
|
||||
position: number;
|
||||
trigger_type: number; //AutomodTriggerTypes
|
||||
trigger_metadata: AutomodMentionSpamRuleSchema | AutomodSuspectedSpamRuleSchema | AutomodCommonlyFlaggedWordsRuleSchema | AutomodCustomWordsRuleSchema;
|
||||
}
|
||||
|
||||
export interface AutomodRuleSchemaWithId extends AutomodRuleSchema {
|
||||
id: string;
|
||||
}
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
export * from "./ActivitySchema";
|
||||
export * from "./ApplicationAuthorizeSchema";
|
||||
export * from "./AutomodRuleSchema";
|
||||
export * from "./BackupCodesChallengeSchema";
|
||||
export * from "./BanCreateSchema";
|
||||
export * from "./BanModeratorSchema";
|
||||
|
||||
Reference in new issue
Block a user