Skip to content

Commit

Permalink
update file structure
Browse files Browse the repository at this point in the history
  • Loading branch information
arthuralvim committed Nov 10, 2021
1 parent fe1c676 commit 70fc6ef
Show file tree
Hide file tree
Showing 27 changed files with 1,506 additions and 928 deletions.
File renamed without changes.
24 changes: 0 additions & 24 deletions Pipfile

This file was deleted.

489 changes: 0 additions & 489 deletions Pipfile.lock

This file was deleted.

2 changes: 1 addition & 1 deletion Procfile
Original file line number Diff line number Diff line change
@@ -1 +1 @@
worker: python pybr2021/bot.py
worker: python bot.py
44 changes: 15 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,23 @@
# Robô no Discord da Python Brasil 2021
# Robô do Discord da Scipy Latin America 2021

### Fazendo o Bot Funcionar

```bash
$ poetry install
$ poetry run python bot.py
```

### Comandos disponíveis

#### Config

- `pybr!config roles`
- Cria os roles/perfis
- `pybr!config canais`
- Cria as categories e os canais de texto e voz e atribui as permissões corretas

### Adicionando novos canais e roles

#### Roles
Adicione uma tupla na lista [new_roles](https://github.com/rougeth/pybr2021-discord-bot/blob/main/pybr2021/bot.py#L50-L54), exemplo:

```python
new_roles = [
("root", discord.Permissions.all(), 90),
("Organização", org_permissions, 80),
("Voluntariado", None, 70),
("Novo Role", None, 60),
]
```
- `scibot!config info`: - Retorna informações do canal
- `scibot!config roles`: - Cria as roles descritas em src/roles.py
- `scibot!config canais`: - Cria os canaos descritos em src/channels.py
- `scibot!config reset-roles`: - Deleta roles criadas pelo bot.
- `scibot!config reset-canais`: - Deleta canais criadas pelo bot.

Os elementos da tupla devem ser, em ordem:
1. Nome do novo perfil/role.
2. As permissões do novo perfil. Deve ser uma instância de `discord.Permissions` ([doc](https://discordpy.readthedocs.io/en/stable/api.html?highlight=permissionoverwrite#discord.Permissions)) ou `None`.
3. A posição do novo perfil em relação aos demais. Quanto maior o número, maior na hierarquia.


#### Canais
Para criar novos canais, a mudança é um pouco maior. Siga os exemplos no [próprio código](https://github.com/rougeth/pybr2021-discord-bot/blob/main/pybr2021/bot.py#L97-L143) e consulte a documentação do [discord.py](https://discordpy.readthedocs.io/).
#### Agradecimentos

Referências:
- https://support.discord.com/hc/en-us/articles/214836687-Role-Management-101
Código totalmente baseado no bot do discord da Python Brasil.
https://github.com/rougeth/pybr2021-discord-bot
190 changes: 190 additions & 0 deletions bot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
# snake.bot

import asyncio
import discord
import logging
import sentry_sdk
import sys
from decouple import config
from discord.ext import commands
from src.roles import ROLES, get_or_create_role, roles_msg
from src.channels import CHANNELS, create_channel
from src.icons import icon_check, icon_1, icon_2, icon_3, icon_time
from src.helpers import get_destination

logger = logging.getLogger('discord')
log_level = logging.INFO
logger.setLevel(log_level)
log_formatter = logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s')
terminal_handler = logging.StreamHandler()
file_handler = logging.FileHandler(filename='discord.log', encoding='utf-8', mode='w')
terminal_handler.setLevel(log_level)
file_handler.setLevel(log_level)
terminal_handler.setFormatter(log_formatter)
file_handler.setFormatter(log_formatter)
logger.addHandler(terminal_handler)
logger.addHandler(file_handler)


DISCORD_TOKEN = config("DISCORD_TOKEN")
SENTRY_TOKEN = config("SENTRY_TOKEN", default=None)

if SENTRY_TOKEN:
sentry_sdk.init(SENTRY_TOKEN, traces_sample_rate=1.0)

bot = commands.Bot(command_prefix="scibot!", intents=discord.Intents.all())

# bot.add_cog(cogs.Reminders(bot))
# bot.add_cog(cogs.Greetings(bot))
# bot.add_cog(cogs.Greetings2(bot))
# bot.add_cog(cogs.Schedules(bot))


@bot.event
async def on_error(event, *args, **kwargs):
"""Don't ignore the error, causing Sentry to capture it."""
logger.exception("Exception while handling event. event={event!r}, args={args!r}, kwargs={kwargs!r}")
if SENTRY_TOKEN:
_, e, traceback = sys.exc_info()
sentry_sdk.capture_exception(e)
logger.info(f"Exception sent to Sentry. e={e!r}")


@bot.event
async def on_message(message):
if not message.author.bot and message.content.lower() == "ping":
await message.channel.send("pong")
await bot.process_commands(message)


@bot.group(name="config", invoke_without_command=True)
async def config_group(ctx, *args):
await ctx.channel.send(
"Comandos Disponíveis:\n"
"**info**\n - Mostrar informações dos canais\n"
"**roles**\n - Cria todos os roles necessários\n"
"**canais**\n - Cria todos os canais necessários\n"
"**reset-roles**\n - Deleta todos os roles criados pelo bot\n"
"**reset-canais**\n - Deleta todos os canais criados pelo bot\n"
)


@config_group.command(name="info")
@commands.has_role("Moderator")
async def info(ctx: commands.Context):
await ctx.channel.send(
content=(f"Guild ID: `{ctx.guild.id}`\nChannel ID: `{ctx.channel.id}`\n")
)


@config_group.command(name="roles")
@commands.has_role("Moderator")
async def config_roles(ctx: commands.Context):
logger.info("Configurando roles")
tracking_message = await ctx.channel.send(roles_msg.format(icon_1, icon_2, icon_3))

roles = await ctx.guild.fetch_roles()
roles = {role.name: role for role in roles}
logger.info(f"{len(roles)} roles encontrados. roles={','.join(roles.keys())!r}")

await tracking_message.edit(content=(roles_msg.format(icon_check, icon_2, icon_3)))

logger.info("Criando roles")
for role in ROLES:
try:
roles[role.name] = await get_or_create_role(name=role.name, guild=ctx.guild,
permissions=role.permissions, colour=role.colour)
logger.info(f"Role {role.name} created.")
except Exception as e:
logger.info(f"Problem while creating role {role.name}. Skipping it for now.")
logger.exception(f"Exception sent to Sentry. e={e!r}")

await tracking_message.edit(content=(roles_msg.format(icon_check, icon_check, icon_3)))

logger.info("Configurando permissões")
positions = {roles[role.name]: role.position for role in ROLES}
positions[ctx.guild.me.top_role] = 999
await ctx.guild.edit_role_positions(positions)

await tracking_message.edit(content=(roles_msg.format(icon_check, icon_check, icon_check)))


@config_group.command(name="canais")
@commands.has_role("Moderator")
async def config_channels(ctx: commands.Context):

track_message = await ctx.channel.send("""Criando Categorias e Canais""")

for channel in CHANNELS:
channel_message = await ctx.channel.send(
"""Channel {} being created. {}""".format(channel.name, icon_time)
)
await create_channel(channel, ctx)
await channel_message.edit(
content=(
"""Channel {} being created. {}""".format(channel.name, icon_check)
)
)

await track_message.edit(content=("""Criando Categorias e Canais {}""".format(icon_check)))


@bot.command(name="msg", brief="Send a msg to a channel [#channel] [msg]")
@commands.has_role("Moderator")
async def sendmsg(ctx, *args):

if len(args) < 2:
logger.warning("Missing destination channel and message")
return

destination, destination_type = get_destination(ctx, args[0])

if not destination:
logger.warning(
f"Destination not found. args={args!r}"
)
return

message = " ".join(args[1:])

logger.info(f"Message sent. Destination={destination}, message={message}")
await destination.send(message)


@config_group.command(name="reset-canais")
@commands.has_role("Moderator")
async def reset_channels(ctx: commands.Context):
guild = ctx.guild

channels = await guild.fetch_channels()
managed_channels = [channel.name for channel in CHANNELS] + [channel.category for channel in CHANNELS]
managed_channels = list(set(managed_channels))
channels_to_be_deleted = [channel for channel in channels if channel.name in managed_channels]
await asyncio.gather(*[
channel.delete() for channel in channels_to_be_deleted
])
logger.info(f"Channels deleted: {channels_to_be_deleted}")


@config_group.command(name="reset-roles")
@commands.has_role("Moderator")
async def reset_roles(ctx: commands.Context):
guild = ctx.guild

roles = await guild.fetch_roles()
managed_roles = [role.name for role in ROLES]
roles_to_be_deleted = [role for role in roles if role.name in managed_roles]
await asyncio.gather(*[
role.delete() for role in roles_to_be_deleted
])
logger.info(f"Roles deleted: {roles_to_be_deleted}")


@bot.event
async def on_ready():
print('Show is starting!')
print('We have logged in as {0.user}'.format(bot))


if __name__ == '__main__':
bot.run(DISCORD_TOKEN)
48 changes: 0 additions & 48 deletions config.toml

This file was deleted.

24 changes: 24 additions & 0 deletions examples/example-bot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# snake.bot

import discord
from decouple import config
DISCORD_TOKEN = config("DISCORD_TOKEN")
client = discord.Client()


@client.event
async def on_ready():
print('We have logged in as {0.user}'.format(client))


@client.event
async def on_message(message):
if message.author == client.user:
return

if message.content.startswith('$hello'):
await message.channel.send('Hello!')


if __name__ == '__main__':
client.run(DISCORD_TOKEN)
13 changes: 13 additions & 0 deletions examples/example-sentry.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import sentry_sdk
from decouple import config

sentry_sdk.init(
config("SENTRY_TOKEN"),

# Set traces_sample_rate to 1.0 to capture 100%
# of transactions for performance monitoring.
# We recommend adjusting this value in production.
traces_sample_rate=1.0
)

division_by_zero = 1 / 0
16 changes: 16 additions & 0 deletions examples/example-spreadsheet.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import gspread
from oauth2client.service_account import ServiceAccountCredentials

scope = ['https://spreadsheets.google.com/feeds']
creds = ServiceAccountCredentials.from_json_keyfile_name('client_secret.json', scope)
client = gspread.authorize(creds)

wks = client.open_by_key('1R0fYLV32a4TpDL0AxO-pxgjEI0XToRu9tU-lw0wL51A')

all_emails = []
for i in range(3):
worksheet = wks.get_worksheet(i)
emails = worksheet.col_values(4)[1:]
all_emails.extend(emails)

assert "[email protected]" in all_emails
Loading

0 comments on commit 70fc6ef

Please sign in to comment.