Skip to content
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
8 changes: 7 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,16 @@ jobs:
- name: Test with pytest
id: test
env:
CI_EVENT_ID: ${{ github.event.number || github.sha }}
GITHUB_PYTEST: "true"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DISCORD_BOT_TOKEN: ${{ secrets.DISCORD_TEST_BOT_TOKEN }}
DISCORD_WEBHOOK: ${{ secrets.DISCORD_TEST_BOT_WEBHOOK }}
DISCORD_GITHUB_STATUS_CHANNEL_ID: ${{ vars.DISCORD_GITHUB_STATUS_CHANNEL_ID }}
DISCORD_REDDIT_CHANNEL_ID: ${{ vars.DISCORD_REDDIT_CHANNEL_ID }}
DISCORD_SPONSORS_CHANNEL_ID: ${{ vars.DISCORD_SPONSORS_CHANNEL_ID }}
GRAVATAR_EMAIL: ${{ secrets.GRAVATAR_EMAIL }}
IGDB_CLIENT_ID: ${{ secrets.TWITCH_CLIENT_ID }}
IGDB_CLIENT_SECRET: ${{ secrets.TWITCH_CLIENT_SECRET }}
PRAW_CLIENT_ID: ${{ secrets.REDDIT_CLIENT_ID }}
PRAW_CLIENT_SECRET: ${{ secrets.REDDIT_CLIENT_SECRET }}
REDDIT_USERNAME: ${{ secrets.REDDIT_USERNAME }}
Expand Down
29 changes: 22 additions & 7 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,35 +17,50 @@ ENV COMMIT=${COMMIT}
ARG DAILY_TASKS=true
ARG DAILY_RELEASES=true
ARG DAILY_TASKS_UTC_HOUR=12
ARG DISCORD_GITHUB_STATUS_CHANNEL_ID
ARG DISCORD_REDDIT_CHANNEL_ID
ARG DISCORD_SPONSORS_CHANNEL_ID

# Secret config
ARG DISCORD_BOT_TOKEN
ARG DAILY_CHANNEL_ID
ARG DISCORD_BOT_TOKEN
ARG DISCORD_CLIENT_ID
ARG DISCORD_CLIENT_SECRET
ARG DISCORD_REDIRECT_URI
ARG GITHUB_CLIENT_ID
ARG GITHUB_CLIENT_SECRET
ARG GITHUB_REDIRECT_URI
ARG GITHUB_WEBHOOK_SECRET_KEY
ARG GRAVATAR_EMAIL
ARG IGDB_CLIENT_ID
ARG IGDB_CLIENT_SECRET
ARG PRAW_CLIENT_ID
ARG PRAW_CLIENT_SECRET
ARG PRAW_SUBREDDIT
ARG DISCORD_WEBHOOK
ARG GRAVATAR_EMAIL
ARG REDIRECT_URI

# Environment variables
ENV DAILY_TASKS=$DAILY_TASKS
ENV DAILY_RELEASES=$DAILY_RELEASES
ENV DAILY_CHANNEL_ID=$DAILY_CHANNEL_ID
ENV DAILY_TASKS_UTC_HOUR=$DAILY_TASKS_UTC_HOUR
ENV DISCORD_BOT_TOKEN=$DISCORD_BOT_TOKEN
ENV DISCORD_CLIENT_ID=$DISCORD_CLIENT_ID
ENV DISCORD_CLIENT_SECRET=$DISCORD_CLIENT_SECRET
ENV DISCORD_GITHUB_STATUS_CHANNEL_ID=$DISCORD_GITHUB_STATUS_CHANNEL_ID
ENV DISCORD_REDDIT_CHANNEL_ID=$DISCORD_REDDIT_CHANNEL_ID
ENV DISCORD_REDIRECT_URI=$DISCORD_REDIRECT_URI
ENV DISCORD_SPONSORS_CHANNEL_ID=$DISCORD_SPONSORS_CHANNEL_ID
ENV GITHUB_CLIENT_ID=$GITHUB_CLIENT_ID
ENV GITHUB_CLIENT_SECRET=$GITHUB_CLIENT_SECRET
ENV GITHUB_REDIRECT_URI=$GITHUB_REDIRECT_URI
ENV GITHUB_WEBHOOK_SECRET_KEY=$GITHUB_WEBHOOK_SECRET_KEY
ENV GRAVATAR_EMAIL=$GRAVATAR_EMAIL
ENV IGDB_CLIENT_ID=$IGDB_CLIENT_ID
ENV IGDB_CLIENT_SECRET=$IGDB_CLIENT_SECRET
ENV PRAW_CLIENT_ID=$PRAW_CLIENT_ID
ENV PRAW_CLIENT_SECRET=$PRAW_CLIENT_SECRET
ENV PRAW_SUBREDDIT=$PRAW_SUBREDDIT
ENV DISCORD_WEBHOOK=$DISCORD_WEBHOOK
ENV GRAVATAR_EMAIL=$GRAVATAR_EMAIL
ENV REDIRECT_URI=$REDIRECT_URI

