Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v2.4] event planner #112

Closed
wants to merge 19 commits into from
Closed
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
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
<img width="512" height="512" src="https://raw.githubusercontent.com/s0lst1ce/assets/master/sunflower_logo_1.png">
</p>

[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)]

# Botanist

This program is a Discord bot which is basically a mod to the real time messaging platform. It is built using discord.py API which offers full compatibility to the official Discord API.
Expand Down Expand Up @@ -186,6 +188,14 @@ Allows the developers to update the bot and notify all server owners of the chan

Gives several time-related commands to ease organization. For now this only includes a remind function but an event planner is in the works.

| Group | Command | Arguments | Description | Clearance |
| ----- | :------: | :-------------------: | :----------------------------------------------------------: | --------- |
| | `remind` | `<date> [message...]` | returns the specified message after the specified amount of time. To precise the delay before sending the message use the following format: `1d15h6m1s` where `d` stands for days, `h` for hours, `m` for minutes and `s` for seconds. The numbers preceding them must be integers and represent the number of units to wait for (be it days, hours, minutes or seconds). All other words given as argument will form the message's content and will be sent in PM to the user after the specified delay has elapsed. | * |
| Group | Command | Arguments | Description | Clearance |
| ----- | :-------: | :-------------------: | :----------------------------------------------------------: | :-------: |
| | `remind` | `<date> [message...]` | returns the specified message after the specified amount of time. To precise the delay before sending the message use the following format: `1d15h6m1s` where `d` stands for days, `h` for hours, `m` for minutes and `s` for seconds. The numbers preceding them must be integers and represent the number of units to wait for (be it days, hours, minutes or seconds). All other words given as argument will form the message's content and will be sent in PM to the user after the specified delay has elapsed. | * |
| event | `new ` | `<name>` | creates a live event creation session in Direct Message (DM). The bot will ask the user to fill in the required and optional fields of `name`. | * |
| event | `send` | `<name>` | Sends the event in the current channel. | * |
| event | `rm` | `<name>` | Deletes the `name` event from the user’s selection of events | * |
| event | `list` | | Returns the list of all events for this user. | * |
| event | `edit` | `<name> <field>` | lets the user only edit `field` for `name` event | * |
| event | `preview` | `<name>` | returns the current embed bound to `name` | * |


5 changes: 3 additions & 2 deletions src/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ async def run(self, ctx):
while not good:
lang = await self.get_answer(
ctx,
f"I'm an international robot and tend to opperate in many places. This also means that I speak many language! The list of supported languages can be found on my website {WEBSITE}. So which do you want to speak with? Languages are expressed in their 2 letter code. You can choose from this list: {ALLOWED_LANGS}",
f"I'm an international robot and tend to operate in many places. This also means that I speak many language! The list of supported languages can be found on my website {WEBSITE}. So which do you want to speak with? Languages are expressed in their 2 letter code.",
)
if not self.is_valid(lang.content):
continue
Expand All @@ -63,7 +63,7 @@ async def run(self, ctx):
"Role setup is **mandatory** for the bot to work correctly. Otherwise no one will be able to use administration commands."
)
await self.config_channel.send(
"**\nStarting role configuration**\nThis bot uses two level of clearance for its commands.\nThe first one is the **manager** level of clearance. Everyone with a role with this clearance can use commands related to server management. This includes but is not limited to message management and issuing warnings.\nThe second level of clearance is **admin**. Anyone who has a role with this level of clearance can use all commands but the ones related to the bot configuration. This is reserved to the server owner. All roles with this level of clearance inherit **manager** clearance as well."
"**\nStarting role configuration**\nThis bot uses two hierachical level of clearance plus an independant one for its commands.\nThe first level of clearance is **admin**. Anyone who has a role with this level of clearance can use all commands but the ones related to the bot configuration. This is reserved to the server owner. All roles with this level of clearance inherit **manager** clearance as well.\nThe second one is the **manager** level of clearance. Everyone with a role with this clearance can use commands related to server management. This includes but is not limited to message management and issuing warnings.\nThe last is **planner** and allows its bearers to post events in the server."
)

