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 external database (MongoDB) #49

Merged
merged 1 commit into from
Nov 8, 2023
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
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,38 @@ You need the following environmental variables either in a `.env` file under the

* `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.
* `MONGO_URI`: address of the [MongoDB](https://docs.mongodb.com/manual/reference/connection-string/) instance to be used, could be local or [Cluster from Atlas](https://www.mongodb.com/cloud/atlas).


<!-- DOCKER INSTRUCTIONS -->
### Dockerize

If you want to use [`Docker`](https://www.docker.com/), you need to take care of few extra steps.

#### Dependencies

Be sure to have this two technologies installed:

* [Docker Engine](https://docs.docker.com/engine/install/)
* [Docker Compose](https://docs.docker.com/compose/install/)

#### Environment Variables

Add these variables in the "environment" (`.env`) file (additional to the ones required on the [Configuration section](#configuration)).

- **MONGO_ROOT_USERNAME**: username to be created as root user with given credentials to manage MongoDB.
- **MONGO_ROOT_PASSWORD**: strong password to be used as credentials for `MONGO_ROOT_USERNAME`.
- **MONGO_USERNAME**: user that manage the connections of the application into the database.
- **MONGO_PASSWORD**: credentials configured to the user of the application.

> :warning: You can omit **MONGO_URI** because will be configured during the creation.

#### Run

```sh
# Build and run the bot
docker-compose up -d
```


<!-- USAGE EXAMPLES -->
Expand Down
41 changes: 41 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
version: '3'
services:
otterbuddy:
build:
context: .
dockerfile: Dockerfile
container_name: otterbuddy
restart: unless-stopped
environment:
BOT_TOKEN: "${BOT_TOKEN}"
LOGGING_CHANNEL: "${LOGGING_CHANNEL}"
WELCOME_MESSAGES: "${WELCOME_MESSAGES}"
MONGO_URI: "mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@mongodb:27017/OtterBuddy"
MAIL_USER: "${MAIL_USER}"
MAIL_PASS: "${MAIL_PASS}"
OTTER_ADMIN: "${OTTER_ADMIN}"
OTTER_MODERATOR: "${OTTER_MODERATOR}"
OTTER_ROLE: "${OTTER_ROLE}"
volumes:
- ./:/otter-buddy
depends_on:
- mongodb
links:
- mongodb

mongodb:
image: mongo:4.4
container_name: mongodb
restart: unless-stopped
command: mongod --auth
environment:
MONGO_INITDB_ROOT_USERNAME: "${MONGO_ROOT_USERNAME}"
MONGO_INITDB_ROOT_PASSWORD: "${MONGO_ROOT_PASSWORD}"
MONGO_INITDB_DATABASE: "OtterBuddy"
MONGO_INITDB_USER: "${MONGO_USERNAME}"
MONGO_INITDB_PWD: "${MONGO_PASSWORD}"
MONGODB_DATA_DIR: /data/db
MONDODB_LOG_DIR: /logs/db
volumes:
- ./mongodb/data:/data/db
- ./mongodb/entrypoint:/docker-entrypoint-initdb.d/
14 changes: 14 additions & 0 deletions mongodb/entrypoint/mongo-init.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
set -e

mongo <<EOF
use $MONGO_INITDB_DATABASE

db.createUser({
user: '$MONGO_INITDB_USER',
pwd: '$MONGO_INITDB_PWD',
roles: [{
role: 'readWrite',
db: '$MONGO_INITDB_DATABASE'
}]
})
EOF
2 changes: 1 addition & 1 deletion otter_welcome_buddy/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ async def main() -> None:
)

async with bot:
await database.init_database(bot)
await database.init_database()
await cogs.register_cogs(bot)
await bot.start(os.environ["DISCORD_TOKEN"])

Expand Down
64 changes: 64 additions & 0 deletions otter_welcome_buddy/log/dblogger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import logging

from pymongo import monitoring


logger = logging.getLogger(__name__)


class DbCommandLogger(monitoring.CommandListener):
"""
Custom MongoDB command logger that logs information about the execution of commands.

Attributes:
None

Methods:
started(event): Logs when a MongoDB command is started.
succeeded(event): Logs when a MongoDB command succeeds.
failed(event): Logs when a MongoDB command fails.
"""

def started(self, event: monitoring.CommandStartedEvent) -> None:
"""
This method is called when a MongoDB command is started.

Args:
event: The object containing information about the started command.
"""
logger.info(
"Command %s with request id %s started on server %s",
event.command_name,
event.request_id,
event.connection_id,
)

def succeeded(self, event: monitoring.CommandStartedEvent) -> None:
"""
This method is called when a MongoDB command succeeds.

Args:
event: The object containing information about the successful command.
"""
logger.info(
"Command %s with request id %s on server %s succeeded in %s microseconds",
event.command_name,
event.request_id,
event.connection_id,
event.duration_micros,
)

def failed(self, event: monitoring.CommandStartedEvent) -> None:
"""
This method is called when a MongoDB command fails.

Args:
event: The object containing information about the failed command.
"""
logger.info(
"Command %s with request id %s on server %s failed in %s microseconds",
event.command_name,
event.request_id,
event.connection_id,
event.duration_micros,
)
14 changes: 12 additions & 2 deletions otter_welcome_buddy/startup/database.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
from discord.ext.commands import Bot
import os

from dotenv import load_dotenv
from mongoengine import connect as mongo_connect
from pymongo import monitoring

from otter_welcome_buddy.common.constants import DATA_FILE_PATH
from otter_welcome_buddy.common.utils.database import get_cache_engine
from otter_welcome_buddy.database.dbconn import BaseModel
from otter_welcome_buddy.log.dblogger import DbCommandLogger


async def init_database(_bot: Bot) -> None:
async def init_database() -> None:
"""Initialize the database from the existing models"""
load_dotenv()

# Initialize local database used as cache - Sqlite3
engine = get_cache_engine(db_path=DATA_FILE_PATH)
BaseModel.metadata.create_all(engine)

# Connect to global database - MongoDB
monitoring.register(DbCommandLogger())
mongo_connect(host=os.environ["MONGO_URI"])
Loading
Loading