Skip to content

Feature: IntroductionWatch & AntiScam & Modern Edit/Delete Tracking - #407

Open
SimplyJpk wants to merge 15 commits into
masterfrom
feat/intro-watch
Open

SimplyJpk wants to merge 15 commits into
masterfrom
feat/intro-watch

Conversation

@SimplyJpk

Copy link
Copy Markdown
Member

Introduces a couple small changes as QOL and improve some moderation.

  1. IntroductionWatch: All it does is keep a message it controls as latest message in introduction channel. Attempts to give a user who hasn't read any rules or doesn't know where to post some information.
image

When a user posts, a timer starts, after 2 minutes the bot deletes its previous message and creates another. I've seen a couple bots do similar stuff to this, but I also included reminder not to ask people to DM or advertise with links to help channel and rules.

  1. QOL, mostly around historic message watching
image image image

The main idea here is to surface more information, when I previously created the last version of this. Nicknames were not really different from username, forum/threads didn't exist and discord didn't trigger message edits when someone posted a new message and it included an image.

The latest changes tries to only show edits when there is an actual edit, not just some slight modification to the snowflake by discord because of some other detail. Also includes the users nickanme/username and id so if users change their name, we can still search for these results.

  1. AntiScam
    Very small feature, Wick isn't doing a good enough job, so instead we're trying to more aggressively catch the 4x image phishes. The bot is watching messages, if a message has 4 images and they post another message in another channel with 4 images, it mutes them for 24 hours, and deletes the posts.

Gives us a chance to confirm/ban, and tries to reduce the number of times any of us type "image spam scam"

Note

This PR summary was generated with Copilot and reviewed/edited by @SimplyJpk.
It appears accurate but may not cover every change.

This pull request introduces several improvements to the development environment and adds comprehensive tests for key moderation and server features. The most important changes are summarized below.

Development environment enhancements:

  • Added a recommended C# extension (ms-dotnettools.csharp) to .vscode/extensions.json to ensure a consistent development setup.
  • Updated .editorconfig to enforce consistent code style across all files, including line endings, indentation, charset, and whitespace trimming. Also set specific indentation for .json files.
  • Improved .vscode/launch.json and .vscode/tasks.json to build and run the bot using .NET 8, set up environment variables for compatibility, add pre-launch checks for required settings, and provide tasks for building, testing, publishing, watching, and starting the database. [1] [2] [3]

Test coverage for moderation and server logic:

  • Added ImageSpamTrackerTests covering spam detection logic, attachment shape matching, and registry expiry in DiscordBot.Tests/Services/ImageSpamTrackerTests.cs.
  • Added AuditLogCardsTests for card generation, text fitting, and message formatting in DiscordBot.Tests/Services/AuditLogCardsTests.cs.
  • Added IntroductionPromptScheduleTests for scheduling and timing logic in DiscordBot.Tests/Services/IntroductionPromptScheduleTests.cs.

- New IntroductionWatch section (Enabled=false, DelayMinutes=5) with a
  validation warning when enabled and DelayMinutes < 1
- IntroductionPromptSchedule: thread-safe trailing debounce, delay clamped
  to at least 1 minute
- Posts a Components V2 prompt in Introductions once the channel has been
  quiet for DelayMinutes after a human message, then deletes the old prompt
- Skips posting when the latest message is already the prompt
- On startup finds the existing prompt in recent history and removes
  older duplicates
- Prompt is sent with no allowed mentions; off unless IntroductionWatch.Enabled
- Dev configmap enables IntroductionWatch with a 1 minute delay
- Add Introduction Prompt row to docs/features.md
…T 8 support

Fixes some issues around running tasks through vscode and versions being required. Also updates the unsupported netcoreapp2.1 to 8.0 in launch config. Also use integrated terminal so that colours can be seen in terminal
…entity

- Add ILoggingService.LogComponentsToChannel (CV2, optional files, no pings)
- Add AuditCard builder that keeps card text within Discord's 4000-char limit
- Deleted-message cards show avatar, names, user ID, channel, attachments, replies and forwards
- Log deletions by users who left; uncached deletes no longer download the channel
- Log bulk deletes as one card grouped by author
- Classify message updates so unfurls, pins and flag changes no longer log as edits
- Edit cards show before/after text and attachment changes; uncached edits show the new text
- Log thread and forum post deletions with owner, tags, starter post and who deleted it
- Document the audit log cards and the optional View Audit Log permission
- Second message with exactly 4 images within 15 minutes deletes the user's matching messages and times them out
- Report card lists the messages and re-uploads the images so moderators can check for false positives
- Exempt bots, webhooks, admins, Manage Messages and the Moderator role; forwards are checked too
- Audit log skips messages the guard deleted, since the report already covers them
- ImageSpamGuard settings (off by default; enabled in k8s dev)
# Conflicts:
#	DiscordBot.Tests/Settings/BotSettingsValidationTests.cs
Copilot AI balanced review requested due to automatic review settings October 25, 2026 08:55
@github-actions

Copy link
Copy Markdown

🚀 Deploy this PR

Code-only changes

  1. Make sure the udc-bot-dev ArgoCD app target revision is set to master.
  2. Go to the Deploy to Dev workflow and click Run workflow with this PR number.

