1
Fork 0
mirror of https://github.com/wlinator/luminara.git synced 2024-10-02 18:03:12 +00:00

Merge pull request #20 from wlinator/moderation

Moderation: Config
This commit is contained in:
wlinator 2024-08-03 14:57:41 -04:00
commit cef7724a10
14 changed files with 621 additions and 708 deletions

View file

@ -22,12 +22,61 @@
"case_type_field": "Type:",
"case_type_field_value": "`{0}`",
"case_type_field_value_with_duration": "`{0} ({1})`",
"config_author": "Server Configuration",
"config_birthday_channel_set": "birthday announcements will be sent in {0}.",
"config_birthday_module_already_disabled": "the birthday module was already disabled.",
"config_birthday_module_disabled": "the birthday module was successfully disabled.",
"config_boost_channel_set": "boost announcements will be sent in {0}.",
"config_boost_image_field": "New Image URL:",
"config_boost_image_original": "Original (default)",
"config_boost_image_updated": "the boost image has been updated.",
"config_boost_module_already_disabled": "the boost module was already disabled.",
"config_boost_module_disabled": "the boost module was successfully disabled.",
"config_boost_template_field": "New Template:",
"config_boost_template_updated": "the boost message template has been updated.",
"config_example_next_footer": "An example will be sent next.",
"config_level_channel_set": "all level announcements will be sent in {0}.",
"config_level_current_channel_set": "members will receive level announcements in their current channel.",
"config_level_module_already_enabled": "the Lumi XP system was already enabled.",
"config_level_module_disabled": "the Lumi XP system was successfully disabled.",
"config_level_module_disabled_warning": "Warning: this module is disabled, please do '/config levels enable'",
"config_level_module_enabled": "the Lumi XP system was successfully enabled.",
"config_level_template": "Template:",
"config_level_template_updated": "the level template was successfully updated.",
"config_level_type_example": "Example:",
"config_level_type_generic": "level announcements will be **generic messages**.",
"config_level_type_generic_example": "📈 | **lucas** you have reached **Level 15**.",
"config_level_type_whimsical": "level announcements will be **sarcastic comments**.",
"config_level_type_whimsical_example": "📈 | **lucas** Lol it took you this long to reach **Level 15**.",
"config_modlog_channel_set": "moderation logs will be sent in {0}.",
"config_prefix_get": "the current prefix for this server is `{0}`.",
"config_prefix_set": "the prefix has been set to `{0}`.",
"config_prefix_too_long": "the prefix must be 25 characters or less.",
"config_show_author": "{0} Configuration",
"config_show_birthdays": "Birthdays",
"config_show_boost_announcements": "Boost announcements",
"config_show_default_enabled": "✅ Enabled (default)",
"config_show_disabled": "❌ Disabled",
"config_show_enabled": "✅ Enabled",
"config_show_guide": "Guide: {0}",
"config_show_level_announcements": "Level announcements",
"config_show_moderation_log": "Moderation Log",
"config_show_moderation_log_channel_deleted": "⚠️ **Not configured** (channel deleted?)",
"config_show_moderation_log_enabled": "✅ {0}",
"config_show_moderation_log_not_configured": "⚠️ **Not configured yet**",
"config_show_new_member_greets": "New member greets",
"config_welcome_channel_set": "I will announce new members in {0}.",
"config_welcome_module_already_disabled": "the greeting module was already disabled.",
"config_welcome_module_disabled": "the greeting module was successfully disabled.",
"config_welcome_template_field": "New Template:",
"config_welcome_template_updated": "the welcome message template has been updated.",
"daily_already_claimed_author": "Already Claimed",
"daily_already_claimed_description": "you can claim your daily reward again <t:{0}:R>.",
"daily_already_claimed_footer": "Daily reset is at 7 AM EST",
"daily_streak_footer": "You're on a streak of {0} days",
"daily_success_claim_author": "Reward Claimed",
"daily_success_claim_description": "you claimed your reward of **${0}**!",
"default_level_up_message": "**{0}** you have reached **Level {1}**.",
"error_actionable_hierarchy_bot": "I don't have permission to perform this action on this user due to role hierarchy.",
"error_actionable_hierarchy_user": "you don't have permission to perform this action on this user due to role hierarchy.",
"error_actionable_self": "you can't perform this action on yourself.",
@ -36,10 +85,12 @@
"error_birthdays_disabled_author": "Birthdays Disabled",
"error_birthdays_disabled_description": "birthdays are disabled in this server.",
"error_birthdays_disabled_footer": "Contact a mod to enable them.",
"error_boost_image_url_invalid": "the image URL must end with `.jpg` or `.png`.",
"error_bot_missing_permissions_author": "Bot Missing Permissions",
"error_bot_missing_permissions_description": "Lumi lacks the required permissions to run this command.",
"error_command_cooldown_author": "Command Cooldown",
"error_command_cooldown_description": "try again in **{0:02d}:{1:02d}**.",
"error_image_url_invalid": "invalid image URL.",
"error_invalid_duration": "Invalid duration: {0}",
"error_invalid_duration_author": "Invalid Duration",
"error_invalid_duration_description": "Please provide a valid duration between 1 minute and 30 days.",

View file

@ -12,7 +12,7 @@ class Constants:
TITLE = "Luminara"
AUTHOR = "wlinator"
LICENSE = "GNU General Public License v3.0"
VERSION = "2.8.3" # "Moderation: Timeouts" update
VERSION = "2.8.4" # "Moderation: Config" update
# bot credentials
TOKEN: Optional[str] = os.environ.get("TOKEN", None)
@ -36,6 +36,10 @@ class Constants:
MARIADB_ROOT_PASSWORD: Optional[str] = os.environ.get("MARIADB_ROOT_PASSWORD", None)
MARIADB_DATABASE: Optional[str] = os.environ.get("MARIADB_DATABASE", None)
# config
CONFIG_GUIDE_URL = "https://wiki.wlinator.org/serverconfig"
ALLOWED_IMAGE_EXTENSIONS = (".jpg", ".png")
# emotes
EMOTES_GUILD_ID = 1038051105642401812

