Skip to content

Commit

Permalink
Merge pull request #161 from DMcP89/release/v0.4.1-Beta
Browse files Browse the repository at this point in the history
Release/v0.4.1 beta
  • Loading branch information
DMcP89 authored Sep 1, 2024
2 parents 5b074ee + bc75931 commit c23cbee
Show file tree
Hide file tree
Showing 14 changed files with 661 additions and 566 deletions.
18 changes: 15 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
![harambot-banner](./assests/harambot_banner.png)
![harambot-banner](https://raw.githubusercontent.com/DMcP89/harambot/main/assests/harambot_banner.png)
# Harambot
_An interactive Yahoo Fantasy sports bot for Discord._

Expand Down Expand Up @@ -41,6 +41,18 @@ In order to properly configure your bot you will need the following:

_Visit our [wiki](https://github.com/DMcP89/harambot/wiki) for a step by step guide on how to obtain these values._

#### Generate a key for your local database

Parts of the database are encrypted, which means we need to generate a key. Using the python interactive interpreter, you can generate one by running these three lines inside the interpreter:

```
from cryptography.fernet import Fernet
fernet_key = Fernet.generate_key()
print(fernet_key.decode())
```

Your key will appear below.

### Run the bot on [Render](https://render.com/)

[![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](https://render.com/deploy?repo=https://github.com/DMcP89/harambot)
Expand All @@ -57,7 +69,7 @@ _Visit our [wiki](https://github.com/DMcP89/harambot/wiki) for a step by step gu
export DISCORD_TOKEN='[YOUR DISCORD TOKEN]'
export YAHOO_KEY='[YOUR YAHOO API CLIENT ID]'
export YAHOO_SECRET='[YOUR YAHOO API CLIENT SECRET]'
export DATABASE_URL='[YOUR DATABASE URL]'
export DATABASE_URL='[YOUR DATABASE URL]' # which can be a pathway to a file, such as 'sqllite:///harambot.db'
export HARAMBOT_KEY='[YOUR ENCRYPTION KEY]' # A URL-safe base64-encoded 32-byte key
```

Expand Down Expand Up @@ -122,7 +134,7 @@ The permission value should be 277562378304

![discord-config-commnd](https://raw.githubusercontent.com/DMcP89/harambot/main/assests/harambot_configure_1.png)

* Use the Login with Yahoo button to authenticate with Yahoo and get your Yahoo token
* Use the Login with Yahoo button to authenticate with Yahoo and get your Yahoo token (this is a one time token)


![discord-config-yahoo](https://raw.githubusercontent.com/DMcP89/harambot/main/assests/harambot_configure_4.png)
Expand Down
5 changes: 4 additions & 1 deletion harambot/cogs/webserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ async def handler(request):
app["bot"] = self.bot
runner = web.AppRunner(app)
await runner.setup()
site = web.TCPSite(runner, "0.0.0.0", settings.port)
if "PORT" in settings:
site = web.TCPSite(runner, "0.0.0.0", settings.port)
else:
site = web.TCPSite(runner, "0.0.0.0", 10000)
await self.bot.wait_until_ready()
await site.start()
logger.info("Webserver started on port {}".format(settings.port))
88 changes: 23 additions & 65 deletions harambot/cogs/yahoo.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,17 @@
import discord
import logging
import urllib3
import functools
import yahoo_oauth


from discord.ext import commands
from discord import app_commands
from yahoo_oauth import OAuth2
from playhouse.shortcuts import model_to_dict
from typing import List, Optional
from datetime import datetime, timedelta

from harambot.yahoo_api import Yahoo
from harambot.database.models import Guild
from harambot.config import settings
from harambot import utils

logging.setLoggerClass(logging.Logger)
yahoo_oauth.logger = logging.getLogger("yahoo_oauth")
logging.getLogger("yahoo_oauth").setLevel(settings.LOGLEVEL)
logging.getLogger("yahoo_oauth").setLevel("INFO")

logger = logging.getLogger("discord.harambot.cogs.yahoo")

Expand All @@ -31,59 +24,22 @@ class YahooCog(commands.Cog):

def __init__(self, bot, KEY, SECRET):
self.bot = bot
self.http = urllib3.PoolManager()
self.KEY = KEY
self.SECRET = SECRET
self.yahoo_api = None

def set_yahoo(f):
@functools.wraps(f)
async def wrapper(
self, interaction: discord.Interaction, *args, **kwargs
):
guild = Guild.get_or_none(
Guild.guild_id == str(interaction.guild_id)
)
if guild is None:
logger.error(
"Guild with id %i does not exist in the database",
interaction.guild_id,
)
return await interaction.response.send_message(
"I'm not set up for this server yet please run /config"
)
if (
not self.yahoo_api
or self.yahoo_api.league_id != guild.league_id
):
self.yahoo_api = Yahoo(
OAuth2(
self.KEY,
self.SECRET,
store_file=False,
**model_to_dict(guild),
),
guild.league_id,
guild.league_type,
)

return await f(self, interaction, *args, **kwargs)

return wrapper
self.yahoo_api = Yahoo()

@app_commands.command(
name="standings",
description="Returns the current standings of your league",
)
@set_yahoo
async def standings(self, interaction: discord.Interaction):
logger.info("Command:Standings called in %i", interaction.guild_id)
embed = discord.Embed(
title="Standings",
description="Team Name\n W-L-T",
color=0xEEE657,
)
standings = self.yahoo_api.get_standings()
standings = self.yahoo_api.get_standings(guild_id=interaction.guild_id)
if standings:
for team in standings:
embed.add_field(
Expand All @@ -95,14 +51,12 @@ async def standings(self, interaction: discord.Interaction):
else:
await interaction.response.send_message(self.error_message)

@set_yahoo
async def roster_autocomplete(
self,
interaction: discord.Interaction,
current: str,
) -> List[app_commands.Choice[str]]:

teams = self.yahoo_api.get_teams()
teams = self.yahoo_api.get_teams(guild_id=interaction.guild_id)
if teams:
options = list(
map(
Expand All @@ -119,7 +73,6 @@ async def roster_autocomplete(
name="roster", description="Returns the roster of the given team"
)
@app_commands.autocomplete(team_name=roster_autocomplete)
@set_yahoo
async def roster(self, interaction: discord.Interaction, team_name: str):
logger.info(
"Command:Roster called in %i with team_name:%s",
Expand All @@ -131,7 +84,9 @@ async def roster(self, interaction: discord.Interaction, team_name: str):
description="",
color=0xEEE657,
)
roster = self.yahoo_api.get_roster(team_name)
roster = self.yahoo_api.get_roster(
guild_id=interaction.guild_id, team_name=team_name
)
if roster:
for player in roster:
embed.add_field(
Expand All @@ -147,10 +102,11 @@ async def roster(self, interaction: discord.Interaction, team_name: str):
name="trade",
description="Create poll for latest trade for league approval",
)
@set_yahoo
async def trade(self, interaction: discord.Interaction):
logger.info("Command:Trade called in %i", interaction.guild_id)
latest_trade = self.yahoo_api.get_latest_trade()
latest_trade = self.yahoo_api.get_latest_trade(
guild_id=interaction.guild_id
)
if latest_trade is None:
await interaction.response.send_message(
"No trades up for approval at this time"
Expand Down Expand Up @@ -233,13 +189,14 @@ async def trade(self, interaction: discord.Interaction):
await response_message.add_reaction(yes_emoji)
await response_message.add_reaction(no_emoji)

@set_yahoo
async def stats_autocomplete(
self,
interaction: discord.Interaction,
current: str,
) -> List[app_commands.Choice[str]]:
players = self.yahoo_api.get_players(current)
players = self.yahoo_api.get_players(
current, guild_id=interaction.guild_id
)
if players:
options = list(
map(
Expand All @@ -258,14 +215,15 @@ async def stats_autocomplete(
name="stats", description="Returns the details of the given player"
)
@app_commands.autocomplete(player_name=stats_autocomplete)
@set_yahoo
async def stats(self, interaction: discord.Interaction, player_name: str):
logger.info(
"Command:Stats called in %i with player_name:%s",
interaction.guild_id,
player_name,
)
player = self.yahoo_api.get_player_details(player_name)
player = self.yahoo_api.get_player_details(
player_name, guild_id=interaction.guild_id
)
if player:
embed = self.get_player_embed(player)
await interaction.response.send_message(embed=embed)
Expand Down Expand Up @@ -330,7 +288,6 @@ def get_player_text(self, player):
@app_commands.command(
name="matchups", description="Returns the current weeks matchups"
)
@set_yahoo
async def matchups(
self, interaction: discord.Interaction, week: Optional[int] = None
):
Expand All @@ -340,7 +297,9 @@ async def matchups(
)
)

week, details = self.yahoo_api.get_matchups(week)
week, details = self.yahoo_api.get_matchups(
guild_id=interaction.guild_id, week=week
)
if details:
embed = discord.Embed(
title="Matchups for Week {}".format(week),
Expand All @@ -359,26 +318,25 @@ async def matchups(
name="waivers",
description="Returns the waiver transactions from the last 24 hours",
)
@set_yahoo
async def waivers(self, interaction: discord.Interaction, days: int = 1):
logger.info("Command:Waivers called in %i", interaction.guild_id)

await interaction.response.defer()
embed_functions_dict = {
"add/drop": utils.create_add_drop_embed,
"add": utils.create_add_embed,
"drop": utils.create_drop_embed,
}
ts = datetime.now() - timedelta(days=days)
transactions = self.yahoo_api.get_transactions(
timestamp=ts.timestamp()
guild_id=interaction.guild_id, timestamp=ts.timestamp()
)
if transactions:
await interaction.response.defer()
for transaction in transactions:
await interaction.followup.send(
embed=embed_functions_dict[transaction["type"]](
transaction
)
)
else:
await interaction.response.send_message("No transactions found")
await interaction.followup.send("No transactions found")
18 changes: 15 additions & 3 deletions harambot/database/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,26 @@
from harambot.database.fields import EncryptedField

logger = logging.getLogger("peewee")
logger.setLevel(settings.LOGLEVEL)
if "LOGLEVEL" in settings:
logger.setLevel(settings.LOGLEVEL)
else:
logger.setLevel("DEBUG")

if "DATABASE_URL" in settings:
database = connect(settings.database_url)
else:
logger.info("Using in-memory database")
database = SqliteDatabase(":memory:")

KEY = ""
if "HARAMBOT_KEY" in settings:
KEY = settings.HARAMBOT_KEY
else:
from cryptography.fernet import Fernet

fernet_key = Fernet.generate_key()
KEY = fernet_key.decode()


class BaseModel(Model):
class Meta:
Expand All @@ -24,8 +36,8 @@ class Meta:

class Guild(BaseModel):
guild_id = TextField(unique=True)
access_token = EncryptedField(key=settings.HARAMBOT_KEY)
refresh_token = EncryptedField(key=settings.HARAMBOT_KEY)
access_token = EncryptedField(key=KEY)
refresh_token = EncryptedField(key=KEY)
expires_in = IntegerField()
token_type = TextField()
xoauth_yahoo_guid = TextField(null=True)
Expand Down
Loading

0 comments on commit c23cbee

Please sign in to comment.