new_roles = []
Expand Down Expand Up @@ -136,6 +136,7 @@ async def run(self, ctx):
with ConfigFile(ctx.guild.id) as conf:
conf["roles"]["manager"] = new_roles[0]
conf["roles"]["admin"] = new_roles[1]
conf["roles"]["planner"] = new_roles[2]

await self.config_channel.send("Successfully updated role configuration")

Expand Down
7 changes: 6 additions & 1 deletion src/exts/development.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,14 @@ async def log(self, ctx):
@commands.command()
async def dev(self, ctx):
"""sends the developement server URL to the author of the message"""
tr = Translator(name, get_lang(ctx))
tr = Translator(name, get_lang(ctx.guild.id))
await ctx.author.send(tr["dev"] + DEV_SRV_URL)

@commands.command()
@is_runner()
async def eval(self, ctx, *, expression):
await ctx.send("```py\n" + eval(expression) + "```")


def setup(bot):
bot.add_cog(Development(bot))
25 changes: 14 additions & 11 deletions src/exts/essentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def __init__(self, bot, cfg_chan_id):

async def run(self, ctx):
# welcome & goodbye messages
tr = Translator(name, get_lang(ctx))
tr = Translator(name, get_lang(ctx.guild.id))
msgs = {
"welcome": [tr["welcome1"], tr["welcome2"]],
"goodbye": [tr["goodbye1"], tr["goodbye2"]],
Expand Down Expand Up @@ -94,7 +94,7 @@ def __init__(self, bot):
@commands.Cog.listener()
async def on_command_error(self, ctx, error):
"""handles command errors"""
#raise error
raise error
local_logger.error(error)
if type(error) in ERRS_MAPPING.keys():
msg = get_embed_err(ERRS_MAPPING[type(error)])
Expand All @@ -108,8 +108,7 @@ async def on_command_error(self, ctx, error):

@commands.Cog.listener()
async def on_guild_join(self, guild):
with open(os.path.join(CONFIG_FOLDER, f"{guild.id}.json"), "w") as file:
json.dump(DEFAULT_SERVER_FILE)
ConfigFile(guild.id, default=DEFAULT_SERVER_FILE)
await guild.owner.send(
f"I was just added to your server. For me to work correctly (or at all) on your server you should send `::init` in any channel of your {guild.name} server."
)
Expand Down Expand Up @@ -147,7 +146,7 @@ async def on_member_remove(self, member):
@commands.command()
async def ping(self, ctx):
"""This command responds with the current latency."""
tr = Translator(name, get_lang(ctx))
tr = Translator(name, get_lang(ctx.guild.id))
latency = self.bot.latency
await ctx.send(EMOJIS["ping_pong"] + tr["latency"].format(latency))

Expand All @@ -167,7 +166,7 @@ async def shutdown(self, ctx):
@commands.command()
@has_auth("manager")
async def clear(self, ctx, *filters):
"""deletes specified <nbr> number of messages in the current channel"""
"""deletes specified <nbr> number of messages in the current channel."""
# building arguments
filters = list(filters)
nbr = None
Expand Down Expand Up @@ -198,7 +197,11 @@ async def clear(self, ctx, *filters):
if period:
hist_args["after"] = period
if nbr and not members:
hist_args["limit"] = nbr + 1
nbr += 1
hist_args["limit"] = nbr
if members:
await ctx.message.delete()

if not (period or nbr):
raise discord.ext.commands.ArgumentParsingError(
"Can't delete all messages of a user!"
Expand All @@ -208,18 +211,18 @@ async def clear(self, ctx, *filters):
now = datetime.datetime.now()
async for msg in ctx.channel.history(**hist_args):
if not members or msg.author in members:
local_logger.info(
local_logger.debug(
f"Deleting message {msg.jump_url} from guild {msg.guild.name}."
)
if (msg.created_at - now).days >= -14:
if (msg.created_at - now).days <= -14:
await msg.delete()
else:
to_del.append(msg)

if nbr != None:
nbr -= 1
if nbr <= 0:
break
nbr -= 1

try:
await ctx.channel.delete_messages(to_del)
Expand All @@ -234,7 +237,7 @@ async def clear(self, ctx, *filters):
@commands.command()
async def status(self, ctx):
"""returns some statistics about the server and their members"""
tr = Translator(name, get_lang(ctx))
tr = Translator(name, get_lang(ctx.guild.id))
stats = discord.Embed(
name=tr["stats_name"],
description=tr["stats_description"].format(
Expand Down
30 changes: 22 additions & 8 deletions src/exts/poll.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def __init__(self, bot, cfg_chan_id):

async def run(self, ctx):
try:
tr = Translator(name, get_lang(ctx))
tr = Translator(name, get_lang(ctx.guild.id))
await self.config_channel.send(tr["start_conf"])
pursue = await self.get_yn(ctx, tr["pursue"])
if not pursue:
Expand Down Expand Up @@ -101,6 +101,15 @@ async def on_raw_reaction_add(self, payload):
"""currently makes this checks for ALL channels. Might want to change the behavior to allow reactions on other msgs"""
# getting poll_allowed_chans
# @is_init

# fetching concerned message and the user who added the reaction
message = await self.bot.get_channel(payload.channel_id).fetch_message(
payload.message_id
)
# making sure we're not in a DM
if not isinstance(message.channel, discord.TextChannel):
return

with ConfigFile(payload.guild_id) as conf:
poll_allowed_chans = conf["poll_channels"]

Expand All @@ -109,10 +118,6 @@ async def on_raw_reaction_add(self, payload):
payload.channel_id in poll_allowed_chans
):

# fetching concerned message and the user who added the reaction
message = await self.bot.get_channel(payload.channel_id).fetch_message(
payload.message_id
)
user = self.bot.get_user(payload.user_id)

if f"{message.id}.json" in os.listdir(POLL_FOLDER):
Expand All @@ -122,11 +127,13 @@ async def on_raw_reaction_add(self, payload):
if str(payload.emoji) in settings["unicode"]:
good = True
else:
#this is a custom emoji
# this is a custom emoji
if payload.emoji.id in settings["custom"]:
good = True
if not good:
local_logger.debug("User tried to add some forbidden reaction to an extended poll.")
local_logger.debug(
"User tried to add some forbidden reaction to an extended poll."
)
await message.remove_reaction(payload.emoji, user)
return

Expand Down Expand Up @@ -203,11 +210,18 @@ async def on_raw_reaction_remove(self, payload):
async def on_message(self, message):
if message.author == self.bot.user:
return
if isinstance(message.channel, discord.DMChannel):
# we're in a DM
return

if not was_init(message):
await message.channel.send(embed=get_embed_err(ERR_NOT_SETUP))
return

# making sure we're not in a DM
if not isinstance(message.channel, discord.TextChannel):
return

# getting poll_allowed_chans
# poll_allowed_chans = ConfigFile(message.guild.id)["poll_channels"]
with ConfigFile(message.guild.id) as conf:
Expand Down Expand Up @@ -357,7 +371,7 @@ async def extended(self, ctx, *words):
for choice in choices.split("\n"):
it = choice.split(" ", 1)[0]
if it.startswith("<"):
#this is a custom emoji
# this is a custom emoji
emotes["custom"].append(int(it.split(":", 2)[2][:-1]))
else:
emotes["unicode"].append(it)
Expand Down
4 changes: 2 additions & 2 deletions src/exts/role.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def __init__(self, bot, config_chan_id):
super().__init__(bot, config_chan_id)

async def run(self, ctx):
tr = Translator(name, get_lang(ctx))
tr = Translator(name, get_lang(ctx.guild.id))
try:
await ctx.send(tr["start_conf"])
free_roles = []
Expand Down Expand Up @@ -88,7 +88,7 @@ async def role(self, ctx):
@role.command()
async def add(self, ctx, member: discord.Member, *roles: discord.Role):
"""Gives <member> listed <roles> roles"""
tr = Translator(name, get_lang(ctx))
tr = Translator(name, get_lang(ctx.guild.id))
# checking if member can self-assing role(s)
if not has_auth("admin")(ctx):
allowed_roles = []
Expand Down
Loading