SHELL ["/bin/bash", "-o", "pipefail", "-c"]
# install dependencies
Expand All @@ -69,7 +84,7 @@ RUN <<_SETUP
set -e

# replace the version in the code
sed -i "s/version = '0.0.0'/version = '${BUILD_VERSION}'/g" src/common.py
sed -i "s/version = '0.0.0'/version = '${BUILD_VERSION}'/g" src/common/common.py

# install dependencies
python -m pip install --no-cache-dir -r requirements.txt
Expand Down
83 changes: 45 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
[![GitHub Workflow Status (CI)](https://img.shields.io/github/actions/workflow/status/lizardbyte/support-bot/ci.yml.svg?branch=master&label=CI%20build&logo=github&style=for-the-badge)](https://github.com/LizardByte/support-bot/actions/workflows/ci.yml?query=branch%3Amaster)
[![Codecov](https://img.shields.io/codecov/c/gh/LizardByte/support-bot.svg?token=900Q93P1DE&style=for-the-badge&logo=codecov&label=codecov)](https://app.codecov.io/gh/LizardByte/support-bot)

Support bot written in python to help manage LizardByte communities. The current focus is discord and reddit, but other
platforms such as GitHub discussions/issues could be added.
Support bot written in python to help manage LizardByte communities. The current focus is Discord and Reddit, but other
platforms such as GitHub discussions/issues might be added in the future.


## Overview
Expand All @@ -24,45 +24,52 @@ platforms such as GitHub discussions/issues could be added.
* Presence Intent
* Server Members Intent
* Copy the `Token`
* Add the following as environment variables or in a `.env` file (use `sample.env` as an example).
:exclamation: if using Docker these can be arguments.
:warning: Never publicly expose your tokens, secrets, or ids.

| variable | required | default | description |
|-------------------------|----------|------------------------------------------------------|---------------------------------------------------------------|
| DISCORD_BOT_TOKEN | True | `None` | Token from Bot page on discord developer portal. |
| DAILY_TASKS | False | `true` | Daily tasks on or off. |
| DAILY_RELEASES | False | `true` | Send a message for each game released on this day in history. |
| DAILY_CHANNEL_ID | False | `None` | Required if daily_tasks is enabled. |
| DAILY_TASKS_UTC_HOUR | False | `12` | The hour to run daily tasks. |
| GRAVATAR_EMAIL | False | `None` | Gravatar email address for bot avatar. |
| IGDB_CLIENT_ID | False | `None` | Required if daily_releases is enabled. |
| IGDB_CLIENT_SECRET | False | `None` | Required if daily_releases is enabled. |
| SUPPORT_COMMANDS_REPO | False | `https://github.com/LizardByte/support-bot-commands` | Repository for support commands. |
| SUPPORT_COMMANDS_BRANCH | False | `master` | Branch for support commands. |

* Running bot:
* `python -m src`
* Invite bot to server:
* `https://discord.com/api/oauth2/authorize?client_id=<the client id of the bot>&permissions=8&scope=bot%20applications.commands`


### Reddit

* Set up an application at [reddit apps](https://www.reddit.com/prefs/apps/).
* The redirect uri should be https://localhost:8080
* Take note of the `client_id` and `client_secret`
* Enter the following as environment variables

| Parameter | Required | Default | Description |
|--------------------|----------|---------|-------------------------------------------------------------------------|
| PRAW_CLIENT_ID | True | None | `client_id` from reddit app setup page. |
| PRAW_CLIENT_SECRET | True | None | `client_secret` from reddit app setup page. |
| PRAW_SUBREDDIT | True | None | Subreddit to monitor (reddit user should be moderator of the subreddit) |
| DISCORD_WEBHOOK | False | None | URL of webhook to send discord notifications to |
| GRAVATAR_EMAIL | False | None | Gravatar email address to get avatar from |
| REDDIT_USERNAME | True | None | Reddit username |
* | REDDIT_PASSWORD | True | None | Reddit password |

* Running bot:
* `python -m src`

### Environment Variables

* Add the following as environment variables or in a `.env` file (use `sample.env` as an example).
:exclamation: if using Docker these can be arguments.
:warning: Never publicly expose your tokens, secrets, or ids.

| variable | required | default | description |
|----------------------------------|----------|------------------------------------------------------|-------------------------------------------------------------------------|
| DAILY_TASKS | False | `true` | Daily tasks on or off. |
| DAILY_RELEASES | False | `true` | Send a message for each game released on this day in history. |
| DAILY_CHANNEL_ID | False | `None` | Required if daily_tasks is enabled. |
| DAILY_TASKS_UTC_HOUR | False | `12` | The hour to run daily tasks. |
| DISCORD_BOT_TOKEN | True | `None` | Token from Bot page on discord developer portal. |
| DISCORD_CLIENT_ID | True | `None` | Discord OAuth2 client id. |
| DISCORD_CLIENT_SECRET | True | `None` | Discord OAuth2 client secret. |
| DISCORD_GITHUB_STATUS_CHANNEL_ID | True | `None` | Channel ID to send GitHub status updates to. |
| DISCORD_REDDIT_CHANNEL_ID | True | `None` | Channel ID to send Reddit post updates to. |
| DISCORD_REDIRECT_URI | False | `https://localhost:8080/discord/callback` | The redirect uri for OAuth2. Must be publicly accessible. |
| DISCORD_SPONSORS_CHANNEL_ID | True | `None` | Channel ID to send sponsorship updates to. |
| GITHUB_CLIENT_ID | True | `None` | GitHub OAuth2 client id. |
| GITHUB_CLIENT_SECRET | True | `None` | GitHub OAuth2 client secret. |
| GITHUB_REDIRECT_URI | False | `https://localhost:8080/github/callback` | The redirect uri for OAuth2. Must be publicly accessible. |
| GITHUB_WEBHOOK_SECRET_KEY | True | `None` | A secret value to ensure webhooks are from trusted sources. |
| GRAVATAR_EMAIL | False | `None` | Gravatar email address for bot avatar. |
| IGDB_CLIENT_ID | False | `None` | Required if daily_releases is enabled. |
| IGDB_CLIENT_SECRET | False | `None` | Required if daily_releases is enabled. |
| PRAW_CLIENT_ID | True | None | `client_id` from reddit app setup page. |
| PRAW_CLIENT_SECRET | True | None | `client_secret` from reddit app setup page. |
| PRAW_SUBREDDIT | True | None | Subreddit to monitor (reddit user should be moderator of the subreddit) |
| REDDIT_USERNAME | True | None | Reddit username |
| REDDIT_PASSWORD | True | None | Reddit password |
| SUPPORT_COMMANDS_REPO | False | `https://github.com/LizardByte/support-bot-commands` | Repository for support commands. |
| SUPPORT_COMMANDS_BRANCH | False | `master` | Branch for support commands. |

### Start

```bash
python -m src
```

* Invite bot to server:
* `https://discord.com/api/oauth2/authorize?client_id=<the client id of the bot>&permissions=8&scope=bot%20applications.commands`
Binary file added assets/favicon.ico
Binary file not shown.
1 change: 1 addition & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ betamax-serializers==0.2.1
pytest==8.3.4
pytest-asyncio==0.24.0
pytest-cov==6.0.0
pytest-mock==3.14.0
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
cryptography==43.0.3
Flask==3.1.0
GitPython==3.1.43
igdb-api-v4==0.3.3
Expand All @@ -7,3 +8,4 @@ praw==7.8.1
py-cord==2.6.1
python-dotenv==1.0.1
requests==2.32.3
requests-oauthlib==2.0.0
17 changes: 13 additions & 4 deletions sample.env
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,27 @@ DAILY_TASKS=true
DAILY_RELEASES=true
DAILY_CHANNEL_ID=
DAILY_TASKS_UTC_HOUR=12
SUPPORT_COMMANDS_BRANCH=master

# Secret settings
DISCORD_BOT_TOKEN=
GRAVATAR_EMAIL=

# discord/github oauth2
DISCORD_CLIENT_ID=
DISCORD_CLIENT_SECRET=
DISCORD_REDIRECT_URI=
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=
GITHUB_REDIRECT_URI=

# igdb
IGDB_CLIENT_ID=
IGDB_CLIENT_SECRET=
READTHEDOCS_TOKEN=

# reddit bot
PRAW_CLIENT_ID=
PRAW_CLIENT_SECRET=
PRAW_SUBREDDIT=AskReddit
DISCORD_WEBHOOK=
GRAVATAR_EMAIL=
REDIRECT_URI=
REDDIT_USERNAME=
REDDIT_PASSWORD=
33 changes: 13 additions & 20 deletions src/__main__.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,33 @@
# standard imports
import os
import time

# development imports
from dotenv import load_dotenv
load_dotenv(override=False) # environment secrets take priority over .env file

# local imports
if True: # hack for flake8
from src.discord import bot as d_bot
from src import keep_alive
from src.reddit import bot as r_bot
# local imports, import after env loaded
from src.common import globals # noqa: E402
from src.discord import bot as d_bot # noqa: E402
from src.common import webapp # noqa: E402
from src.reddit import bot as r_bot # noqa: E402


def main():
# to run in replit
try:
os.environ['REPL_SLUG']
except KeyError:
pass # not running in replit
else:
keep_alive.keep_alive() # Start the web server
webapp.start() # Start the web server

discord_bot = d_bot.Bot()
discord_bot.start_threaded() # Start the discord bot
globals.DISCORD_BOT = d_bot.Bot()
globals.DISCORD_BOT.start_threaded() # Start the discord bot

reddit_bot = r_bot.Bot()
reddit_bot.start_threaded() # Start the reddit bot
globals.REDDIT_BOT = r_bot.Bot()
globals.REDDIT_BOT.start_threaded() # Start the reddit bot

try:
while discord_bot.bot_thread.is_alive() or reddit_bot.bot_thread.is_alive():
while globals.DISCORD_BOT.bot_thread.is_alive() or globals.REDDIT_BOT.bot_thread.is_alive():
time.sleep(0.5)
except KeyboardInterrupt:
print("Keyboard Interrupt Detected")
discord_bot.stop()
reddit_bot.stop()
globals.DISCORD_BOT.stop()
globals.REDDIT_BOT.stop()


if __name__ == '__main__': # pragma: no cover
Expand Down
Empty file added src/common/__init__.py
Empty file.
21 changes: 17 additions & 4 deletions src/common.py → src/common/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@
import requests


colors = {
'black': 0x000000,
'green': 0x00ff00,
'orange': 0xffa500,
'purple': 0x9147ff,
'red': 0xff0000,
'white': 0xffffff,
'yellow': 0xffff00,
}


def get_bot_avatar(gravatar: str) -> str:
"""
Get Gravatar image url.
Expand Down Expand Up @@ -36,21 +47,23 @@ def get_avatar_bytes():
return avatar_img


def get_data_dir():
def get_app_dirs():
# parent directory name of this file, not full path
parent_dir = os.path.dirname(os.path.abspath(__file__)).split(os.sep)[-2]
parent_dir = os.path.dirname(os.path.abspath(__file__)).split(os.sep)[-3]
if parent_dir == 'app': # running in Docker container
a = '/app'
d = '/data'
else: # running locally
a = os.getcwd()
d = os.path.join(os.getcwd(), 'data')
os.makedirs(d, exist_ok=True)
return d
return a, d


# constants
avatar = get_bot_avatar(gravatar=os.environ['GRAVATAR_EMAIL'])
org_name = 'LizardByte'
bot_name = f'{org_name}-Bot'
bot_url = 'https://app.lizardbyte.dev'
data_dir = get_data_dir()
app_dir, data_dir = get_app_dirs()
version = '0.0.0'
Loading