main.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. import os
  2. from dotenv import load_dotenv
  3. import discord
  4. from discord.ext import commands
  5. from discord.commands import Option
  6. from discord.commands import slash_command
  7. from datetime import datetime
  8. import configparser
  9. import mysql.connector
  10. intents = discord.Intents.default()
  11. intents.message_content = True
  12. intents.members = True
  13. intents.guilds = True
  14. intents.reactions = True
  15. client = discord.Client(intents=intents)
  16. #---------------------------------#
  17. #Load .env file
  18. load_dotenv()
  19. token = os.getenv("TOKEN")
  20. if token is None:
  21. raise ValueError("TOKEN not found in .env file")
  22. debug_guilds_up = []
  23. server_token = os.getenv("SERVER").split(",")
  24. for i in range(len(server_token)):
  25. debug_guilds_up.append(int(server_token[i]))
  26. dbhost = os.getenv("HOST")
  27. if dbhost is None:
  28. raise ValueError("HOST not found in .env file")
  29. dbname = os.getenv("NAME")
  30. if dbname is None:
  31. raise ValueError("NAME not found in .env file")
  32. dbpsswd = os.getenv("PASSWORD")
  33. if dbpsswd is None:
  34. raise ValueError("PASSWORD not found in .env file")
  35. dbdb = os.getenv("DATABASE")
  36. if dbdb is None:
  37. raise ValueError("DATABASE not found in .env file")
  38. #---------------------------------#
  39. #ConfigParser
  40. config = configparser.RawConfigParser()
  41. configFilePath = r'config.cfg'
  42. config.read_file(open(configFilePath))
  43. label_rules = config.get('Reactionroles Rules', 'label_rules')
  44. role_rules = config.get('Reactionroles Rules', 'rules_role')
  45. channel_log = config.get('Logs', 'channel_log')
  46. channel_banlog = config.get('Logs', 'ban_log')
  47. #---------------------------------#
  48. #Database initialization
  49. conn = mysql.connector.connect(
  50. host=dbhost,
  51. user=dbname,
  52. password=dbpsswd
  53. )
  54. cursor = conn.cursor()
  55. conn.database = dbdb
  56. cursor.execute("""
  57. CREATE TABLE IF NOT EXISTS User (
  58. id INT AUTO_INCREMENT PRIMARY KEY,
  59. userid BIGINT,
  60. discordname VARCHAR(100),
  61. roles INT
  62. )
  63. """)
  64. cursor.execute("""
  65. CREATE TABLE IF NOT EXISTS Warns (
  66. id INT AUTO_INCREMENT PRIMARY KEY,
  67. userid BIGINT,
  68. username VARCHAR(100),
  69. moderatorname VARCHAR(100),
  70. reason VARCHAR(250),
  71. date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  72. )
  73. """)
  74. cursor.execute("""
  75. CREATE TABLE IF NOT EXISTS Bans (
  76. id INT AUTO_INCREMENT PRIMARY KEY,
  77. userid BIGINT,
  78. username VARCHAR(100),
  79. moderatorname VARCHAR(100),
  80. reason VARCHAR(250),
  81. date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  82. )
  83. """)
  84. cursor.execute("""
  85. CREATE TABLE IF NOT EXISTS Unbans (
  86. id INT AUTO_INCREMENT PRIMARY KEY,
  87. userid BIGINT,
  88. username VARCHAR(100),
  89. moderatorname VARCHAR(100),
  90. reason VARCHAR(250),
  91. date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  92. )
  93. """
  94. )
  95. cursor.execute("""
  96. CREATE TABLE IF NOT EXISTS Kick (
  97. id INT AUTO_INCREMENT PRIMARY KEY,
  98. userid BIGINT,
  99. username VARCHAR(100),
  100. moderatorname VARCHAR(100),
  101. reason VARCHAR(250),
  102. date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  103. )
  104. """)
  105. #---------------------------------#
  106. #Initialize Bot
  107. bot = commands.Bot(
  108. command_prefix=commands.when_mentioned_or("!"),
  109. description="VicePD Bot",
  110. intents=intents,
  111. debug_guilds=debug_guilds_up if debug_guilds_up else None
  112. )
  113. #Loading Cogs
  114. async def load_extensions():
  115. cogs_dir = "./cogs"
  116. if bot.guilds:
  117. channel = discord.utils.get(bot.guilds[0].channels, id=int(channel_log))
  118. if not os.path.exists(cogs_dir):
  119. print(f"Cogs directory '{cogs_dir}' not found!")
  120. return
  121. for filename in os.listdir(cogs_dir):
  122. if filename.endswith(".py"):
  123. cog_list = os.path.splitext(filename)[0]
  124. try:
  125. bot.load_extension(f"cogs.{cog_list}")
  126. print(f"Loaded cog: {cog_list}")
  127. if bot.guilds and channel:
  128. await channel.send(f"Loaded Cogs: {cog_list}")
  129. except Exception as e:
  130. print(f"Failed to load cog {cog_list}: {e}")
  131. if bot.guilds and channel:
  132. await channel.send(f"Failed to load cog {cog_list}: {e}")
  133. class Admin(commands.Cog):
  134. def __init__(self, bot):
  135. self.bot = bot
  136. #---------------------------------#
  137. #Print in Log if error occurs
  138. @bot.event
  139. async def on_application_command_error(ctx, error):
  140. channel = discord.utils.get(ctx.guild.channels, id=int(channel_log))
  141. if channel:
  142. await channel.send(f"Error occurred: {str(error)}")
  143. #---------------------------------#
  144. #Bot Online Console
  145. @bot.event
  146. async def on_ready():
  147. print(f"{bot.user} is online")
  148. if bot.guilds:
  149. channel = discord.utils.get(bot.guilds[0].channels, id=int(channel_log))
  150. if channel:
  151. await channel.send(f"{bot.user} is online")
  152. bot.add_view(PersistentRoleView()) #loading reactionrole memory
  153. await load_extensions()
  154. print("Registered Slash-Commands:")
  155. for command in bot.pending_application_commands:
  156. print(f" - {command.name}")
  157. if bot.guilds and channel:
  158. await channel.send("Registered Slash-Commands:")
  159. await channel.send(f"- {command.name}")
  160. #---------------------------------------------------------------------------------------#
  161. #DONT Touch anything above this line, unless you know what you are doing!#
  162. #---------------------------------------------------------------------------------------#
  163. #_________________________________#
  164. #BAN SYSTEM
  165. #---------------------------------#
  166. ##Ban
  167. @bot.slash_command(name="ban", description="Ban a user from this Server")
  168. async def ban(
  169. ctx,
  170. user: Option(discord.User, description = "Select User", required=True), # type: ignore
  171. reason: Option(str, description = "Reason for the ban", default="No reason provided") # type: ignore
  172. ):
  173. if not ctx.author.guild_permissions.ban_members:
  174. await ctx.respond("Error: You don't have the permission to ban Members!", ephemeral=True)
  175. return
  176. if user == bot.user:
  177. await ctx.respond("Error: I can't ban myself!", ephemeral=True)
  178. return
  179. if user == ctx.author:
  180. await ctx.respond("Error: You can't ban yourself!", ephemeral=True)
  181. return
  182. channel= discord.utils.get(ctx.guild.channels, id = int(channel_banlog))
  183. embed = discord.Embed(
  184. title=f"Ban of **{user.name}**",
  185. description=f"User {user.mention} has been banned from the Server",
  186. color=discord.Color.red()
  187. )
  188. time = discord.utils.format_dt(datetime.now(), "f")
  189. embed.add_field(name="Ban Date", value=time, inline=False)
  190. embed.add_field(name="Moderator", value=f"{ctx.author}", inline=False)
  191. embed.add_field(name="Reason", value=reason, inline=False)
  192. embed.add_field(name="User ID", value=user.id)
  193. embed.set_thumbnail(url=user.display_avatar.url)
  194. embed.set_author(name="VicePD", icon_url="https://i.imgur.com/6QteFrg.png")
  195. embed.set_footer(text="VicePD - Bot | Made by BaumSplitter41")
  196. try:
  197. await ctx.guild.ban(user, reason=reason)
  198. await ctx.respond(f"User {user.mention} has been banned from this Server!", ephemeral=True)
  199. await channel.send(embed=embed)
  200. cursor.execute(
  201. "INSERT INTO Bans (userid, username, moderatorname, reason) VALUES (%s, %s, %s, %s)",
  202. (user.id, str(user), str(ctx.author), reason)
  203. )
  204. conn.commit()
  205. except discord.Forbidden:
  206. await ctx.respond("Error: I don't have permission to ban this user.", ephemeral=True)
  207. except discord.HTTPException as e:
  208. await ctx.respond(f"Error: Could not ban User {user.mention}. Reason: {e}", ephemeral=True)
  209. except Exception as e:
  210. await ctx.respond(f"Unexpected error: {e}", ephemeral=True)
  211. #---------------------------------#
  212. #Unban
  213. @bot.slash_command(name="unban", description="Unban a user from this Server")
  214. async def unban(
  215. ctx,
  216. user: Option(discord.User, description = "Insert User ID", required=True), # type: ignore
  217. reason: Option(str, description = "Reason for the unbanning", default="No reason provided") # type: ignore
  218. ):
  219. if not ctx.author.guild_permissions.ban_members:
  220. await ctx.respond("Error: You don't have the permission to unban Members!", ephemeral=True)
  221. return
  222. if user == bot.user:
  223. await ctx.respond("Error: I can't unban myself!", ephemeral=True)
  224. return
  225. if user == ctx.author:
  226. await ctx.respond("Error: You can't unban yourself!", ephemeral=True)
  227. return
  228. if user in ctx.guild.members:
  229. await ctx.respond("Error: This user is not banned!", ephemeral=True)
  230. return
  231. channel= discord.utils.get(ctx.guild.channels, id = int(channel_banlog))
  232. embed = discord.Embed(
  233. title=f"Unban of **{user.name}**",
  234. description=f"User {user.mention} was unbanned from this server.",
  235. color=discord.Color.green()
  236. )
  237. time = discord.utils.format_dt(datetime.now(), "f")
  238. embed.add_field(name="Unban Date", value=time, inline=False)
  239. embed.add_field(name="Moderator", value=f"{ctx.author}", inline=False)
  240. embed.add_field(name="Reason", value=reason, inline=False)
  241. embed.add_field(name="User ID", value=user.id)
  242. embed.set_thumbnail(url=user.display_avatar.url)
  243. embed.set_author(name="VicePD", icon_url="https://i.imgur.com/6QteFrg.png")
  244. embed.set_footer(text="VicePD - Bot | Made by BaumSplitter41")
  245. try:
  246. await ctx.guild.unban(user, reason=reason)
  247. await ctx.respond(f"User {user.mention} is now unbanned!", ephemeral=True)
  248. await channel.send(embed=embed)
  249. cursor.execute(
  250. "INSERT INTO Unbans (userid, username, moderatorname, reason) VALUES (%s, %s, %s, %s)",
  251. (user.id, str(user), str(ctx.author), reason)
  252. )
  253. conn.commit()
  254. except discord.Forbidden:
  255. await ctx.respond("Error: I don't have permission to unban this user.", ephemeral=True)
  256. except discord.HTTPException as e:
  257. await ctx.respond(f"Error: Could not unban User {user.mention}. Reason: {e}", ephemeral=True)
  258. except Exception as e:
  259. await ctx.respond(f"Unexpected error: {e}", ephemeral=True)
  260. #---------------------------------#
  261. #_________________________________#
  262. #---------------------------------#
  263. #Kick
  264. @bot.slash_command(name="kick", description="Kick a user from this Server")
  265. async def kick(
  266. ctx,
  267. user: Option(discord.User, description = "Select User", required=True), # type: ignore
  268. reason: Option(str, description = "Reason for the ban", default="No reason provided") # type: ignore
  269. ):
  270. if not ctx.author.guild_permissions.kick_members:
  271. await ctx.respond("Error: You don't have the permission to kick Members!", ephemeral=True)
  272. return
  273. if user == bot.user:
  274. await ctx.respond("Error: I can't kick myself!", ephemeral=True)
  275. return
  276. if user == ctx.author:
  277. await ctx.respond("Error: You can't kick yourself!", ephemeral=True)
  278. return
  279. channel= discord.utils.get(ctx.guild.channels, id = int(channel_banlog))
  280. embed = discord.Embed(
  281. title=f"Kick of **{user.name}**",
  282. description=f"User {user.mention} has been kicked from the Server",
  283. color=discord.Color.red()
  284. )
  285. time = discord.utils.format_dt(datetime.now(), "f")
  286. embed.add_field(name="Kick Date", value=time, inline=False)
  287. embed.add_field(name="Moderator", value=f"{ctx.author}", inline=False)
  288. embed.add_field(name="Reason", value=reason, inline=False)
  289. embed.add_field(name="User ID", value=user.id)
  290. embed.set_thumbnail(url=user.display_avatar.url)
  291. embed.set_author(name="VicePD", icon_url="https://i.imgur.com/6QteFrg.png")
  292. embed.set_footer(text="VicePD - Bot | Made by BaumSplitter41")
  293. try:
  294. await ctx.guild.kick(user, reason=reason)
  295. await ctx.respond(f"User {user.mention} has been kicked from this Server!", ephemeral=True)
  296. cursor.execute(
  297. "INSERT INTO Kick (userid, username, moderatorname, reason) VALUES (%s, %s, %s, %s)",
  298. (int(user.id), str(user), str(ctx.author), reason)
  299. )
  300. conn.commit()
  301. await channel.send(embed=embed)
  302. except discord.Forbidden:
  303. await ctx.respond("Error: I don't have permission to kick this user.", ephemeral=True)
  304. except discord.HTTPException as e:
  305. await ctx.respond(f"Error: Could not kick User {user.mention}. Reason: {e}", ephemeral=True)
  306. except Exception as e:
  307. await ctx.respond(f"Unexpected error: {e}", ephemeral=True)
  308. #---------------------------------#
  309. #---------------------------------#
  310. #Warn
  311. @bot.slash_command(name="warn", description="Warn a user from this Server")
  312. async def warn(
  313. ctx,
  314. user: Option(discord.User, required=True), # type: ignore
  315. reason: Option(str, default="No reason provided") # type: ignore
  316. ):
  317. await ctx.defer(ephemeral=True)
  318. if not ctx.author.guild_permissions.kick_members:
  319. await ctx.followup.send("No permission.", ephemeral=True)
  320. return
  321. if user in (bot.user, ctx.author):
  322. await ctx.followup.send("Invalid target.", ephemeral=True)
  323. return
  324. cursor.execute(
  325. "INSERT INTO Warns (userid, username, moderatorname, reason) VALUES (%s, %s, %s, %s)",
  326. (user.id, str(user), str(ctx.author), reason)
  327. )
  328. conn.commit()
  329. await ctx.followup.send(
  330. f"User {user.mention} has been warned for: {reason}",
  331. ephemeral=True
  332. )
  333. #---------------------------------#
  334. #Modinfo
  335. @bot.slash_command(name="modinfo", description="Shows the moderative history of a user from this Server")
  336. async def modinfo(
  337. ctx,
  338. user: Option(discord.User, required=True) # type: ignore
  339. ):
  340. await ctx.defer(ephemeral=False)
  341. if not ctx.author.guild_permissions.kick_members:
  342. await ctx.followup.send("No permission.", ephemeral=True)
  343. return
  344. embed = discord.Embed(
  345. title=f"__Moderation History for {user.name}__",
  346. color=discord.Color.orange()
  347. )
  348. cursor.execute(
  349. "SELECT moderatorname, reason, date FROM Warns WHERE userid = %s",
  350. (user.id,)
  351. )
  352. warns = cursor.fetchall()
  353. if warns:
  354. for moderatorname, reason, date in warns:
  355. embed.add_field(
  356. name=f"Warned by {moderatorname} on {date.strftime('%Y-%m-%d %H:%M:%S')}",
  357. value=f"Reason: {reason}",
  358. inline=False
  359. )
  360. cursor.execute(
  361. "SELECT moderatorname, reason, date FROM Kick WHERE userid = %s",
  362. (user.id,)
  363. )
  364. kicks = cursor.fetchall()
  365. if kicks:
  366. for moderatorname, reason, date in kicks:
  367. embed.add_field(
  368. name=f"Kicked by {moderatorname} on {date.strftime('%Y-%m-%d %H:%M:%S')}",
  369. value=f"Reason: {reason}",
  370. inline=False
  371. )
  372. cursor.execute(
  373. "SELECT moderatorname, reason, date FROM Bans WHERE userid = %s",
  374. (user.id,)
  375. )
  376. bans = cursor.fetchall()
  377. if bans:
  378. for moderatorname, reason, date in bans:
  379. embed.add_field(
  380. name=f"Banned by {moderatorname} on {date.strftime('%Y-%m-%d %H:%M:%S')}",
  381. value=f"Reason: {reason}",
  382. inline=False
  383. )
  384. cursor.execute(
  385. "SELECT moderatorname, reason, date FROM Unbans WHERE userid = %s",
  386. (user.id,)
  387. )
  388. unbans = cursor.fetchall()
  389. if unbans:
  390. for moderatorname, reason, date in unbans:
  391. embed.add_field(
  392. name=f"Unbanned by {moderatorname} on {date.strftime('%Y-%m-%d %H:%M:%S')}",
  393. value=f"Reason: {reason}",
  394. inline=False
  395. )
  396. if not warns and not kicks and not bans and not unbans:
  397. await ctx.followup.send(f"User {user.mention} has no moderation history.", ephemeral=True)
  398. return
  399. embed.set_thumbnail(url=user.display_avatar.url)
  400. embed.set_author(name="VicePD", icon_url="https://i.imgur.com/6QteFrg.png")
  401. embed.set_footer(text="VicePD - Bot | Made by BaumSplitter41")
  402. await ctx.followup.send(embed=embed, ephemeral=False)
  403. #_________________________________#
  404. ## Reaction role system
  405. #---------------------------------#
  406. #reaction role verfiy
  407. class PersistentRoleView(discord.ui.View):
  408. def __init__(self):
  409. super().__init__(timeout=None)
  410. @discord.ui.button(
  411. label=label_rules,
  412. style=discord.ButtonStyle.success,
  413. emoji="✅",
  414. custom_id="persistent_view:role_verify"
  415. )
  416. async def verify_callback(self, button: discord.ui.Button, interaction: discord.Interaction):
  417. role = interaction.guild.get_role(int(role_rules))
  418. if role is None:
  419. await interaction.response.send_message("Error: The konfigured role was not found", ephemeral=True)
  420. return
  421. if role in interaction.user.roles:
  422. await interaction.user.remove_roles(role)
  423. await interaction.response.send_message(f"Rolle **{role.name}** wurde entfernt.", ephemeral=True)
  424. else:
  425. await interaction.user.add_roles(role)
  426. await interaction.response.send_message(f"Du hast die Rolle **{role.name}** erhalten!", ephemeral=True)
  427. @bot.slash_command(name="verify_message", description="Send the reactionrole message")
  428. async def setup_rr(
  429. ctx: discord.ApplicationContext,
  430. channel: discord.TextChannel,
  431. title: str,
  432. description: str
  433. ):
  434. if not ctx.author.guild_permissions.administrator:
  435. await ctx.respond("You dont have the permissions to do that..", ephemeral=True)
  436. return
  437. embed = discord.Embed(
  438. title=title,
  439. description=f"{description}\n\nViel Spass auf dem Server!",
  440. color=discord.Color.red()
  441. )
  442. embed.set_image(url="https://i.imgur.com/FoF791J.png")
  443. try:
  444. await channel.send(embed=embed, view=PersistentRoleView())
  445. await ctx.respond(f"Message was succesfully sent in {channel.mention}!", ephemeral=True)
  446. except discord.Forbidden:
  447. await ctx.respond("I dont have permissions to write in this channel", ephemeral=True)
  448. #---------------------------------#
  449. #_________________________________#
  450. #---------------------------------#
  451. #Run function
  452. load_extensions()
  453. bot.run(token)
  454. #---------------------------------#