Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
5a86ff9
fix(docker): update postgres volume mount path for PG 18 compatibilit…
YuriSouzaDev May 3, 2026
9b81210
Merge branch '4.x' of https://github.com/he4rt/heartdevs.com into 4.x
YuriSouzaDev May 3, 2026
00c3721
Merge branch '4.x' of https://github.com/he4rt/heartdevs.com into 4.x
YuriSouzaDev May 4, 2026
754648e
Merge branch '4.x' of https://github.com/he4rt/heartdevs.com into 4.x
YuriSouzaDev May 6, 2026
59ac75b
feat(config): adicionar token do Discord e chave da OpenAI nas config…
YuriSouzaDev May 7, 2026
5c0160f
feat(moderation): implementar JsonSerializable e aceitar autor por pa…
YuriSouzaDev May 7, 2026
d67bd42
feat(moderation): priorizar regras manuais e preservar ação sugerida …
YuriSouzaDev May 7, 2026
5765bd1
test(moderation): atualizar testes da pipeline de classificação com n…
YuriSouzaDev May 7, 2026
abc4fd1
feat(bot-discord): implementar DiscordModerationAdapter com mute, kic…
YuriSouzaDev May 7, 2026
6ca0fd9
feat(moderation): adicionar traduções de DM do Discord para ações de …
YuriSouzaDev May 7, 2026
315f9e2
feat(bot-discord): integrar pipeline de moderação automática ao event…
YuriSouzaDev May 7, 2026
b6a61c0
test(bot-discord): adicionar testes de feature do DiscordModerationAd…
YuriSouzaDev May 7, 2026
3a22a0b
chore: registrar HubPanelProvider e adicionar dependência he4rt/hub
YuriSouzaDev May 7, 2026
9c1a942
feat(database): adicionar seeder do servidor Discord pessoal para des…
YuriSouzaDev May 7, 2026
94c9a88
fix(bot-discord): usar dispatch assíncrono no ExecuteAction para não …
YuriSouzaDev May 7, 2026
6a2c84e
fix(bot-discord): centralizar cliente HTTP com timeout explícito de 1…
YuriSouzaDev May 7, 2026
cdef161
fix(moderation): substituir instanciação desnecessária de User no Ing…
YuriSouzaDev May 7, 2026
6520f45
fix(moderation): adicionar type guard instanceof User no fromPlatform…
YuriSouzaDev May 7, 2026
a8cda07
fix(moderation): corrigir expectativa de status no RouteDecisionTest …
YuriSouzaDev May 7, 2026
182b24a
fix(bot-discord): tratar channelID em branco no DiscordModerationAdap…
YuriSouzaDev May 7, 2026
82f9558
fix(bot-discord): remocao de dependencia adicionada precocemente
YuriSouzaDev May 8, 2026
5e18561
chore: remocao de depedencia prematura do he4rt/hub
YuriSouzaDev May 8, 2026
2517bbd
fix(moderation): adicionar anotação de tipo de retorno para jsonSeria…
YuriSouzaDev May 8, 2026
4f5705c
fix(moderacao): alinhar escalada de penalidades aos testes
YuriSouzaDev May 8, 2026
2285bd5
test(moderacao): ajustar plataforma invalida no teste
YuriSouzaDev May 8, 2026
f37d6a6
fix(bot-discord): refatorar PersonalDiscordServerSeeder para reutiliz…
YuriSouzaDev May 9, 2026
74dc714
fix(moderacao): preservar acao de regra no roteamento
YuriSouzaDev May 9, 2026
008c6d6
fix(bot-discord): alinhar execucao de moderacao e requests
YuriSouzaDev May 9, 2026
510b84f
Merge branch '4.x' into feature/discord-bot-moderation
YuriSouzaDev May 9, 2026
ebd1e34
fix(panel): corrigir namespace do Dashboard
YuriSouzaDev May 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions PR.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
## Summary

- Ajusta a escalada de penalidades para alinhar com as regras esperadas pelos testes.
- Corrige o teste de execucao para validar plataforma realmente nao suportada.

## Changes

- `app-modules/moderation/src/Classification/Actions/Advisors/HistoryBasedPenaltyAdvisor.php`
- `app-modules/moderation/tests/Feature/Enforcement/ExecuteActionTest.php`

## Testing

- `vendor/bin/pest --ci --parallel`

## Notes

- O teste "skips platforms not in target list" foi ajustado porque o Discord agora e uma plataforma registrada; antes, nao existia adapter Discord e o teste passava mesmo com `discord` na lista. Agora a lista usa `skype` (plataforma inexistente) para garantir que a execucao seja realmente ignorada.
8 changes: 6 additions & 2 deletions app-modules/bot-discord/src/BotDiscordServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,20 @@

