Skip to content
Merged
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
182 changes: 166 additions & 16 deletions DexScript/github/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class InstallerConfig:
"""

github = ["Dotsian/DexScript", "dev"]
files = ["__init__.py", "cog.py", "commands.py", "parser.py", "utils.py"]
files = ["__init__.py", "cog.py", "commands.py", "parser.py", "utils.py", "config.toml"]
appearance = {
"logo": f"{ASSET_PATH}/DexScriptLogo.png",
"logo_error": f"{ASSET_PATH}/DexScriptLogoError.png",
Expand Down Expand Up @@ -71,15 +71,10 @@ def __init__(self, installer, embed_type="setup"):

self.installer = installer

match embed_type:
case "setup":
self.setup()
case "error":
self.error()
case "installed":
self.installed()
case "uninstalled":
self.uninstalled()
if not hasattr(self, embed_type):
return

getattr(self, embed_type)()

def setup(self):
self.title = "DexScript Installation"
Expand Down Expand Up @@ -139,6 +134,15 @@ def uninstalled(self):

self.set_thumbnail(url=config.appearance["logo"])

def config(self):
with open(f"{config.path}/config.toml") as file:
file_contents = file.read()

self.title = "DexScript Configuration"
self.description = f"```toml\n{file_contents}\n```"
self.color = discord.Color.from_str("#03BAFC")
self.timestamp = datetime.now()


class InstallerView(discord.ui.View):
def __init__(self, installer):
Expand Down Expand Up @@ -177,11 +181,153 @@ async def uninstall_button(self, interaction: discord.Interaction, _: discord.ui
await interaction.message.edit(**self.installer.interface.fields)
await interaction.response.defer()

@discord.ui.button(
style=discord.ButtonStyle.secondary,
label="Config",
disabled=not os.path.isfile(f"{config.path}/config.toml")
)
async def config_button(self, interaction: discord.Interaction, _: discord.ui.Button):
self.installer.interface.embed = InstallerEmbed(self.installer, "config")
self.installer.interface.view = ConfigView(self.installer)

await interaction.message.edit(**self.installer.interface.fields)
await interaction.response.defer()

@discord.ui.button(style=discord.ButtonStyle.red, label="Exit")
async def quit_button(self, interaction: discord.Interaction, _: discord.ui.Button):
self.install_button.disabled = True
self.uninstall_button.disabled = True
self.quit_button.disabled = True
for item in self.children:
item.disabled = True

await interaction.message.edit(**self.installer.interface.fields)
await interaction.response.defer()


class ConfigModal(discord.ui.Modal):
def __init__(self, installer, setting: str):
self.installer = installer
self.setting = setting

super().__init__(title=f"Editing `{setting}`")

value = discord.ui.TextInput(label="New value", required=True)

async def on_submit(self, interaction: discord.Interaction):
with open(f"{config.path}/config.toml") as file:
lines = [x.strip() for x in file.readlines()]
new_lines = []

for line in lines:
if not line.startswith(self.setting):
new_lines.append(line + "\n")
continue

full_value = self.value.value
new_value = f'"{full_value}"'

if full_value.lower() in ["true", "false"]:
new_value = full_value.lower()
elif full_value.startswith("[") and full_value.endswith("]"):
new_value = full_value

new_lines.append(f"{self.setting} = {new_value}\n")

with open(f"{config.path}/config.toml", "w") as write_file:
write_file.writelines(new_lines)

self.installer.interface.embed = InstallerEmbed(self.installer, "config")

await interaction.message.edit(**self.installer.interface.fields)

await interaction.response.send_message(
f"Updated `{self.setting}` to `{self.value.value}`!",
ephemeral=True
)


class ConfigSelect(discord.ui.Select):
def __init__(self, installer):
self.installer = installer

options = []

with open(f"{config.path}/config.toml") as file:
description = ""

for line in file.readlines():
if line.rstrip() in ["\n", "", "]"] or line.startswith(" "):
continue

if line.startswith("#"):
description = line[2:]
continue

name = line.split(" ")[0]

options.append(
discord.SelectOption(label=name, value=name, description=description)
)

description = ""

super().__init__(placeholder="Edit setting", max_values=1, min_values=1, options=options)

async def callback(self, interaction: discord.Interaction):
await interaction.response.send_modal(ConfigModal(self.installer, self.values[0]))


class ConfigView(discord.ui.View):
def __init__(self, installer):
super().__init__()
self.installer = installer

back_button = discord.ui.Button(label="Back", style=discord.ButtonStyle.primary)
reset_button = discord.ui.Button(label="Reset", style=discord.ButtonStyle.grey)
quit_button = discord.ui.Button(label="Exit", style=discord.ButtonStyle.red)

back_button.callback = self.back_button
reset_button.callback = self.reset_button
quit_button.callback = self.quit_button

self.add_item(back_button)
self.add_item(ConfigSelect(installer))
self.add_item(reset_button)
self.add_item(quit_button)

async def back_button(self, interaction: discord.Interaction):
self.installer.interface.embed = InstallerEmbed(self.installer, "setup")
self.installer.interface.view = InstallerView(self.installer)

await interaction.message.edit(**self.installer.interface.fields)
await interaction.response.defer()

async def reset_button(self, interaction: discord.Interaction):
request = requests.get(
f"https://api.github.com/repos/{config.github[0]}/"
"contents/DexScript/package/config.toml",
{"ref": config.github[1]}
)

if request.status_code != requests.codes.ok:
await interaction.response.send_message(
f"Failed to reset config file `({request.status_code})`", ephemeral=True
)
return

request = request.json()
content = b64decode(request["content"])

with open(f"{config.path}/config.toml", "w") as opened_file:
opened_file.write(content.decode())

self.installer.interface.embed = InstallerEmbed(self.installer, "config")

await interaction.message.edit(**self.installer.interface.fields)

await interaction.response.send_message("Successfully reset config file", ephemeral=True)

async def quit_button(self, interaction: discord.Interaction):
for item in self.children:
item.disabled = True

await interaction.message.edit(**self.installer.interface.fields)
await interaction.response.defer()
Expand Down Expand Up @@ -274,11 +420,15 @@ async def install(self):

await bot.remove_cog("DexScript") # type: ignore

link = f"https://api.github.com/repos/{config.github[0]}/contents/"
link = f"https://api.github.com/repos/{config.github[0]}/contents"

os.makedirs(config.path, exist_ok=True)

for file in config.files:
if file.endswith(".toml") and os.path.isfile(f"{config.path}/{file}"):
logger.log(f"{file} already exists, skipping", "INFO")
continue

logger.log(f"Fetching {file} from '{link}/DexScript/package'", "INFO")

request = requests.get(f"{link}/DexScript/package/{file}", {"ref": config.github[1]})
Expand All @@ -293,7 +443,7 @@ async def install(self):
content = b64decode(request["content"])

with open(f"{config.path}/{file}", "w") as opened_file:
opened_file.write(content.decode("UTF-8"))
opened_file.write(content.decode())

logger.log(f"Installed {file} from '{link}/DexScript/package'", "INFO")

Expand Down Expand Up @@ -334,7 +484,7 @@ def latest_version(self):
if pyproject_request.status_code != requests.codes.ok:
return

toml_content = b64decode(pyproject_request.json()["content"]).decode("UTF-8")
toml_content = b64decode(pyproject_request.json()["content"]).decode()
new_version = re.search(r'version\s*=\s*"(.*?)"', toml_content)

if not new_version:
Expand Down
39 changes: 8 additions & 31 deletions DexScript/package/cog.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
ASSET_PATH = "https://raw.githubusercontent.com/Dotsian/DexScript/refs/heads/main/assets"


def check_dexscript_user(ctx):
return ctx.message.author.id in config.dexscript_user_ids

class DexScript(commands.Cog):
"""
DexScript commands.
Expand All @@ -25,12 +28,12 @@ def __init__(self, bot):

