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

Add reaction check handler #29

Merged
merged 18 commits into from
Mar 13, 2023
Merged
Show file tree
Hide file tree
Changes from 12 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
4 changes: 2 additions & 2 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Description

Please include a summary of the changes and the related issue.
Please include a summary of the changes and the related issue.

# Type of change

Expand All @@ -11,7 +11,7 @@ Please include a summary of the changes and the related issue.

# How Has This Been Tested?

Please describe the tests that you ran to verify your changes.
Please describe the tests that you ran to verify your changes.

# Checklist:

Expand Down
66 changes: 54 additions & 12 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,37 +1,79 @@
default_language_version:
# force all unspecified python hooks to run python3
python: python3

repos:
- repo: https://github.com/asottile/pyupgrade
rev: v3.3.1
hooks:
- id: pyupgrade
args: [--py310-plus]

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.0.1
rev: v4.4.0
hooks:
# simply checks whether the files parse as valid python
- id: check-ast
# checks toml files for parseable syntax
- id: check-toml
# checks yaml files for parseable syntax
- id: check-yaml
# checks a common error of defining a docstring after code
- id: check-docstring-first
# ensures that (non-binary) executables have a shebang
- id: check-executables-have-shebangs
# ensures that (non-binary) files with a shebang are executable
- id: check-shebang-scripts-are-executable
# checks for files that contain merge conflict strings
- id: check-merge-conflict
# ensures that links to vcs websites are permalinks (i.e. commit hash instead of master)
- id: check-vcs-permalinks
# trims trailing whitespace
- id: trailing-whitespace
# ensures that a file is either empty, or ends with one newline
- id: end-of-file-fixer
# replaces or checks mixed line ending
- id: mixed-line-ending

- repo: https://github.com/psf/black
rev: 22.6.0
- repo: https://github.com/asottile/reorder_python_imports
rev: v3.9.0
hooks:
- id: black
- id: reorder-python-imports
args: [--py310-plus]

- repo: https://github.com/PyCQA/isort
rev: 5.10.1
- repo: https://github.com/asottile/add-trailing-comma
rev: v2.4.0
hooks:
- id: isort
args: ["--profile", "black"]
- id: add-trailing-comma
args: [--py36-plus]

- repo: https://github.com/psf/black
rev: 23.1.0
hooks:
- id: black

- repo: https://github.com/PyCQA/flake8
rev: 5.0.3
rev: 6.0.0
hooks:
- id: flake8
additional_dependencies: [mccabe]
args: ["--max-line-length", "88", "--max-complexity", "10"]

- repo: https://github.com/PyCQA/pylint/
rev: v2.14.5
rev: v2.16.1
hooks:
- id: pylint
exclude: tests/ # Prevent files in tests/ to be passed in to pylint

- repo: https://github.com/AleksaC/hadolint-py
rev: v1.19.0
rev: v2.12.0.2
hooks:
- id: hadolint

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.0.0
hooks:
- id: mypy
exclude: ^tests/
additional_dependencies:
- APScheduler==3.9.1
- discord.py==2.0.1
10 changes: 5 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@
FROM python:3.10-slim
LABEL AUTHOR="Proyecto Nutria <contact@proyectonutria.com>"

ENV POETRY_VERSION=1.1.14
ENV POETRY_VERSION=1.2
# -m makes sure that you're using the pip tied to the active Python executable
RUN python3.10 -m pip install poetry==$POETRY_VERSION
RUN python3.10 -m pip install --no-cache-dir poetry==$POETRY_VERSION

WORKDIR /root

# copy requirement files to ensure they will be cached
COPY poetry.lock pyproject.toml ./
# $HOME may changed by runtimes, virtual env solves reproducibility issues
RUN poetry config virtualenvs.in-project true --local
RUN poetry install --no-dev
# $HOME may changed by runtimes, virtual env solves reproducibility issues
RUN poetry config virtualenvs.in-project true --local \
&& poetry install --no-dev