namespace He4rt\BotDiscord;

use He4rt\BotDiscord\Moderation\DiscordModerationAdapter;
use Laracord\Laracord;
use Laracord\LaracordServiceProvider;

class BotDiscordServiceProvider extends LaracordServiceProvider
{
public function register(): void
{
parent::register();

$this->mergeConfigFrom(__DIR__.'/../config/bot-discord.php', 'bot-discord');

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

parent::register();
}

public function boot(): void
Expand Down
53 changes: 51 additions & 2 deletions app-modules/bot-discord/src/Events/MessageReceivedEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,22 @@

namespace He4rt\BotDiscord\Events;

use Discord\Discord;
use Discord\Parts\Channel\Message;
use Discord\WebSockets\Event as Events;
use He4rt\Activity\Message\Actions\NewMessage;
use He4rt\Activity\Message\DTOs\NewMessageDTO;
use He4rt\BotDiscord\Moderation\DiscordModerationAdapter;
use He4rt\Identity\ExternalIdentity\Enums\IdentityProvider;
use He4rt\Identity\ExternalIdentity\Models\ExternalIdentity;
use He4rt\Identity\Tenant\Models\Tenant;
use He4rt\Moderation\Classification\Jobs\ClassifyContent;
use He4rt\Moderation\Classification\Jobs\IngestContent;
use He4rt\Moderation\Classification\Jobs\RouteDecision;
use He4rt\Moderation\Enforcement\ExecuteAction;
use He4rt\Moderation\Enforcement\ModerationAction;
use He4rt\Moderation\Enums\ActionType;
use He4rt\Moderation\Enums\CaseSource;
use He4rt\Moderation\Enums\Platform;
use Laracord\Events\Event;
use Throwable;

Expand All @@ -24,7 +32,7 @@ class MessageReceivedEvent extends Event
*/
protected $handler = Events::MESSAGE_CREATE;

public function handle(Message $message, Discord $discord): void
public function handle(Message $message): void
{
if ($message->author->bot) {
return;
Expand All @@ -36,6 +44,11 @@ public function handle(Message $message, Discord $discord): void
->where('external_account_id', (string) $message->guild_id)
->firstOrFail();

$authorIdentity = ExternalIdentity::query()
->where('provider', IdentityProvider::Discord)
->where('external_account_id', (string) $message->user_id)
->first();

resolve(NewMessage::class)->persist(new NewMessageDTO(
tenantId: $tenantProvider->tenant_id,
provider: IdentityProvider::Discord,
Expand All @@ -47,6 +60,42 @@ public function handle(Message $message, Discord $discord): void
sentAt: $message->timestamp->toDateTimeImmutable()
));

$content = DiscordModerationAdapter::make()->ingest([
'message_id' => $message->id,
'author_id' => $message->user_id,
'content' => $message->content,
'channel_id' => $message->channel_id,
'guild_id' => (string) $message->guild_id,
'username' => $message->author->username,
'attachments' => [],
'tenant_id' => (string) $tenantProvider->tenant_id,
'author' => $authorIdentity?->user,
]);

$case = new IngestContent($content, CaseSource::AutoDetect)->handle();
$this->logger()->info('[Moderation] Case created: '.$case->id.' status='.$case->status->value);
new ClassifyContent($case)->handle();
$case->refresh();
$this->logger()->info('[Moderation] After classify: scores='.json_encode($case->ai_scores).' status='.$case->status->value);
new RouteDecision($case)->handle();
$case->refresh();
$this->logger()->info('[Moderation] After route: status='.$case->status->value.' priority='.$case->priority);

if ($case->suggested_action && $case->author) {
$action = ModerationAction::query()->create([
'case_id' => $case->id,
'moderator_id' => null,
'action_type' => $case->suggested_action,
'target_platforms' => [Platform::Discord->value],
'duration' => $case->suggested_action === ActionType::Ban ? 'permanent' : null,
'reason' => 'Auto-moderation triggered by Discord message classification.',
'automated' => true,
'tenant_id' => $case->tenant_id,
]);

dispatch(new ExecuteAction($action, $case->author));
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

} catch (Throwable $throwable) {
$this->logger()->error(
sprintf('%s | File: %s | Line: %s | Trace: %s', $throwable->getMessage(), $throwable->getFile(), $throwable->getLine(), $throwable->getTraceAsString()),
Expand Down
Loading