@staticmethod
def check_version():
if not config.versioncheck:
if not config.version_warning:
return None

request = requests.get(
"https://api.github.com/repos/Dotsian/DexScript/contents/pyproject.toml",
{"ref": config.reference},
{"ref": config.branch},
)

if request.status_code != requests.codes.ok:
Expand All @@ -50,6 +53,7 @@ def check_version():

@commands.command()
@commands.is_owner()
@commands.check(check_dexscript_user)
async def run(self, ctx: commands.Context, *, code: str):
"""
Executes DexScript code.
Expand Down Expand Up @@ -84,6 +88,7 @@ async def run(self, ctx: commands.Context, *, code: str):

@commands.command()
@commands.is_owner()
@commands.check(check_dexscript_user)
async def about(self, ctx: commands.Context):
"""
Displays information about DexScript.
Expand Down Expand Up @@ -120,6 +125,7 @@ async def about(self, ctx: commands.Context):

@commands.command()
@commands.is_owner()
@commands.check(check_dexscript_user)
async def installer(self, ctx: commands.Context, reference: str = "main"):
"""
Displays the DexScript installer.
Expand Down Expand Up @@ -148,32 +154,3 @@ async def installer(self, ctx: commands.Context, reference: str = "main"):

case _:
await ctx.send(f"Request raised error code `{request.status_code}`.")

@commands.command()
@commands.is_owner()
async def setting(self, ctx: commands.Context, setting: str, value: str | None = None):
"""
Changes a setting based on the value provided.

Parameters
----------
setting: str
The setting you want to toggle.
value: str | None
The value you want to set the setting to.
"""
setting = setting.lower()

if setting not in vars(config):
await ctx.send(f"`{setting}` is not a valid setting.")
return

setting_value = vars(config)[setting]
new_value = value

if isinstance(setting_value, bool):
new_value = bool(value) if value else not setting_value

setattr(config, setting, new_value)

await ctx.send(f"`{setting}` has been set to `{new_value}`")
14 changes: 14 additions & 0 deletions DexScript/package/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Whether or not DexScript will warn you for running an outdated version.
version-warning = true

# The command groups that DexScript will load.
command-groups = ["Global", "Emoji", "Eval", "File", "Filter", "Template"]

# A list of user IDs that will be able to execute DexScript commands.
dexscript-user-ids = []

# Displays additional information for error handling.
debug = false

# The GitHub branch that will be used for version checking and other misc features.
branch = "main"
6 changes: 3 additions & 3 deletions DexScript/package/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@ def __init__(self, ctx, bot):
and issubclass(o, commands.DexCommand)
and not issubclass(o, commands.Global)
and o.__name__ != "DexCommand"
and o.__name__ in config.modules
and o.__name__ in config.command_groups
),
)

self.global_methods = [x for x in dir(commands.Global) if not x.startswith("__")]

if "Global" not in config.modules:
if "Global" not in config.command_groups:
self.global_methods = []

def create_value(self, line):
Expand All @@ -62,7 +62,7 @@ def create_value(self, line):
Types.BOOLEAN: lower in ["true", "false"],
Types.HEX: lower.startswith("#"),
Types.ARRAY: lower.startswith("[") and lower.endswith("]"),
Types.NONE: lower == "NIL"
Types.NONE: lower == "nil"
}

for key, operation in type_dict.items():
Expand Down
Loading
Loading