Manifest changes (e.g. new services in k8s/dev/)

  1. Comment /build on this PR to build the Docker image (without deploying to master).
  2. Once the build succeeds, update the image tag in k8s/dev/bot.yaml on your branch with the SHA from the build comment, then push.
  3. In ArgoCD, switch the udc-bot-dev app target revision from master to your branch (App Details → Source → Edit → Save).
  4. ArgoCD will sync your manifest changes + new image. Test your changes.
  5. When done, switch ArgoCD target revision back to master.

var extension = Path.GetExtension(attachment.Filename);
if (extension.Length is 0 or > 6)
extension = ".png";
files.Add(new FileAttachment(new MemoryStream(bytes), $"spam-{files.Count + 1}{extension.ToLowerInvariant()}"));
Comment thread DiscordBot/Services/Server/AuditLogService.cs Fixed
Comment thread DiscordBot/Services/Server/IntroductionWatcherService.cs Fixed
}
finally
{
foreach (var file in files)
Comment thread DiscordBot/Services/Server/IntroductionWatcherService.cs Fixed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Build compatibility, moderation safeguards, and introduction-watcher failure recovery need correction before approval.

5 open issues
What changed in this PR

Adds introduction prompts and image-spam moderation, while modernizing the bot’s audit logs to give moderators clearer message and thread history.

Changes:

  • Adds configurable introduction reminders and image-spam detection with timeouts, deletions, and reports.
  • Replaces message audit embeds with richer cards and filters non-edit updates.
  • Adds focused tests, deployment settings, and development-tooling updates.
File Description
k8s/​prod/​bot-config.yaml Enables introduction prompts and spam protection in production.
k8s/​dev/​bot-config.yaml Enables both features in development.
docs/​features.md Documents moderation features, settings, and permissions.
DiscordBot/​Settings/​Settings.example.json Adds disabled-by-default example settings.
DiscordBot/​Settings/​Deserialized/​Settings.cs Defines and validates new feature settings.
DiscordBot/​Services/​Server/​MessageEditClassifier.cs Distinguishes content and attachment edits from other updates.
DiscordBot/​Services/​Server/​IntroductionWatcherService.cs Posts and recovers introduction prompts.
DiscordBot/​Services/​Server/​IntroductionPromptSchedule.cs Implements thread-safe prompt scheduling.
DiscordBot/​Services/​Server/​AuditLogService.cs Handles richer message and thread audit events.
DiscordBot/​Services/​Server/​AuditLogCards.cs Builds size-limited audit and moderation cards.
DiscordBot/​Services/​Moderation/​ImageSpamTracker.cs Tracks repeated image posts and attachment shapes.
DiscordBot/​Services/​Moderation/​ImageSpamGuardService.cs Applies moderation actions and reports image spam.
DiscordBot/​Services/​Moderation/​BotDeletionRegistry.cs Suppresses duplicate deletion reports.
DiscordBot/​Services/​LoggingService.cs Sends component cards and files without pings.
DiscordBot/​Program.cs Registers and starts the new services.
DiscordBot/​DiscordBot.csproj Adds a .NET 10 framework target.
DiscordBot.Tests/​Settings/​BotSettingsValidationTests.cs Tests new settings validation.
DiscordBot.Tests/​Services/​MessageEditClassifierTests.cs Tests edit classification and duplicate suppression.
DiscordBot.Tests/​Services/​IntroductionPromptScheduleTests.cs Tests scheduling and delay boundaries.
DiscordBot.Tests/​Services/​ImageSpamTrackerTests.cs Tests detection, attachment matching, and registry expiry.
DiscordBot.Tests/​Services/​AuditLogCardsTests.cs Tests card formatting, content limits, and galleries.
.vscode/​tasks.json Updates build, test, run, and database tasks.
.vscode/​launch.json Updates debugging paths and startup checks.
.vscode/​extensions.json Recommends the C# extension.
.editorconfig Standardizes whitespace, encoding, and indentation.

Review effort: Balanced

Comment thread DiscordBot/DiscordBot.csproj Outdated
public static bool Matches(IReadOnlyList<AttachmentShape> attachments, IReadOnlyList<AttachmentShape>? forwarded, int imageCount)
{
var set = attachments.Count > 0 ? attachments : forwarded ?? [];
return set.Count == imageCount && set.All(IsImage);
Comment on lines +111 to +112
await _loggingService.LogChannelAndFile(
$"[{ServiceName}] Failed to post the introduction prompt: {e.Message}", ExtendedLogSeverity.Warning);
Comment thread DiscordBot/Services/Moderation/ImageSpamTracker.cs Outdated
Comment on lines +109 to +112
catch (Exception e) when (e is not OperationCanceledException)
{
await _loggingService.LogChannelAndFile(
$"[{ServiceName}] Failed to post the introduction prompt: {e.Message}", ExtendedLogSeverity.Warning);
…spam guard

- Trigger only when scam-shaped posts span at least two distinct channels
- Never match when ImageCount is below 1, so text-only messages cannot trigger
- Clarify the ImageCount warning and update the feature docs
… stopping the loop

- Add IntroductionPromptSchedule.Retry, which re-arms without overriding a newer Touch
- Retry transient post failures after one minute; skip retries on 4xx errors
- Fall back to console when channel/file warning logging throws
Comment on lines +136 to +139
catch (Exception e)
{
LoggingService.LogToConsole($"{message} (could not log to channel/file: {e.Message})", ExtendedLogSeverity.Warning);
}
Comment on lines +205 to +208
catch (Exception e)
{
await LogWarningAsync($"Failed to delete old introduction prompt {messageId}: {e.Message}");
}

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants