Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
176 changes: 150 additions & 26 deletions DiscordBot/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import logging
import re
import requests
from report import Report
from report import Report, AbuseType, MisinfoCategory, HealthCategory, NewsCategory
import pdb

# Set up logging to the console
Expand Down Expand Up @@ -34,6 +34,7 @@ def __init__(self):
self.group_num = None
self.mod_channels = {} # Map from guild to the mod channel id for that guild
self.reports = {} # Map from user IDs to the state of their report
self.active_mod_flow = None # State for the current moderation flow

async def on_ready(self):
print(f'{self.user.name} has connected to Discord! It is these guilds:')
Expand Down Expand Up @@ -99,33 +100,156 @@ async def handle_dm(self, message):
self.reports.pop(author_id)

async def handle_channel_message(self, message):
# Only handle messages sent in the "group-#" channel
if not message.channel.name == f'group-{self.group_num}':
# Only handle messages sent in the "group-#-mod" channel
if message.channel.name == f'group-{self.group_num}-mod':
await self.handle_mod_channel_message(message)
elif message.channel.name == f'group-{self.group_num}':
return

# Forward the message to the mod channel
mod_channel = self.mod_channels[message.guild.id]
await mod_channel.send(f'Forwarded message:\n{message.author.name}: "{message.content}"')
scores = self.eval_text(message.content)
await mod_channel.send(self.code_format(scores))


def eval_text(self, message):
''''
TODO: Once you know how you want to evaluate messages in your channel,
insert your code here! This will primarily be used in Milestone 3.
'''
return message


def code_format(self, text):
''''
TODO: Once you know how you want to show that a message has been
evaluated, insert your code here for formatting the string to be
shown in the mod channel.
'''
return "Evaluated: '" + text+ "'"

async def start_moderation_flow(self, report_type, report_content, message_author, message_link=None):
# Determine the initial step based on report type
if report_type.startswith('ADVERTISING MISINFO'):
initial_step = 'advertising_done'
elif report_type.startswith('MISINFORMATION') or report_type.startswith('HEALTH MISINFO') or report_type.startswith('NEWS MISINFO'):
initial_step = 'danger_level'
else:
initial_step = 'default_done'
self.active_mod_flow = {
'step': initial_step,
'report_type': report_type,
'report_content': report_content,
'message_author': message_author,
'message_link': message_link,
'context': {}
}
mod_channel = None
for channel in self.mod_channels.values():
mod_channel = channel
break
if mod_channel:
await mod_channel.send(f"A new report has been submitted:\nType: {report_type}\nContent: {report_content}\nReported user: {message_author}")
if initial_step == 'danger_level':
await mod_channel.send("What is the level of danger for this report?\n• LOW\n• MEDIUM\n• HIGH")
elif initial_step == 'advertising_done':
await mod_channel.send("Report sent to advertising team. No further action required.")
self.active_mod_flow = None
elif initial_step == 'default_done':
# Just show the report, do not prompt for reply
self.active_mod_flow = None
else:
await self.prompt_next_moderation_step(mod_channel)

async def notify_reported_user(self, user_name, guild, outcome, explanation=None):
# Find the user object by name in the guild
user = discord.utils.get(guild.members, name=user_name)
if user:
try:
msg = f"Your message was reviewed by moderators. Outcome: {outcome}."
if explanation:
msg += f"\nReason: {explanation}"
msg += "\nIf you believe this was a mistake, you may reply to this message to appeal."
await user.send(msg)
except Exception as e:
print(f"Failed to DM user {user_name}: {e}")

async def handle_mod_channel_message(self, message):
if not self.active_mod_flow:
return
step = self.active_mod_flow['step']
ctx = self.active_mod_flow['context']
content = message.content.strip().lower()
mod_channel = message.channel
report_type = self.active_mod_flow['report_type']
report_content = self.active_mod_flow['report_content']
reported_user_name = self.active_mod_flow['message_author']
guild = mod_channel.guild if hasattr(mod_channel, 'guild') else None

