Skip to content

feat(moderation): implementar DiscordModerationAdapter para integração com Discord #211

@danielhe4rt

Description

@danielhe4rt

Contexto

O sistema de moderação possui uma arquitetura de platform adapters que permite executar ações de moderação em múltiplas plataformas. Atualmente, apenas o WebModerationAdapter está implementado (suspensão/ban na plataforma web). O Discord é a principal plataforma da comunidade e precisa de um adapter dedicado.

Objetivo

Implementar DiscordModerationAdapter que execute ações de moderação (warn, mute, kick, ban) via Discord REST API e notifique os usuários por DM.

Interfaces Envolvidas

ModerationPlatformContract

// app-modules/moderation/src/Platform/ModerationPlatformContract.php

interface ModerationPlatformContract
{
public function platform(): Platform;
public function ingest(array $rawPayload): ModerationContentDTO;
public function execute(ModerationAction $action, User $target): ExecutionResultDTO;
public function notify(User $user, string $message, array $context = []): void;
public function supports(): array; // ActionType[]
public function resolveUser(string $externalId): ?User;
}

ExecutionResultDTO

// app-modules/moderation/src/DTOs/ExecutionResultDTO.php

final readonly class ExecutionResultDTO
{
public Platform $platform;
public bool $success;
public ?string $error;
public array $platformResponse;

    public static function success(Platform $platform, array $response = []): self;
    public static function failure(Platform $platform, string $error, array $response = []): self;
}

Como o adapter é chamado

// app-modules/moderation/src/Enforcement/ExecuteAction.php

public function handle(): void
{
$platforms = app()->tagged('moderation.platforms');

    foreach ($platforms as $adapter) {
        if (in_array($adapter->platform()->value, $this->action->target_platforms, true)) {
            $results[] = $adapter->execute($this->action, $this->target);
        }
    }
    // salva resultados, atualiza case, dispara evento
}

Implementação Referência

O WebModerationAdapter (app-modules/moderation/src/Platform/WebModerationAdapter.php) serve como referência:

  • Retorna Platform::Web no platform()
  • Suporta: Warn, Suspend, Ban, ContentRemove
  • Usa match no ActionType pra executar a ação correta
  • Retorna ExecutionResultDTO::success() ou ::failure()
  • Notifica via Laravel Notification

Passo a Passo

1. Criar o adapter

Arquivo: app-modules/bot-discord/src/Moderation/DiscordModerationAdapter.php

class DiscordModerationAdapter implements ModerationPlatformContract
{
public function platform(): Platform
{
return Platform::Discord;
}

    public function supports(): array
    {
        return [ActionType::Warn, ActionType::Mute, ActionType::Kick, ActionType::Ban];
    }
}

2. Implementar execute()

Usar a Discord REST API via Http facade do Laravel:

ActionType Discord API Endpoint
Warn Apenas DM pro user POST /users/@me/channelsPOST /channels/{id}/messages
Mute Timeout (communication_disabled_until) PATCH /guilds/{guild}/members/{user} com communication_disabled_until
Kick Kick member DELETE /guilds/{guild}/members/{user}
Ban Ban member PUT /guilds/{guild}/bans/{user} com delete_message_seconds

Headers necessários: Authorization: Bot {token} (token do bot do Discord)

3. Implementar notify()

Enviar DM embed pro usuário com detalhes da ação:

  1. Criar DM channel: POST /users/@me/channels com recipient_id
  2. Enviar mensagem: POST /channels/{channel_id}/messages com embed formatado

O embed deve conter: tipo da ação, motivo, duração (se aplicável), e link pra appeal.

4. Implementar resolveUser()

Mapear Discord ID externo → User interno usando a tabela external_identities.

5. Implementar ingest()

Transformar payload de mensagem do Discord em ModerationContentDTO.

6. Registrar o adapter

Arquivo: app-modules/bot-discord/src/BotDiscordServiceProvider.php

$this->app->singleton(DiscordModerationAdapter::class);
$this->app->tag(DiscordModerationAdapter::class, 'moderation.platforms');

7. Tratar durations

Duração Mute (timeout) Ban
24h 24 horas Ban + delete 24h messages
7d 7 dias (max timeout) Ban + delete 7d messages
30d N/A (max 28 dias) Ban permanente
permanent N/A Ban permanente

Discord timeout máximo: 28 dias. Pra durações maiores, considerar ban temporário com agendamento de unban.

8. Testes

  • Teste de mute via API (mock Http)
  • Teste de kick via API
  • Teste de ban via API
  • Teste de warn (DM only)
  • Teste de notify (DM embed)
  • Teste de resolveUser via external_identities
  • Teste de ingest de payload Discord
  • Teste de duração > 28 dias (edge case)
  • Teste de falha da API (rate limit, permissão insuficiente)

Arquivos Relacionados

Arquivo Propósito
app-modules/moderation/src/Platform/ModerationPlatformContract.php Contrato a implementar
app-modules/moderation/src/Platform/WebModerationAdapter.php Implementação de referência
app-modules/moderation/src/ModerationServiceProvider.php Padrão de registro (singleton + tag)
app-modules/moderation/src/Enforcement/ExecuteAction.php Job que chama os adapters
app-modules/moderation/src/DTOs/ExecutionResultDTO.php DTO de resultado
app-modules/moderation/src/DTOs/ModerationContentDTO.php DTO de conteúdo
app-modules/bot-discord/src/BotDiscordServiceProvider.php ServiceProvider do bot
app-modules/bot-discord/config/bot-discord.php Config do Discord (channels, roles)

Critérios de Aceite

  • DiscordModerationAdapter implementa ModerationPlatformContract
  • Warn envia DM embed pro usuário
  • Mute aplica timeout via API
  • Kick remove membro via API
  • Ban aplica ban via API com delete de mensagens
  • Falhas da API retornam ExecutionResultDTO::failure() sem crashar
  • Adapter registrado e taggeado no ServiceProvider
  • Testes cobrindo todos os action types + edge cases
  • Rate limiting respeitado (429 handling)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions