Skip to content
This repository has been archived by the owner on Nov 22, 2021. It is now read-only.

Commit

Permalink
Merge pull request #33 from parafoxia/rc.1
Browse files Browse the repository at this point in the history
Merge version rc.1 into master to release
  • Loading branch information
parafoxia authored Aug 22, 2020
2 parents ec777c4 + 79b5379 commit 4dbff3e
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 23 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "Solaris-Bot"
version = "1.0.0-beta.4"
version = "1.0.0-rc.1"
description = "A Discord bot designed to make your server a safer and better place."

license = "GPLv3"
Expand Down
92 changes: 87 additions & 5 deletions solaris/bot/cogs/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,18 @@
from beautifultable import BeautifulTable
from discord.ext import commands

from solaris.utils import SUPPORT_GUILD_INVITE_LINK, chron, converters, menu, string
from solaris.utils import (
INFO_ICON,
LOADING_ICON,
SUCCESS_ICON,
SUPPORT_GUILD_INVITE_LINK,
checks,
chron,
converters,
menu,
string,
)
from solaris.utils.modules import deactivate


class DetailedServerInfoMenu(menu.MultiPageMenu):
Expand All @@ -54,6 +65,73 @@ def __init__(self, ctx, table_info):
super().__init__(ctx, pagemaps, timeout=120.0)


class LeavingMenu(menu.SelectionMenu):
def __init__(self, ctx):
pagemap = {
"header": "Leave Wizard",
"title": "Leaving already?",
"description": (
"If you remove Solaris from your server, all server information Solaris has stored, as well as any roles and channels Solaris has created, will be deleted."
f"If you are having issues with Solaris, consider joining the support server to try and find a resolution - select {ctx.bot.info} to get an invite link.\n\n"
"Are you sure you want to remove Solaris from your server?"
),
"thumbnail": ctx.bot.user.avatar_url,
}
super().__init__(ctx, ["confirm", "cancel", "info"], pagemap, timeout=120.0)

async def start(self):
r = await super().start()

if r == "confirm":
pagemap = {
"header": "Leave Wizard",
"description": "Please wait... This should only take a few seconds.",
"thumbnail": LOADING_ICON,
}
await self.switch(pagemap, clear_reactions=True)
await self.leave()
elif r == "cancel":
await self.stop()
elif r == "info":
pagemap = {
"header": "Leave Wizard",
"title": "Let's get to the bottom of this!",
"description": f"Click [here]({SUPPORT_GUILD_INVITE_LINK}) to join the support server.",
"thumbnail": INFO_ICON,
}
await self.switch(pagemap, clear_reactions=True)

async def leave(self):
dlc_id, dar_id = (
await self.bot.db.record(
"SELECT DefaultLogChannelID, DefaultAdminRoleID FROM system WHERE GuildID = ?", self.ctx.guild.id
)
or [None] * 2
)

await deactivate.everything(self.ctx)

if self.ctx.guild.me.guild_permissions.manage_roles and (dar := self.ctx.guild.get_role(dar_id)) is not None:
await dar.delete(reason="Solaris is leaving the server.")

if (
self.ctx.guild.me.guild_permissions.manage_channels
and (dlc := self.ctx.guild.get_channel(dlc_id)) is not None
):
await dlc.delete(reason="Solaris is leaving the server.")

pagemap = {
"header": "Leave Wizard",
"title": "Sorry to see you go!",
"description": (
f"If you ever wish to reinvite Solaris, you can do so by clicking [here]({self.bot.admin_invite}) (recommended permissions), or [here]({self.bot.non_admin_invite}) (minimum required permissions).\n\n"
"The Solaris team wish you and your server all the best."
),
}
await self.switch(pagemap)
await self.ctx.guild.leave()


class Meta(commands.Cog):
"""Commands for retrieving information regarding Solaris, from invitation links to detailed bot statistics."""

Expand Down Expand Up @@ -252,9 +330,9 @@ async def userinfo_command(
ctx=ctx,
header="Information",
description=(
f"This member is also known as {target.display_name} in this server."
f"This member is known as both **{target.name}** and **{target.display_name}** in this server."
if target.nick
else "This member does not have a nickname in this server."
else f"This member is known as **{target.name}** in this server."
),
colour=target.colour,
thumbnail=target.avatar_url,
Expand Down Expand Up @@ -453,9 +531,13 @@ async def icon_command(self, ctx):
)
)

@commands.command(name="leave")
@commands.command(
name="leave",
help="Utility to make Solaris clean up before leaving the server. This involves deactivating all active modules and deleting the default log channel and the default admin role should they still exist.",
)
@checks.author_can_configure()
async def leave_command(self, ctx):
pass
await LeavingMenu(ctx).start()

@commands.command(name="shutdown")
@commands.is_owner()
Expand Down
35 changes: 25 additions & 10 deletions solaris/bot/cogs/mod.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ async def kick_command(
else:
count = 0

async with ctx.channel.typing():
async with ctx.typing():
for target in targets:
try:
await target.kick(reason=f"{reason} - Actioned by {ctx.author.name}")
Expand Down Expand Up @@ -90,7 +90,7 @@ async def ban_command(
else:
count = 0

async with ctx.channel.typing():
async with ctx.typing():
for target in targets:
try:
await target.ban(
Expand All @@ -107,14 +107,29 @@ async def ban_command(
else:
await ctx.send(f"{self.bot.cross} No members were banned.")

@commands.command(name="unban")
@commands.command(
name="unban",
help="Unbans one or more users from your server. You must provide the username and discriminator of the user you want to unban in the following format: Username#0000.",
)
@commands.has_permissions(ban_members=True)
@commands.bot_has_permissions(send_messages=True, ban_members=True)
async def unban_command(
self, ctx, targets: commands.Greedy[discord.Member], *, reason: t.Optional[str] = "No reason provided."
self, ctx, targets: commands.Greedy[converters.BannedUser], *, reason: t.Optional[str] = "No reason provided."
):
# TODO: Actually write this.
await ctx.send("Not implemented.")
if not targets:
await ctx.send(f"{self.bot.cross} No valid targets were passed.")
else:
count = 0

async with ctx.typing():
for target in targets:
await ctx.guild.unban(target, reason=f"{reason} - Actioned by {ctx.author.name}")
count += 1

if count > 0:
await ctx.send(f"{self.bot.tick} {count:,} user(s) were unbanned.")
else:
await ctx.send(f"{self.bot.cross} No users were unbanned.")

@commands.command(name="clear", aliases=["clr"], help="Clears up to 100 messages from a channel.")
@commands.has_permissions(manage_messages=True)
Expand All @@ -128,7 +143,7 @@ def _check(m):
f"{self.bot.cross} The number of messages to clear is outside valid bounds - it should be between 1 and 100 inclusive."
)
else:
async with ctx.channel.typing():
async with ctx.typing():
await ctx.message.delete()
cleared = await ctx.channel.purge(
limit=scan, check=_check, after=dt.datetime.utcnow() - dt.timedelta(days=14)
Expand All @@ -149,7 +164,7 @@ async def clearchannel_command(
):
ctx_is_target = ctx.channel == target

async with ctx.channel.typing():
async with ctx.typing():
await target.clone(reason=f"{reason} - Actioned by {ctx.author.name}")
await target.delete(reason=f"Channel cleared. - Actioned by {ctx.author.name}")

Expand Down Expand Up @@ -194,7 +209,7 @@ async def setnickname_command(
async def clearnickname_command(self, ctx, targets: commands.Greedy[discord.Member]):
count = 0

async with ctx.channel.typing():
async with ctx.typing():
for target in targets:
try:
await target.edit(nick=None)
Expand All @@ -220,7 +235,7 @@ async def clearnickname_command(self, ctx, targets: commands.Greedy[discord.Memb
async def unhoistnicknames_command(self, ctx, *, strict: t.Optional[bool] = False):
count = 0

async with ctx.channel.typing():
async with ctx.typing():
for member in ctx.guild.members:
try:
match = re.match(
Expand Down
25 changes: 20 additions & 5 deletions solaris/bot/cogs/modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@
import discord
from discord.ext import commands

from solaris.utils import LOADING_ICON, SUCCESS_ICON, checks, menu, modules
from solaris.utils import ERROR_ICON, LOADING_ICON, SUCCESS_ICON, checks, menu, modules


class SetupMenu(menu.SelectionMenu):
def __init__(self, ctx):
pagemap = {
"header": "Setup",
"header": "Setup Wizard",
"title": "Hello!",
"description": "Welcome to the Solaris first time setup! You need to run this before you can use most of Solaris' commands, but you only ever need to run once.\n\nIn order to operate effectively in your server, Solaris needs to create a few things:",
"thumbnail": ctx.bot.user.avatar_url,
Expand Down Expand Up @@ -57,7 +57,7 @@ async def start(self):

if r == "confirm":
pagemap = {
"header": "Setup",
"header": "Setup Wizard",
"description": "Please wait... This should only take a few seconds.",
"thumbnail": LOADING_ICON,
}
Expand All @@ -84,7 +84,14 @@ async def run(self):
)
await lc.send(f"{self.bot.tick} The log channel has been created and set to {lc.mention}.")
else:
await self.switch("setup log channel failed", clear_reactions=True)
pagemap = {
"header": "Setup Wizard",
"title": "Setup failed",
"description": "The log channel could not be created as Solaris does not have the Manage Channels permission. The setup can not continue.",
"thumbnail": ERROR_ICON,
}
await self.switch(pagemap)
return

if not await modules.retrieve.system__adminrole(self.bot, self.ctx.guild):
if self.ctx.guild.me.guild_permissions.manage_roles:
Expand All @@ -101,7 +108,14 @@ async def run(self):
)
await lc.send(f"{self.bot.tick} The admin role has been created and set to {ar.mention}.")
else:
await self.switch("setup admin role failed", clear_reactions=True)
pagemap = {
"header": "Setup Wizard",
"title": "Setup failed",
"description": "The admin role could not be created as Solaris does not have the Manage Roles permission. The setup can not continue.",
"thumbnail": ERROR_ICON,
}
await self.switch(pagemap)
return

await self.complete()

Expand Down Expand Up @@ -134,6 +148,7 @@ async def on_ready(self):
@checks.bot_has_booted()
@checks.first_time_setup_has_not_run()
@checks.author_can_configure()
@checks.guild_is_not_discord_bot_list()
async def setup_command(self, ctx):
await SetupMenu(ctx).start()

Expand Down
16 changes: 16 additions & 0 deletions solaris/utils/checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,19 @@ async def predicate(ctx):
return True

return commands.check(predicate)


class GuildIsDiscordBotList(CustomCheckFailure):
def __init__(self):
super().__init__(
"In order to prevent unintended disruption, this command can not be run in the Discord Bot List server. If you wish to test module functionality, you will need to do so in another server."
)


def guild_is_not_discord_bot_list():
async def predicate(ctx):
if ctx.guild.id == 264445053596991498:
raise GuildIsDiscordBotList()
return True

return commands.check(predicate)
6 changes: 6 additions & 0 deletions solaris/utils/converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,9 @@ async def convert(self, ctx, arg):
ctx.guild.members,
name=str(Search(arg, [m.display_name for m in ctx.guild.members]).best(min_accuracy=0.75)),
)


class BannedUser(commands.Converter):
async def convert(self, ctx, arg):
if ctx.guild.me.guild_permissions.ban_members:
return next(filter(lambda u: str(u) == arg, [e.user for e in await ctx.guild.bans()]))
4 changes: 2 additions & 2 deletions solaris/utils/embed.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ def build(self, **kwargs):
embed.set_author(name=kwargs.get("header", "Solaris"))
embed.set_footer(
text=kwargs.get(
"footer", f"Invoked by {ctx.author.display_name}" if ctx else "Server Safety and Security Systems"
"footer", f"Invoked by {ctx.author.display_name}" if ctx else r"\o/"
),
icon_url=ctx.author.avatar_url if ctx else Embed.Empty,
icon_url=ctx.author.avatar_url if ctx else self.bot.user.avatar_url,
)

# FIXME: In d.py 1.4, `Embed.Empty` will be supported.
Expand Down

0 comments on commit 4dbff3e

Please sign in to comment.