Skip to content

Commit

Permalink
feat: complete restrict command
Browse files Browse the repository at this point in the history
  • Loading branch information
didinele committed Oct 7, 2023
1 parent 535546a commit 9626f15
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 37 deletions.
26 changes: 5 additions & 21 deletions packages/core/src/actions/IModAction.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,6 @@
import type { Selectable } from 'kysely';
import type { Case, RestrictCaseData, WarnCaseData } from '../db';

/**
* Represents additional data related to the duration of a case.
*
* This is optional, either both properties or neither must be passed in, and is meant to be "mixed-in" to other
* case data interfaces that support timed actions.
*/
export type OptionalCaseCreateDurationData =
| {
duration: null;
expiresAt: null;
}
| {
duration: number;
expiresAt: Date;
};

/**
* Base data required to create a case.
*/
Expand All @@ -31,11 +15,11 @@ export interface BaseCaseCreateData {
* Data required for restrict cases.
*/
// We use a type intersection here since `OptionalCaseCreateDurationData` is a union.
export type RestrictCaseCreateData = BaseCaseCreateData &
OptionalCaseCreateDurationData & {
clean: boolean;
roleId: string;
};
export interface RestrictCaseCreateData extends BaseCaseCreateData {
clean: boolean;
expiresAt: Date | null;
roleId: string;
}

/**
* Structure responsible for preparation, execution, and notification of a mod action.
Expand Down
3 changes: 1 addition & 2 deletions packages/core/src/actions/RestrictModAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,12 @@ export class RestrictModAction implements IRestrictModAction {
id: cs!.id,
roleId: data.roleId,
clean: data.clean,
duration: data.duration,
expiresAt: data.expiresAt,
})
.returningAll()
.executeTakeFirst();

if (data.duration) {
if (data.expiresAt) {
await transaction
.insertInto('Task')
.values({
Expand Down
2 changes: 0 additions & 2 deletions packages/core/src/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ export type TaskType = (typeof TaskType)[keyof typeof TaskType];
export type BanCaseData = {
id: number;
deleteMessageDays: number | null;
duration: number | null;
expiresAt: Timestamp | null;
};
export type Case = {
Expand Down Expand Up @@ -64,7 +63,6 @@ export type RestrictCaseData = {
id: number;
roleId: string;
clean: Generated<boolean>;
duration: number | null;
expiresAt: Timestamp | null;
};
export type Task = {
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export * from './userActionValidators/UserActionValidatorFactory.js';

export * from './util/encode.js';
export * from './util/factoryFrom.js';
export * from './util/parseRelativeTime.js';
export * from './util/PermissionsBitField.js';
export * from './util/promiseAllObject.js';
export * from './util/sqlJson.js';
Expand Down
2 changes: 0 additions & 2 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ model RestrictCaseData {
roleId String
clean Boolean @default(false)
undoRoles UndoRestrictRole[]
duration Int?
expiresAt DateTime? @db.Timestamptz(6)
}

Expand All @@ -101,7 +100,6 @@ model BanCaseData {
id Int @id
case Case @relation(fields: [id], references: [id], onDelete: Cascade)
deleteMessageDays Int?
duration Int?
expiresAt DateTime? @db.Timestamptz(6)
}

Expand Down
72 changes: 66 additions & 6 deletions services/interactions/src/handlers/punishments.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import {
INJECTION_TOKENS,
UserActionValidatorFactory,
parseRelativeTime,
type IRestrictModAction,
type RestrictCaseCreateData,
} from '@automoderator/core';
import { API, MessageFlags } from '@discordjs/core';
import {
API,
ApplicationCommandOptionType,
ApplicationCommandType,
MessageFlags,
PermissionFlagsBits,
} from '@discordjs/core';
import { inject, injectable } from 'inversify';
import { InteractionsService, type CommandHandler, type Handler } from '../interactions.js';

Expand All @@ -19,7 +26,48 @@ export default class Punishments implements Handler {

public register() {
this.interactions.register({
// TODO: Args
interactions: [
{
name: 'restrict',
description: 'Restrict a user (assign a special, manually configured role to them)',
type: ApplicationCommandType.ChatInput,
dm_permission: false,
default_member_permissions: String(PermissionFlagsBits.ModerateMembers),
options: [
{
name: 'target',
description: 'The user to restrict',
type: ApplicationCommandOptionType.User,
required: true,
},
{
name: 'role',
description: 'The role to assign to the user',
type: ApplicationCommandOptionType.Role,
required: true,
},
{
name: 'reason',
description: 'The reason for restricting the user',
type: ApplicationCommandOptionType.String,
required: false,
},
{
name: 'clean',
description: "Whether or not to remove the other user's roles for the duration of this action",
type: ApplicationCommandOptionType.Boolean,
required: false,
},
{
name: 'duration',
description: 'How long this action should last for',
type: ApplicationCommandOptionType.String,
required: false,
autocomplete: true,
},
],
},
],
commands: [['restrict:none:none', this.handleRestrict]],
});
}
Expand All @@ -41,16 +89,28 @@ export default class Punishments implements Handler {
});
}

let duration = null;
const durationStr = options.getString('duration');
if (durationStr) {
const parsed = parseRelativeTime(durationStr);
if (!parsed.ok) {
return this.api.interactions.reply(interaction.id, interaction.token, {
content: `Failed to parse provided duration: ${parsed.error}`,
flags: MessageFlags.Ephemeral,
});
}

duration = parsed.value;
}

const data: RestrictCaseCreateData = {
guildId: interaction.guild_id!,
modId: interaction.member!.user.id,
reason: options.getString('reason'),
targetId: target.id,
clean: options.getBoolean('clean', true),
roleId: options.getRole('role')!.id,
// TODO: Support duration
duration: null,
expiresAt: null,
roleId: options.getRole('role', true).id,
expiresAt: duration ? new Date(Date.now() + duration) : null,
};

const cs = await this.action.execute(data);
Expand Down
8 changes: 4 additions & 4 deletions services/interactions/src/interactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export type CommandHandler = (

export type ComponentHandler = (interaction: APIMessageComponentInteraction, args: string[]) => Promise<void>;

// [command]:autocompleteName
// [command]:argName
export type AutocompleteIdentifier = `${CommandIdentifier}:${string}`;

export type AutocompleteHandler = (
Expand All @@ -48,7 +48,7 @@ export interface RegisterOptions {
autocomplete?: [AutocompleteIdentifier, AutocompleteHandler][];
commands?: [CommandIdentifier, CommandHandler][];
components?: [string, ComponentHandler][];
interaction?: RESTPostAPIApplicationCommandsJSONBody;
interactions?: RESTPostAPIApplicationCommandsJSONBody[];
modals?: [string, ModalHandler][];
}

Expand Down Expand Up @@ -170,8 +170,8 @@ export class InteractionsService {
}

public register(options: RegisterOptions): void {
if (options.interaction) {
this.interactions.push(options.interaction);
if (options.interactions) {
this.interactions.push(...options.interactions);
}

if (options.commands?.length) {
Expand Down

0 comments on commit 9626f15

Please sign in to comment.