COPY . .
CMD [ "poetry", "run", "python", "-m", "otter_welcome_buddy" ]
24 changes: 18 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<div align="center">
<img src="images/nutria_logo.png">
<h2 align="center">Otter ... Welcome Buddy</h2>
<p align="center">
<p align="center">
Bot to help the management of Proyecto Nutria's discord
<br />
<a href="https://github.com/Proyecto-Nutria/otter-welcome-buddy/issues">Report Bug</a>
Expand Down Expand Up @@ -56,7 +56,7 @@ You need to install all the prerequisites before following with the instalation
1. [Docker](https://docs.docker.com/get-docker/)

### Installation
1. Install our precommits configuration
1. Install our precommits configuration
```sh
pre-commit install
```
Expand All @@ -72,18 +72,30 @@ You need to install all the prerequisites before following with the instalation
<p align="right">(<a href="#readme-top">back to top</a>)</p>


<!-- CONFIGURATION INSTRUCTIONS -->
## Configuration

You need the following environmental variables either in a `.env` file under the root directory of this repository or directly added at your system (or your Docker instance):

* `DISCORD_TOKEN`: the Discord Bot Token retrieved from the [developer page](https://discord.com/developers/applications).
* `WELCOME_MESSAGES`: [`message ids`](https://discordpy.readthedocs.io/en/stable/api.html?highlight=message%20id#discord.Message.id) separated by `,` that give `OTTER_ROLE` when reacted to.
* `OTTER_ADMIN`: Discord role that give access to admin role based commands.
* `OTTER_MODERATOR`: Discord role that give access to moderator role based commands.
* `OTTER_ROLE`: Discord role to give when reacted to `WELCOME_MESSAGES`.


<!-- USAGE EXAMPLES -->
## Usage

1. Activate your virtual environment
```sh
poetry shell
```
1. Run the bot using:
1. Run the bot using:
```sh
poetry run python otter_welcome_buddy
```
1. If you would like to run the build locally:
1. If you would like to run the build locally:
```sh
tox
```
Expand All @@ -93,7 +105,7 @@ You need to install all the prerequisites before following with the instalation

- [ ] Link the repository to our project dashboard
- [ ] Add deepsource
- [ ] Add vale
- [ ] Add vale
- [ ] Enable logging

<p align="right">(<a href="#readme-top">back to top</a>)</p>
Expand All @@ -116,7 +128,7 @@ Don't forget to give the project a star! Thanks again!


<!-- ACKNOWLEDGMENTS -->
## Acknowledgments
## Acknowledgments

This README was possible thanks to [Best-README](https://github.com/othneildrew/Best-README-Template)

Expand Down
10 changes: 8 additions & 2 deletions otter_welcome_buddy/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,22 @@
import os

from discord.ext.commands import Bot
from discord.ext.commands import when_mentioned_or
from dotenv import load_dotenv

from otter_welcome_buddy.common.constants import COMMAND_PREFIX
from otter_welcome_buddy.startup import cogs, intents
from otter_welcome_buddy.startup import cogs
from otter_welcome_buddy.startup import intents

load_dotenv()


async def main() -> None:
"""Principal function to be called by Docker"""

bot: Bot = Bot(
command_prefix=COMMAND_PREFIX, intents=intents.get_registered_intents()
command_prefix=when_mentioned_or(COMMAND_PREFIX),
intents=intents.get_registered_intents(),
)

async with bot:
Expand Down
60 changes: 39 additions & 21 deletions otter_welcome_buddy/cogs/hiring_timelines.py
Original file line number Diff line number Diff line change
@@ -1,59 +1,77 @@
import os

from apscheduler.schedulers.asyncio import AsyncIOScheduler
from discord import TextChannel
from discord.ext import commands
from discord.ext.commands import Bot
from discord.ext.commands import Context

from otter_welcome_buddy.common.constants import CronExpressions
from otter_welcome_buddy.common.utils.dates import DateUtils
from otter_welcome_buddy.common.utils.types.common import DiscordChannelType
from otter_welcome_buddy.formatters import timeline
from otter_welcome_buddy.log import wrapper


class Timelines(commands.Cog):
"""Hiring events for every month"""

def __init__(self, bot, messages_formatter):
self.bot = bot
self.messages_formatter = messages_formatter
def __init__(self, bot: Bot, messages_formatter: type[timeline.Formatter]):
self.bot: Bot = bot
self.messages_formatter: type[timeline.Formatter] = messages_formatter
self.scheduler: AsyncIOScheduler = AsyncIOScheduler()

self.__configure_scheduler()

# Commented the !start !stop since I always forget to turn on the trigger
# @commands.command()
# async def start(self, _):
# """Command to interact with the bot and start cron"""
# self.__configure_scheduler()
@commands.group(
brief="Commands related to Timelines messages!",
invoke_without_command=True,
pass_context=True,
)
async def timelines(self, ctx: Context) -> None:
"""
Timelines will help to keep track of important events to be announced via cronjobs
"""
await ctx.send_help(ctx.command)

@timelines.command(brief="Start the cronjob for the timeline messages") # type: ignore
async def start(self, _: Context) -> None:
"""Command to interact with the bot and start cron"""
self.__configure_scheduler()

# @commands.command()
# async def stop(self, _):
# """Command to interact with the bot and start cron"""
# self.scheduler.stop()
@timelines.command(brief="Stop the cronjob for the timeline messages") # type: ignore
async def stop(self, _: Context) -> None:
"""Command to interact with the bot and stop cron"""
self.scheduler.stop()

@wrapper.log_function()
akotadi marked this conversation as resolved.
Show resolved Hide resolved
def __configure_scheduler(self):
def __configure_scheduler(self) -> None:
"""Configure and start scheduler"""
self.scheduler.add_job(
self.send_message_on_channel,
DateUtils.create_cron_trigger_from(
CronExpressions.DAY_ONE_OF_EACH_MONTH_CRON.value
CronExpressions.DAY_ONE_OF_EACH_MONTH_CRON.value,
),
)
self.scheduler.start()

def _get_hiring_events(self):
def _get_hiring_events(self) -> str:
"""Get hiring events for current month"""
return self.messages_formatter.get_hiring_events_for(
DateUtils.get_current_month()
DateUtils.get_current_month(),
)

@wrapper.log_function()
akotadi marked this conversation as resolved.
Show resolved Hide resolved
async def send_message_on_channel(self):
async def send_message_on_channel(self) -> None:
"""Sends message to announcement channel at the start of month"""
channel_id = int(os.environ["ANNOUNCEMENT_CHANNEL_ID"])
channel = self.bot.get_channel(channel_id)
await channel.send(self._get_hiring_events())
channel_id: int = int(os.environ["ANNOUNCEMENT_CHANNEL_ID"])
channel: DiscordChannelType | None = self.bot.get_channel(channel_id)
if isinstance(channel, TextChannel):
await channel.send(self._get_hiring_events())
else:
raise TypeError("Not valid channel to send the message in")


async def setup(bot):
async def setup(bot: Bot) -> None:
"""Required setup method"""
await bot.add_cog(Timelines(bot, timeline.Formatter))
Loading