View file

@ -5,13 +5,11 @@ from lib.constants import CONST
def clean_error_embed(ctx):
embed = discord.Embed(
return discord.Embed(
color=discord.Color.red(),
description=f"**{ctx.author.name}** ",
)
return embed
class GenericErrors:
@staticmethod
@ -28,16 +26,6 @@ class GenericErrors:
return embed
@staticmethod
def bad_url(ctx, error="the image URL must end with `.jpg` or `.png`."):
embed = clean_error_embed(ctx)
if embed.description is None:
embed.description = formatter.shorten(str(error), 100)
else:
embed.description += formatter.shorten(str(error), 100)
return embed
@staticmethod
def private_message_only(ctx):
embed = clean_error_embed(ctx)

View file

@ -1,14 +1,17 @@
import discord
from config.parser import JsonCache
from discord.commands import SlashCommandGroup
from discord.ext import bridge, commands
from config.parser import JsonCache
from lib import formatter
from lib.embeds.boost import Boost
from lib.embeds.error import GenericErrors
from lib.embeds.greet import Greet
from modules.config import config, set_prefix, xp_reward
from services.config_service import GuildConfig
from modules.config import (
c_birthday,
c_boost,
c_greet,
c_level,
c_moderation,
c_prefix,
c_show,
xp_reward,
)
strings = JsonCache.read_json("strings")
@ -17,31 +20,6 @@ class Config(commands.Cog):
def __init__(self, client):
self.client = client
@bridge.bridge_command(
name="configuration",
aliases=["config"],
description="Show your server configuration.",
help="Shows information about how Lumi is configured in your server. "
"[Read the guide](https://wiki.wlinator.org/serverconfig).",
guild_only=True,
)
@commands.guild_only()
@commands.has_permissions(manage_channels=True)
async def config_command(self, ctx):
await config.cmd(self, ctx)
@bridge.bridge_command(
name="setprefix",
aliases=["sp"],
description="Set Lumi's prefix.",
help="Set the prefix for Lumi in this server. The maximum length of a prefix is 25.",
guild_only=True,
)
@commands.guild_only()
@commands.has_permissions(manage_channels=True)
async def prefix_set_command(self, ctx, *, prefix: str):
await set_prefix.set_cmd(ctx, prefix)
@bridge.bridge_command(
name="xprewards",
aliases=["xpr"],
@ -85,530 +63,115 @@ class Config(commands.Cog):
await xp_reward.remove_reward(ctx, level)
"""
The guild config code is a mess.
CONFIG GROUPS
The 'config' group consists of many different configuration types, each being guild-specific and guild-only.
All commands in this group are exclusively available as slash-commands.
Only administrators can access commands in this group.
- Birthdays
- Welcome
- Boosts
- Levels
- Prefix
- Modlog channel
- Permissions preset (coming soon)
Running '/config show' will show a list of all available configuration types.
"""
config = SlashCommandGroup(
"config",
"server config commands.",
guild_only=True,
default_member_permissions=discord.Permissions(manage_channels=True),
default_member_permissions=discord.Permissions(administrator=True),
)
@config.command(name="show")
async def config_command(self, ctx):
await c_show.cmd(ctx)
birthday_config = config.create_subgroup(name="birthdays")
command_config = config.create_subgroup(name="commands")
intro_config = config.create_subgroup(name="intros")
@config.command(name="channel")
async def config_birthdays_channel(self, ctx, channel: discord.TextChannel):
await c_birthday.set_birthday_channel(ctx, channel)
@birthday_config.command(name="disable")
async def config_birthdays_disable(self, ctx):
await c_birthday.disable_birthday_module(ctx)
welcome_config = config.create_subgroup(name="greetings")
@welcome_config.command(name="channel")
async def config_welcome_channel(self, ctx, channel: discord.TextChannel):
await c_greet.set_welcome_channel(ctx, channel)
@welcome_config.command(name="disable")
async def config_welcome_disable(self, ctx):
await c_greet.disable_welcome_module(ctx)
@welcome_config.command(name="template")
@discord.commands.option(name="text", type=str, max_length=2000)
async def config_welcome_template(self, ctx, text):
await c_greet.set_welcome_template(ctx, text)
boost_config = config.create_subgroup(name="boosts")
@boost_config.command(name="channel")
async def config_boosts_channel(self, ctx, channel: discord.TextChannel):
await c_boost.set_boost_channel(ctx, channel)
@boost_config.command(name="disable")
async def config_boosts_disable(self, ctx):
await c_boost.disable_boost_module(ctx)
@boost_config.command(name="template")
@discord.commands.option(name="text", type=str, max_length=2000)
async def config_boosts_template(self, ctx, text):
await c_boost.set_boost_template(ctx, text)
@boost_config.command(name="image")
@discord.commands.option(name="url", type=str, max_length=2000)
async def config_boosts_image(self, ctx, url):
await c_boost.set_boost_image(ctx, url)
level_config = config.create_subgroup(name="levels")
@birthday_config.command(
name="channel",
description="Set the birthday announcements channel.",
)
async def config_birthdays_channel(self, ctx, *, channel: discord.TextChannel):
guild_config = GuildConfig(ctx.guild.id)
guild_config.birthday_channel_id = channel.id
guild_config.push()
@level_config.command(name="channel")
async def config_level_channel(self, ctx, channel: discord.TextChannel):
await c_level.set_level_channel(ctx, channel)
embed = discord.Embed(
color=discord.Color.orange(),
description=f"✅ | Birthday announcements will be sent in {channel.mention}.",
)
guild_icon = (
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
)
embed.set_author(name="Server Configuration", icon_url=guild_icon)
return await ctx.respond(embed=embed)
@birthday_config.command(
name="disable",
description="Disable the birthday module.",
)
async def config_birthdays_disable(self, ctx):
guild_config = GuildConfig(ctx.guild.id)
embed = discord.Embed(
color=discord.Color.orange(),
)
guild_icon = (
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
)
embed.set_author(name="Server Configuration", icon_url=guild_icon)
if not guild_config.birthday_channel_id:
embed.description = "👍 | The birthday module was already disabled."
return await ctx.respond(embed=embed)
else:
guild_config.birthday_channel_id = None
guild_config.push()
embed.description = "✅ | The birthday module was successfully disabled."
return await ctx.respond(embed=embed)
@command_config.command(
name="channel",
description="Configure where members can use Lumi commands.",
)
async def config_commands_channel(self, ctx, *, channel: discord.TextChannel):
guild_config = GuildConfig(ctx.guild.id)
guild_config.command_channel_id = channel.id
guild_config.push()
embed = discord.Embed(
color=discord.Color.orange(),
description=f"✅ | Commands can now only be used in {channel.mention}.",
)
guild_icon = (
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
)
embed.set_author(name="Server Configuration", icon_url=guild_icon)
embed.set_footer(
text="Note: mod & config commands are still available everywhere.",
)
return await ctx.respond(embed=embed)
@command_config.command(
name="everywhere",
description="Allow members to do commands in all channels.",
)
async def config_commands_everywhere(self, ctx):
guild_config = GuildConfig(ctx.guild.id)
guild_config.command_channel_id = None
guild_config.push()
embed = discord.Embed(
color=discord.Color.orange(),
description="✅ | Server members can now use Lumi commands in all channels. ",
)
guild_icon = (
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
)
embed.set_author(name="Server Configuration", icon_url=guild_icon)
return await ctx.respond(embed=embed)
# @intro_config.command(
# name="channel",
# description="Set the introductions channel."
# )
# async def config_intros_channel(self, ctx, *, channel: discord.TextChannel):
# guild_config = GuildConfig(ctx.guild.id)
# guild_config.intro_channel_id = channel.id
# guild_config.push()
#
# embed = discord.Embed(
# color=discord.Color.orange(),
# description=f"✅ | New introductions will be sent in {channel.mention}."
# )
# guild_icon = ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
# embed.set_author(name="Server Configuration", icon_url=guild_icon)
#
# return await ctx.respond(embed=embed)
#
# @intro_config.command(
# name="disable",
# introduction="Disable the introductions module."
# )
# async def config_intros_disable(self, ctx):
# guild_config = GuildConfig(ctx.guild.id)
#
# embed = discord.Embed(
# color=discord.Color.orange(),
# )
# guild_icon = ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
# embed.set_author(name="Server Configuration", icon_url=guild_icon)
#
# if not guild_config.intro_channel_id:
# embed.description = "👍 | The introductions module was already disabled."
# return await ctx.respond(embed=embed)
#
# else:
# guild_config.intro_channel_id = None
# guild_config.push()
# embed.description = "✅ | The introductions module was successfully disabled."
# return await ctx.respond(embed=embed)
@welcome_config.command(
name="channel",
description="Set the greeting announcements channel.",
)
async def config_welcome_channel(self, ctx, *, channel: discord.TextChannel):
guild_config = GuildConfig(ctx.guild.id)
guild_config.welcome_channel_id = channel.id
guild_config.push()
embed = discord.Embed(
color=discord.Color.orange(),
description=f"✅ | New members will receive a welcome message in {channel.mention}.",
)
guild_icon = (
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
)
embed.set_author(name="Server Configuration", icon_url=guild_icon)
return await ctx.respond(embed=embed)
@welcome_config.command(
name="disable",
description="Disable greetings in this server.",
)
async def config_welcome_disable(self, ctx):
guild_config = GuildConfig(ctx.guild.id)
embed = discord.Embed(
color=discord.Color.orange(),
)
guild_icon = (
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
)
embed.set_author(name="Server Configuration", icon_url=guild_icon)
if not guild_config.welcome_channel_id:
embed.description = "👍 | The greeting module was already disabled."
return await ctx.respond(embed=embed)
else:
guild_config.welcome_channel_id = None
guild_config.welcome_message = None
guild_config.push()
embed.description = "✅ | The greeting module was successfully disabled."
return await ctx.respond(embed=embed)
@welcome_config.command(
name="template",
description="Make a custom greeting template.",
)
async def config_welcome_template(
self,
ctx,
*,
text: discord.Option(str, max_length=2000),
):
guild_config = GuildConfig(ctx.guild.id)
guild_config.welcome_message = text
guild_config.push()
embed = discord.Embed(
color=discord.Color.orange(),
description="✅ | The greeting template was successfully updated.",
)
guild_icon = (
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
)
embed.add_field(name="Template", value=text, inline=False)
embed.add_field(
name="Example",
value="An example will be sent in a separate message.",
inline=False,
)
embed.set_author(name="Server Configuration", icon_url=guild_icon)
await ctx.respond(embed=embed)
embed = Greet.message(ctx.author, text)
return await ctx.send(embed=embed, content=ctx.author.mention)
@boost_config.command(
name="channel",
description="Set the boost announcements channel.",
)
async def config_boosts_channel(self, ctx, *, channel: discord.TextChannel):
guild_config = GuildConfig(ctx.guild.id)
guild_config.boost_channel_id = channel.id
guild_config.push()
embed = discord.Embed(
color=discord.Color.orange(),
description=f"✅ | I will announce server boosts in {channel.mention}.",
)
guild_icon = (
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
)
embed.set_author(name="Server Configuration", icon_url=guild_icon)
return await ctx.respond(embed=embed)
@boost_config.command(
name="disable",
description="Disable boost announcements in this server.",
)
async def config_boosts_disable(self, ctx):
guild_config = GuildConfig(ctx.guild.id)
embed = discord.Embed(
color=discord.Color.orange(),
)
guild_icon = (
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
)
embed.set_author(name="Server Configuration", icon_url=guild_icon)
if not guild_config.boost_channel_id:
embed.description = "👍 | Boost announcements were already disabled."
return await ctx.respond(embed=embed)
else:
guild_config.boost_channel_id = None
guild_config.boost_message = None
guild_config.push()
embed.description = "✅ | Boost announcements are successfully disabled."
return await ctx.respond(embed=embed)
@boost_config.command(
name="template",
description="Make a custom boost announcement template.",
)
async def config_boosts_template(
self,
ctx,
*,
text: discord.Option(str, max_length=2000),
):
guild_config = GuildConfig(ctx.guild.id)
guild_config.boost_message = text
guild_config.push()
embed = discord.Embed(
color=discord.Color.orange(),
description="✅ | The booster template was successfully updated.",
)
guild_icon = (
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
)
embed.add_field(name="Template", value=text, inline=False)
embed.add_field(
name="Example",
value="An example will be sent in a separate message.",
inline=False,
)
embed.set_author(name="Server Configuration", icon_url=guild_icon)
await ctx.respond(embed=embed)
embed = Boost.message(ctx.author, text, guild_config.boost_image_url)
return await ctx.send(embed=embed, content=ctx.author.mention)
@boost_config.command(
name="image",
description="Add a custom image that will used for booster announcements.",
)
async def config_boosts_image(self, ctx, *, image_url: str):
guild_config = GuildConfig(ctx.guild.id)
if image_url.lower() == "original":
guild_config.boost_image_url = None
guild_config.push()
image_url = None
elif not image_url.endswith(".jpg") and not image_url.lower().endswith(".png"):
return await ctx.respond(embed=GenericErrors.bad_url(ctx))
elif not image_url.startswith("http://") and not image_url.startswith(
"https://",
):
return await ctx.respond(embed=GenericErrors.bad_url(ctx, "invalid URL."))
else:
guild_config.boost_image_url = image_url
guild_config.push()
embed = discord.Embed(
color=discord.Color.orange(),
description="✅ | The booster image was successfully updated.",
)
guild_icon = (
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
)
embed.add_field(
name="Image",
value=image_url if image_url else "Original Image",
inline=False,
)
embed.add_field(
name="Example",
value="An example will be sent in a separate message.",
inline=False,
)
embed.set_author(name="Server Configuration", icon_url=guild_icon)
await ctx.respond(embed=embed)
embed = Boost.message(ctx.author, guild_config.boost_message, image_url)
return await ctx.send(embed=embed, content=ctx.author.mention)
@level_config.command(
name="channel",
description="Set the level announcements channel.",
)
async def config_level_channel(self, ctx, *, channel: discord.TextChannel):
guild_config = GuildConfig(ctx.guild.id)
guild_config.level_channel_id = channel.id
guild_config.push()
embed = discord.Embed(
color=discord.Color.orange(),
description=f"✅ | All level announcements will be sent in {channel.mention}.",
)
guild_icon = (
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
)
embed.set_author(name="Server Configuration", icon_url=guild_icon)
if guild_config.level_message_type == 0:
embed.set_footer(
text="Warning: this module is disabled, please do '/config levels enable'",
)
return await ctx.respond(embed=embed)
@level_config.command(
name="currentchannel",
description="Send level announcements in the member's current channel.",
)
@level_config.command(name="currentchannel")
async def config_level_samechannel(self, ctx):
guild_config = GuildConfig(ctx.guild.id)
guild_config.level_channel_id = None
guild_config.push()
await c_level.set_level_current_channel(ctx)
embed = discord.Embed(
color=discord.Color.orange(),
description="✅ | Members will receive level announcements in their current channel.",
)
guild_icon = (
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
)
embed.set_author(name="Server Configuration", icon_url=guild_icon)
if guild_config.level_message_type == 0:
embed.set_footer(
text="Warning: this module is disabled, please do '/config levels enable'",
)
return await ctx.respond(embed=embed)
@level_config.command(
name="disable",
description="Disable levels and the Lumi XP system.",
)
@level_config.command(name="disable")
async def config_level_disable(self, ctx):
guild_config = GuildConfig(ctx.guild.id)
guild_config.level_message_type = 0
guild_config.push()
await c_level.disable_level_module(ctx)
embed = discord.Embed(
color=discord.Color.orange(),
description="✅ | The Lumi XP system was successfully disabled.",
)
guild_icon = (
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
)
embed.set_author(name="Server Configuration", icon_url=guild_icon)
return await ctx.respond(embed=embed)
@level_config.command(
name="enable",
description="Enable levels and the Lumi XP system.",
)
@level_config.command(name="enable")
async def config_level_enable(self, ctx):
guild_config = GuildConfig(ctx.guild.id)
await c_level.enable_level_module(ctx)
embed = discord.Embed(
color=discord.Color.orange(),
)
guild_icon = (
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
)
embed.set_author(name="Server Configuration", icon_url=guild_icon)
@level_config.command(name="type")
@discord.commands.option(name="type", choices=["whimsical", "generic"])
async def config_level_type(self, ctx, type):
await c_level.set_level_type(ctx, type)
if guild_config.level_message_type != 0:
embed.description = "👍 | The Lumi XP system was already enabled."
return await ctx.respond(embed=embed)
@level_config.command(name="template")
async def config_level_template(self, ctx, text: str):
await c_level.set_level_template(ctx, text)
else:
guild_config.level_message_type = 1
guild_config.push()
embed.description = "✅ | The Lumi XP system was successfully enabled."
embed.set_footer(text="Note: see '.help config' for more info.")
return await ctx.respond(embed=embed)
prefix_config = config.create_subgroup(name="prefix")
@level_config.command(
name="type",
description="Set the level announcements type.",
)
async def config_level_type(
self,
ctx,
*,
type: discord.Option(choices=["whimsical", "generic"]),
):
guild_config = GuildConfig(ctx.guild.id)
@prefix_config.command(name="set")
async def config_prefix_set(self, ctx, prefix: str):
await c_prefix.set_prefix(ctx, prefix)
embed = discord.Embed(
color=discord.Color.orange(),
)
guild_icon = (
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
)
embed.set_author(name="Server Configuration", icon_url=guild_icon)
modlog = config.create_subgroup(name="moderation")
if type == "whimsical":
guild_config.level_message_type = 1
guild_config.level_message = None
guild_config.push()
embed.description = "✅ | Level announcements will be sarcastic comments."
embed.add_field(
name="Example",
value="📈 | **lucas** Lol it took you this long to reach **Level 15**.",
inline=False,
)
return await ctx.respond(embed=embed)
else:
guild_config.level_message_type = 2
guild_config.level_message = None
guild_config.push()
embed.description = "✅ | Level announcements will be generic messages."
embed.add_field(
name="Example",
value="📈 | **lucas** you have reached **Level 15**.",
inline=False,
)
return await ctx.respond(embed=embed)
@level_config.command(
name="template",
description="Make a custom leveling template.",
)
async def config_level_template(
self,
ctx,
*,
text: discord.Option(str, max_length=2000),
):
guild_config = GuildConfig(ctx.guild.id)
guild_config.level_message = text
guild_config.push()
preview = formatter.template(text, "Lucas", 15)
embed = discord.Embed(
color=discord.Color.orange(),
description="✅ | The level template was successfully updated.",
)
guild_icon = (
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
)
embed.add_field(name="Template", value=text, inline=False)
embed.add_field(name="Example", value=preview, inline=False)
embed.set_author(name="Server Configuration", icon_url=guild_icon)
if guild_config.level_message_type == 0:
embed.set_footer(
text="Warning: this module is disabled, please do '/config levels enable'",
)
return await ctx.respond(embed=embed)
@modlog.command(name="log")
async def config_moderation_log_channel(self, ctx, channel: discord.TextChannel):
await c_moderation.set_mod_log_channel(ctx, channel)
def setup(client):

View file

@ -0,0 +1,42 @@
import discord
from lib.embed_builder import EmbedBuilder
from lib.constants import CONST
from services.config_service import GuildConfig
async def set_birthday_channel(ctx, channel: discord.TextChannel):
guild_config = GuildConfig(ctx.guild.id)
guild_config.birthday_channel_id = channel.id
guild_config.push()
embed = EmbedBuilder().create_success_embed(
ctx=ctx,
author_text=CONST.STRINGS["config_author"],
description=CONST.STRINGS["config_birthday_channel_set"].format(
channel.mention,
),
)
return await ctx.respond(embed=embed)
async def disable_birthday_module(ctx):
guild_config = GuildConfig(ctx.guild.id)
if not guild_config.birthday_channel_id:
embed = EmbedBuilder().create_warning_embed(
ctx=ctx,
author_text=CONST.STRINGS["config_author"],
description=CONST.STRINGS["config_birthday_module_already_disabled"],
)
else:
embed = EmbedBuilder().create_success_embed(
ctx=ctx,
author_text=CONST.STRINGS["config_author"],
description=CONST.STRINGS["config_birthday_module_disabled"],
)
guild_config.birthday_channel_id = None
guild_config.push()
return await ctx.respond(embed=embed)

98
modules/config/c_boost.py Normal file
View file

@ -0,0 +1,98 @@
import discord
from lib.embed_builder import EmbedBuilder
from lib.constants import CONST
from services.config_service import GuildConfig
from lib.exceptions.LumiExceptions import LumiException
from lib.embeds.boost import Boost
async def set_boost_channel(ctx, channel: discord.TextChannel):
guild_config = GuildConfig(ctx.guild.id)
guild_config.boost_channel_id = channel.id
guild_config.push()
embed = EmbedBuilder().create_success_embed(
ctx=ctx,
author_text=CONST.STRINGS["config_author"],
description=CONST.STRINGS["config_boost_channel_set"].format(channel.mention),
)
return await ctx.respond(embed=embed)
async def disable_boost_module(ctx):
guild_config = GuildConfig(ctx.guild.id)
if not guild_config.boost_channel_id:
embed = EmbedBuilder().create_warning_embed(
ctx=ctx,
author_text=CONST.STRINGS["config_author"],
description=CONST.STRINGS["config_boost_module_already_disabled"],
)
else:
guild_config.boost_channel_id = None
guild_config.boost_message = None
guild_config.push()
embed = EmbedBuilder().create_success_embed(
ctx=ctx,
author_text=CONST.STRINGS["config_author"],
description=CONST.STRINGS["config_boost_module_disabled"],
)
return await ctx.respond(embed=embed)
async def set_boost_template(ctx, text: str):
guild_config = GuildConfig(ctx.guild.id)
guild_config.boost_message = text
guild_config.push()
embed = EmbedBuilder().create_success_embed(
ctx=ctx,
author_text=CONST.STRINGS["config_author"],
description=CONST.STRINGS["config_boost_template_updated"],
footer_text=CONST.STRINGS["config_example_next_footer"],
)
embed.add_field(
name=CONST.STRINGS["config_boost_template_field"],
value=f"```{text}```",
inline=False,
)
await ctx.respond(embed=embed)
example_embed = Boost.message(ctx.author, text, guild_config.boost_image_url)
return await ctx.send(embed=example_embed, content=ctx.author.mention)
async def set_boost_image(ctx, image_url: str | None):
guild_config = GuildConfig(ctx.guild.id)
if image_url is None or image_url.lower() == "original":
guild_config.boost_image_url = None
guild_config.push()
image_url = None
elif not image_url.endswith(CONST.ALLOWED_IMAGE_EXTENSIONS):
raise LumiException(CONST.STRINGS["error_boost_image_url_invalid"])
elif not image_url.startswith(("http://", "https://")):
raise LumiException(CONST.STRINGS["error_image_url_invalid"])
else:
guild_config.boost_image_url = image_url
guild_config.push()
embed = EmbedBuilder().create_success_embed(
ctx=ctx,
author_text=CONST.STRINGS["config_author"],
description=CONST.STRINGS["config_boost_image_updated"],
footer_text=CONST.STRINGS["config_example_next_footer"],
)
embed.add_field(
name=CONST.STRINGS["config_boost_image_field"],
value=image_url or CONST.STRINGS["config_boost_image_original"],
inline=False,
)
await ctx.respond(embed=embed)
example_embed = Boost.message(ctx.author, guild_config.boost_message, image_url)
return await ctx.send(embed=example_embed, content=ctx.author.mention)

64
modules/config/c_greet.py Normal file
View file

@ -0,0 +1,64 @@
import discord
from lib.embed_builder import EmbedBuilder
from lib.constants import CONST
from services.config_service import GuildConfig
from lib.embeds.greet import Greet
async def set_welcome_channel(ctx, channel: discord.TextChannel):
guild_config = GuildConfig(ctx.guild.id)
guild_config.welcome_channel_id = channel.id
guild_config.push()
embed = EmbedBuilder().create_success_embed(
ctx=ctx,
author_text=CONST.STRINGS["config_author"],
description=CONST.STRINGS["config_welcome_channel_set"].format(channel.mention),
)
return await ctx.respond(embed=embed)
async def disable_welcome_module(ctx):
guild_config = GuildConfig(ctx.guild.id)
if not guild_config.welcome_channel_id:
embed = EmbedBuilder().create_warning_embed(
ctx=ctx,
author_text=CONST.STRINGS["config_author"],
description=CONST.STRINGS["config_welcome_module_already_disabled"],
)
else:
guild_config.welcome_channel_id = None
guild_config.welcome_message = None
guild_config.push()
embed = EmbedBuilder().create_success_embed(
ctx=ctx,
author_text=CONST.STRINGS["config_author"],
description=CONST.STRINGS["config_welcome_module_disabled"],
)
return await ctx.respond(embed=embed)
async def set_welcome_template(ctx, text: str):
guild_config = GuildConfig(ctx.guild.id)
guild_config.welcome_message = text
guild_config.push()
embed = EmbedBuilder().create_success_embed(
ctx=ctx,
author_text=CONST.STRINGS["config_author"],
description=CONST.STRINGS["config_welcome_template_updated"],
footer_text=CONST.STRINGS["config_example_next_footer"],
)
embed.add_field(
name=CONST.STRINGS["config_welcome_template_field"],
value=f"```{text}```",
inline=False,
)
await ctx.respond(embed=embed)
example_embed = Greet.message(ctx.author, text)
return await ctx.send(embed=example_embed, content=ctx.author.mention)

136
modules/config/c_level.py Normal file
View file

@ -0,0 +1,136 @@
import discord
from lib.embed_builder import EmbedBuilder
from lib.constants import CONST
from services.config_service import GuildConfig
from lib import formatter
async def set_level_channel(ctx, channel: discord.TextChannel):
guild_config = GuildConfig(ctx.guild.id)
guild_config.level_channel_id = channel.id
guild_config.push()
embed = EmbedBuilder().create_success_embed(
ctx=ctx,
author_text=CONST.STRINGS["config_author"],
description=CONST.STRINGS["config_level_channel_set"].format(channel.mention),
)
if guild_config.level_message_type == 0:
embed.set_footer(text=CONST.STRINGS["config_level_module_disabled_warning"])
return await ctx.respond(embed=embed)
async def set_level_current_channel(ctx):
guild_config = GuildConfig(ctx.guild.id)
guild_config.level_channel_id = None
guild_config.push()
embed = EmbedBuilder().create_success_embed(
ctx=ctx,
author_text=CONST.STRINGS["config_author"],
description=CONST.STRINGS["config_level_current_channel_set"],
)
if guild_config.level_message_type == 0:
embed.set_footer(text=CONST.STRINGS["config_level_module_disabled_warning"])
return await ctx.respond(embed=embed)
async def disable_level_module(ctx):
guild_config = GuildConfig(ctx.guild.id)
guild_config.level_message_type = 0
guild_config.push()
embed = EmbedBuilder().create_success_embed(
ctx=ctx,
author_text=CONST.STRINGS["config_author"],
description=CONST.STRINGS["config_level_module_disabled"],
)
return await ctx.respond(embed=embed)
async def enable_level_module(ctx):
guild_config = GuildConfig(ctx.guild.id)
if guild_config.level_message_type != 0:
embed = EmbedBuilder().create_info_embed(
ctx=ctx,
author_text=CONST.STRINGS["config_author"],
description=CONST.STRINGS["config_level_module_already_enabled"],
)
else:
guild_config.level_message_type = 1
guild_config.push()
embed = EmbedBuilder().create_success_embed(
ctx=ctx,
author_text=CONST.STRINGS["config_author"],
description=CONST.STRINGS["config_level_module_enabled"],
)
return await ctx.respond(embed=embed)
async def set_level_type(ctx, type: str):
guild_config = GuildConfig(ctx.guild.id)
embed = EmbedBuilder().create_success_embed(
ctx=ctx,
author_text=CONST.STRINGS["config_author"],
)
guild_config.level_message = None
if type == "whimsical":
guild_config.level_message_type = 1
guild_config.push()
embed.description = CONST.STRINGS["config_level_type_whimsical"]
embed.add_field(
name=CONST.STRINGS["config_level_type_example"],
value=CONST.STRINGS["config_level_type_whimsical_example"],
inline=False,
)
else:
guild_config.level_message_type = 2
guild_config.push()
embed.description = CONST.STRINGS["config_level_type_generic"]
embed.add_field(
name=CONST.STRINGS["config_level_type_example"],
value=CONST.STRINGS["config_level_type_generic_example"],
inline=False,
)
return await ctx.respond(embed=embed)
async def set_level_template(ctx, text: str):
guild_config = GuildConfig(ctx.guild.id)
guild_config.level_message = text
guild_config.push()
preview = formatter.template(text, "Lucas", 15)
embed = EmbedBuilder().create_success_embed(
ctx=ctx,
author_text=CONST.STRINGS["config_author"],
description=CONST.STRINGS["config_level_template_updated"],
)
embed.add_field(
name=CONST.STRINGS["config_level_template"],
value=f"```{text}```",
inline=False,
)
embed.add_field(
name=CONST.STRINGS["config_level_type_example"],
value=preview,
inline=False,
)
if guild_config.level_message_type == 0:
embed.set_footer(text=CONST.STRINGS["config_level_module_disabled_warning"])
return await ctx.respond(embed=embed)

View file

@ -0,0 +1,17 @@
import discord
from lib.embed_builder import EmbedBuilder
from lib.constants import CONST
from services.moderation.modlog_service import ModLogService
async def set_mod_log_channel(ctx, channel: discord.TextChannel):
mod_log = ModLogService()
mod_log.set_modlog_channel(ctx.guild.id, channel.id)
embed = EmbedBuilder().create_success_embed(
ctx=ctx,
author_text=CONST.STRINGS["config_author"],
description=CONST.STRINGS["config_modlog_channel_set"].format(channel.mention),
)
return await ctx.respond(embed=embed)

View file

@ -0,0 +1,35 @@
from lib.embed_builder import EmbedBuilder
from lib.constants import CONST
from services.config_service import GuildConfig
async def set_prefix(ctx, prefix):
if len(prefix) > 25:
embed = EmbedBuilder().create_error_embed(
ctx=ctx,
author_text=CONST.STRINGS["config_author"],
description=CONST.STRINGS["config_prefix_too_long"],
)
return await ctx.respond(embed=embed)
guild_config = GuildConfig(
ctx.guild.id,
) # generate a guild_config for if it didn't already exist
GuildConfig.set_prefix(guild_config.guild_id, prefix)
embed = EmbedBuilder().create_success_embed(
ctx=ctx,
author_text=CONST.STRINGS["config_author"],
description=CONST.STRINGS["config_prefix_set"].format(prefix),
)
await ctx.respond(embed=embed)
async def get_prefix(ctx):
prefix = GuildConfig.get_prefix(ctx.guild.id)
embed = EmbedBuilder().create_info_embed(
ctx=ctx,
author_text=CONST.STRINGS["config_author"],
description=CONST.STRINGS["config_prefix_get"].format(prefix),
)
await ctx.respond(embed=embed)

73
modules/config/c_show.py Normal file
View file

@ -0,0 +1,73 @@
import discord
from typing import List, Tuple, Optional
from discord import Guild
from lib.embed_builder import EmbedBuilder
from lib.constants import CONST
from services.config_service import GuildConfig
from services.moderation.modlog_service import ModLogService
async def cmd(ctx) -> None:
guild_config: GuildConfig = GuildConfig(ctx.guild.id)
guild: Guild = ctx.guild
embed: discord.Embed = EmbedBuilder().create_success_embed(
ctx=ctx,
author_text=CONST.STRINGS["config_show_author"].format(guild.name),
thumbnail_url=guild.icon.url if guild.icon else CONST.LUMI_LOGO_TRANSPARENT,
show_name=False,
)
config_items: List[Tuple[str, bool, bool]] = [
(
CONST.STRINGS["config_show_birthdays"],
bool(guild_config.birthday_channel_id),
False,
),
(
CONST.STRINGS["config_show_new_member_greets"],
bool(guild_config.welcome_channel_id),
False,
),
(
CONST.STRINGS["config_show_boost_announcements"],
bool(guild_config.boost_channel_id),
False,
),
(
CONST.STRINGS["config_show_level_announcements"],
guild_config.level_message_type != 0,
False,
),
]
for name, enabled, default_enabled in config_items:
status: str = (
CONST.STRINGS["config_show_enabled"]
if enabled
else CONST.STRINGS["config_show_disabled"]
)
if not enabled and default_enabled:
status = CONST.STRINGS["config_show_default_enabled"]
embed.add_field(name=name, value=status, inline=False)
modlog_service: ModLogService = ModLogService()
modlog_channel_id: Optional[int] = modlog_service.fetch_modlog_channel_id(guild.id)
modlog_channel = guild.get_channel(modlog_channel_id) if modlog_channel_id else None
modlog_status: str
if modlog_channel:
modlog_status = CONST.STRINGS["config_show_moderation_log_enabled"].format(
modlog_channel.mention,
)
elif modlog_channel_id:
modlog_status = CONST.STRINGS["config_show_moderation_log_channel_deleted"]
else:
modlog_status = CONST.STRINGS["config_show_moderation_log_not_configured"]
embed.add_field(
name=CONST.STRINGS["config_show_moderation_log"],
value=modlog_status,
inline=False,
)
await ctx.respond(embed=embed)

View file

@ -1,138 +0,0 @@
import discord
from config.parser import JsonCache
from services.config_service import GuildConfig
strings = JsonCache.read_json("strings")
async def cmd(self, ctx):
guild_config = GuildConfig(ctx.guild.id)
embed = discord.Embed(
color=discord.Color.embed_background(),
description="Guide: https://wiki.wlinator.org/serverconfig",
)
icon = ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
embed.set_author(name=f"{ctx.guild.name} config", icon_url=icon)
# birthdays
if guild_config.birthday_channel_id:
channel = await self.client.get_or_fetch_channel(
ctx.guild,
guild_config.birthday_channel_id,
)
if channel:
birthday_config = f"✅ | in {channel.mention}."
else:
birthday_config = "❌ | enable the module with `/config birthdays channel`"
else:
birthday_config = "❌ | enable the module with `/config birthdays channel`"
embed.add_field(name="BIRTHDAYS", value=birthday_config, inline=False)
# commands
if guild_config.command_channel_id:
channel = await self.client.get_or_fetch_channel(
ctx.guild,
guild_config.command_channel_id,
)
if channel:
commands_config = f"✅ | commands only allowed in {channel.mention}."
else:
commands_config = "✅ | commands allowed anywhere."
else:
commands_config = "✅ | commands allowed anywhere."
embed.add_field(name="COMMANDS", value=commands_config, inline=False)
# greetings
if guild_config.welcome_channel_id:
channel = await self.client.get_or_fetch_channel(
ctx.guild,
guild_config.welcome_channel_id,
)
if channel:
greeting_config = f"✅ | in {channel.mention}"
if guild_config.welcome_message:
greeting_config += (
f" with template:\n```{guild_config.welcome_message}```"
)
else:
greeting_config += " without custom template."
else:
greeting_config = "❌ | enable the module with `/config greetings channel`"
else:
greeting_config = "❌ | enable the module with `/config greetings channel`"
embed.add_field(name="GREETINGS", value=greeting_config, inline=False)
# boosts
if guild_config.boost_channel_id:
channel = await self.client.get_or_fetch_channel(
ctx.guild,
guild_config.boost_channel_id,
)
if channel:
boost_config = f"✅ | in {channel.mention}"
if guild_config.boost_message:
if guild_config.boost_image_url:
boost_config += f" with custom image and template:\n```{guild_config.boost_message}```"
else:
boost_config += (
f" with custom template:\n```{guild_config.boost_message}```"
)
else:
if guild_config.boost_image_url:
boost_config += " with custom image, but no template."
else:
boost_config += " without custom image or template."
else:
boost_config = "❌ | enable the module with `/config boosts channel`"
else:
boost_config = "❌ | enable the module with `/config boosts channel`"
embed.add_field(name="BOOSTS", value=boost_config, inline=False)
# levels
if guild_config.level_message_type == 0:
level_config = "❌ | enable levels with `/config levels enable`"
elif guild_config.level_message_type == 1:
level_config = "✅ | whimsical/sarcastic announcements"
else:
level_config = "✅ | generic announcements"
if guild_config.level_channel_id and guild_config.level_message_type != 0:
channel = await self.client.get_or_fetch_channel(
ctx.guild,
guild_config.level_channel_id,
)
if channel:
level_config += f" in {channel.mention}"
else:
level_config += " in the user's current channel"
else:
if guild_config.level_message_type != 0:
level_config += " in the user's current channel"
if guild_config.level_message and guild_config.level_message_type == 2:
level_config += f" with template:\n```{guild_config.level_message}```"
if not guild_config.level_message and guild_config.level_message_type == 2:
level_config += f" with template:\n```{strings['level_up']}```"
embed.add_field(name="LEVELS", value=level_config, inline=False)
await ctx.respond(embed=embed)

View file

@ -1,20 +0,0 @@
from lib.embeds.error import MiscErrors
from lib.embeds.info import MiscInfo
from services.config_service import GuildConfig
async def set_cmd(ctx, prefix):
if len(prefix) > 25:
return await ctx.respond(embed=MiscErrors.prefix_too_long(ctx))
guild_config = GuildConfig(
ctx.guild.id,
) # generate a guild_config for if it didn't already exist
GuildConfig.set_prefix(guild_config.guild_id, prefix)
await ctx.respond(embed=MiscInfo.set_prefix(ctx, prefix))
async def get_cmd(ctx):
prefix = GuildConfig.get_prefix(ctx.guild.id)
await ctx.respond(embed=MiscInfo.get_prefix(ctx, prefix))

View file

@ -6,7 +6,7 @@ from discord.ext import bridge, commands, tasks
from Client import LumiBot
from lib import checks
from modules.config import set_prefix
from modules.config import c_prefix
from modules.misc import avatar, backup, info, introduction, invite, ping, xkcd
@ -69,7 +69,7 @@ class Misc(commands.Cog):
@commands.guild_only()
@checks.allowed_in_channel()
async def prefix_command(self, ctx) -> None:
await set_prefix.get_cmd(ctx)
await c_prefix.get_prefix(ctx)
@bridge.bridge_command(
name="info",