# Misinformation moderation flow
if step == 'advertising_done':
# Already handled
self.active_mod_flow = None
return
if step == 'danger_level':
if content not in ['low', 'medium', 'high']:
await mod_channel.send("Invalid option. Please choose:\n• LOW\n• MEDIUM\n• HIGH")
return
ctx['danger_level'] = content
if content == 'low':
await mod_channel.send("Flag post as low danger. After claim is investigated, what action should be taken on post?\n• DO NOT RECOMMEND\n• FLAG AS UNPROVEN")
self.active_mod_flow['step'] = 'low_action_on_post'
return
elif content == 'medium':
await mod_channel.send("Flag post as medium danger. After claim is investigated, what action should be taken on post?\n• REMOVE\n• RAISE\n• REPORT TO AUTHORITIES")
self.active_mod_flow['step'] = 'medium_action_on_post'
return
elif content == 'high':
await mod_channel.send("Flag post as high danger. What emergency action should be taken based on post?\n• REMOVE\n• RAISE\n• REPORT TO AUTHORITIES")
self.active_mod_flow['step'] = 'high_action_on_post'
return
if step == 'low_action_on_post':
if content == 'do not recommend':
await mod_channel.send("Post will not be recommended. Action recorded. (Update algorithm so post is not recommended.)")
await self.notify_reported_user(reported_user_name, guild, outcome="Post not recommended.")
self.active_mod_flow = None
return
elif content == 'flag as unproven':
await mod_channel.send("Post will be flagged as unproven/non-scientific. Please add explanation for why post is being flagged.")
self.active_mod_flow['step'] = 'flag_explanation'
return
else:
await mod_channel.send("Invalid option. Please choose:\n• DO NOT RECOMMEND\n• FLAG AS UNPROVEN")
return
if step == 'flag_explanation':
await mod_channel.send(f"Explanation recorded: {message.content}\nFlagged post as not proven.")
await self.notify_reported_user(reported_user_name, guild, outcome="Post flagged as unproven/non-scientific.", explanation=message.content)
self.active_mod_flow = None
return
if step == 'medium_action_on_post' or step == 'high_action_on_post':
if content == 'remove':
await mod_channel.send("Post will be removed. Please add explanation for why post is being removed.")
self.active_mod_flow['step'] = 'remove_explanation'
return
elif content == 'raise':
await mod_channel.send("Raising to higher level moderator. Report sent to higher level moderators.")
self.active_mod_flow = None
return
elif content == 'report to authorities':
await mod_channel.send("Reporting to authorities. Report sent to authorities.")
self.active_mod_flow = None
return
else:
await mod_channel.send("Invalid option. Please choose:\n• REMOVE\n• RAISE\n• REPORT TO AUTHORITIES")
return
if step == 'remove_explanation':
await mod_channel.send(f"Explanation recorded: {message.content}\nPost removed. What action should be taken on the creator of the post?\n• RECORD INCIDENT\n• TEMPORARILY MUTE\n• REMOVE USER")
ctx['remove_explanation'] = message.content
await self.notify_reported_user(
reported_user_name,
guild,
outcome="Post removed.",
explanation=ctx.get('remove_explanation', '')
)
self.active_mod_flow['step'] = 'action_on_user'
return
if step == 'action_on_user':
if content == 'record incident':
await mod_channel.send("Incident recorded for internal use. (Add to internal incident count for user.)")
self.active_mod_flow = None
return
elif content == 'temporarily mute':
await mod_channel.send("User will be muted for 24 hours.")
self.active_mod_flow = None
return
elif content == 'remove user':
await mod_channel.send("User will be removed.")
self.active_mod_flow = None
return
else:
await mod_channel.send("Invalid option. Please choose:\n• RECORD INCIDENT\n• TEMPORARILY MUTE\n• REMOVE USER")
return

async def prompt_next_moderation_step(self, mod_channel):
await mod_channel.send("Moderator, please review the report and respond with your decision.")

client = ModBot()
client.run(discord_token)
Loading