Make announcements async, work on bank upgrades

pull/119/head
stijndcl 2022-07-03 17:19:24 +02:00
parent 5b510d1f45
commit ba86d4a6f2
9 changed files with 143 additions and 14 deletions

View File

@ -0,0 +1,28 @@
"""Add missing defaults
Revision ID: 632b69cdadde
Revises: 8c4ad0a1d699
Create Date: 2022-07-03 16:29:07.387011
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '632b69cdadde'
down_revision = '8c4ad0a1d699'
branch_labels = None
depends_on = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###

View File

@ -0,0 +1,32 @@
"""Move dinks over to Bank & add invested amount
Revision ID: 8c4ad0a1d699
Revises: 0d03c226d881
Create Date: 2022-07-03 16:27:11.330746
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '8c4ad0a1d699'
down_revision = '0d03c226d881'
branch_labels = None
depends_on = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('bank', schema=None) as batch_op:
batch_op.add_column(sa.Column('invested', sa.BigInteger(), server_default='0', nullable=False))
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('bank', schema=None) as batch_op:
batch_op.drop_column('invested')
# ### end Alembic commands ###

View File

@ -17,16 +17,17 @@ class Bank(Base):
bank_id: int = Column(Integer, primary_key=True) bank_id: int = Column(Integer, primary_key=True)
user_id: int = Column(BigInteger, ForeignKey("users.user_id")) user_id: int = Column(BigInteger, ForeignKey("users.user_id"))
dinks: int = Column(BigInteger, default=0, nullable=False) dinks: int = Column(BigInteger, server_default="0", nullable=False)
invested: int = Column(BigInteger, server_default="0", nullable=False)
# Interest rate # Interest rate
interest_level: int = Column(Integer, default=1, nullable=False) interest_level: int = Column(Integer, server_default="1", nullable=False)
# Maximum amount that can be stored in the bank # Maximum amount that can be stored in the bank
capacity_level: int = Column(Integer, default=1, nullable=False) capacity_level: int = Column(Integer, server_default="1", nullable=False)
# Maximum amount that can be robbed # Maximum amount that can be robbed
rob_level: int = Column(Integer, default=1, nullable=False) rob_level: int = Column(Integer, server_default="1", nullable=False)
user: User = relationship("User", uselist=False, back_populates="bank", lazy="selectin") user: User = relationship("User", uselist=False, back_populates="bank", lazy="selectin")
@ -67,7 +68,7 @@ class NightlyData(Base):
nightly_id: int = Column(Integer, primary_key=True) nightly_id: int = Column(Integer, primary_key=True)
user_id: int = Column(BigInteger, ForeignKey("users.user_id")) user_id: int = Column(BigInteger, ForeignKey("users.user_id"))
last_nightly: Optional[datetime] = Column(DateTime(timezone=True), nullable=True) last_nightly: Optional[datetime] = Column(DateTime(timezone=True), nullable=True)
count: int = Column(Integer, default=0, nullable=False) count: int = Column(Integer, server_default="0", nullable=False)
user: User = relationship("User", back_populates="nightly_data", uselist=False, lazy="selectin") user: User = relationship("User", back_populates="nightly_data", uselist=False, lazy="selectin")
@ -81,7 +82,7 @@ class UforaCourse(Base):
name: str = Column(Text, nullable=False, unique=True) name: str = Column(Text, nullable=False, unique=True)
code: str = Column(Text, nullable=False, unique=True) code: str = Column(Text, nullable=False, unique=True)
year: int = Column(Integer, nullable=False) year: int = Column(Integer, nullable=False)
log_announcements: bool = Column(Boolean, default=False, nullable=False) log_announcements: bool = Column(Boolean, server_default="0", nullable=False)
announcements: list[UforaAnnouncement] = relationship( announcements: list[UforaAnnouncement] = relationship(
"UforaAnnouncement", back_populates="course", cascade="all, delete-orphan", lazy="selectin" "UforaAnnouncement", back_populates="course", cascade="all, delete-orphan", lazy="selectin"

View File

@ -8,6 +8,7 @@ from database.exceptions.currency import DoubleNightly
from didier import Didier from didier import Didier
from didier.utils.discord.checks import is_owner from didier.utils.discord.checks import is_owner
from didier.utils.discord.converters import abbreviated_number from didier.utils.discord.converters import abbreviated_number
from didier.utils.math.currency import capacity_upgrade_price, interest_upgrade_price, rob_upgrade_price
from didier.utils.types.string import pluralize from didier.utils.types.string import pluralize
@ -34,11 +35,42 @@ class Currency(commands.Cog):
mention_author=False, mention_author=False,
) )
@commands.hybrid_group(name="bank", case_insensitive=True, invoke_without_command=True) @commands.group(name="bank", aliases=["B"], case_insensitive=True, invoke_without_command=True)
async def bank(self, ctx: commands.Context): async def bank(self, ctx: commands.Context):
"""Show your Didier Bank information""" """Show your Didier Bank information"""
async with self.client.db_session as session: async with self.client.db_session as session:
await crud.get_bank(session, ctx.author.id) bank = await crud.get_bank(session, ctx.author.id)
embed = discord.Embed(colour=discord.Colour.blue())
embed.set_author(name=f"Bank van {ctx.author.display_name}")
embed.set_thumbnail(url=ctx.author.avatar.url)
embed.add_field(name="Interest level", value=bank.interest_level)
embed.add_field(name="Capaciteit level", value=bank.capacity_level)
embed.add_field(name="Momenteel geïnvesteerd", value=bank.invested, inline=False)
await ctx.reply(embed=embed, mention_author=False)
@bank.group(name="Upgrade", aliases=["U", "Upgrades"], case_insensitive=True, invoke_without_command=True)
async def bank_upgrades(self, ctx: commands.Context):
"""List the upgrades you can buy & their prices"""
async with self.client.db_session as session:
bank = await crud.get_bank(session, ctx.author.id)
embed = discord.Embed(colour=discord.Colour.blue())
embed.set_author(name="Bank upgrades")
embed.add_field(
name=f"Interest ({bank.interest_level})", value=str(interest_upgrade_price(bank.interest_level))
)
embed.add_field(
name=f"Capaciteit ({bank.capacity_level})", value=str(capacity_upgrade_price(bank.capacity_level))
)
embed.add_field(name=f"Rob ({bank.rob_level})", value=str(rob_upgrade_price(bank.rob_level)))
embed.set_footer(text="Didier Bank Upgrade [Categorie]")
await ctx.reply(embed=embed, mention_author=False)
@commands.hybrid_command(name="dinks") @commands.hybrid_command(name="dinks")
async def dinks(self, ctx: commands.Context): async def dinks(self, ctx: commands.Context):

View File

@ -29,9 +29,9 @@ class Tasks(commands.Cog):
if settings.UFORA_RSS_TOKEN is None or settings.UFORA_ANNOUNCEMENTS_CHANNEL is None: if settings.UFORA_RSS_TOKEN is None or settings.UFORA_ANNOUNCEMENTS_CHANNEL is None:
return return
async with self.client.db_session as session: async with self.client.db_session as db_session:
announcements_channel = self.client.get_channel(settings.UFORA_ANNOUNCEMENTS_CHANNEL) announcements_channel = self.client.get_channel(settings.UFORA_ANNOUNCEMENTS_CHANNEL)
announcements = await fetch_ufora_announcements(session) announcements = await fetch_ufora_announcements(self.client.http_session, db_session)
for announcement in announcements: for announcement in announcements:
await announcements_channel.send(embed=announcement.to_embed()) await announcements_channel.send(embed=announcement.to_embed())

View File

@ -3,9 +3,11 @@ from dataclasses import dataclass, field
from datetime import datetime from datetime import datetime
from typing import Optional from typing import Optional
import async_timeout
import discord import discord
import feedparser import feedparser
import pytz import pytz
from aiohttp import ClientSession
from markdownify import markdownify as md from markdownify import markdownify as md
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
@ -116,7 +118,9 @@ def parse_ids(url: str) -> Optional[tuple[int, int]]:
return int(spl[0]), int(spl[1]) return int(spl[0]), int(spl[1])
async def fetch_ufora_announcements(session: AsyncSession) -> list[UforaNotification]: async def fetch_ufora_announcements(
http_session: ClientSession, database_session: AsyncSession
) -> list[UforaNotification]:
"""Fetch all new announcements""" """Fetch all new announcements"""
notifications: list[UforaNotification] = [] notifications: list[UforaNotification] = []
@ -124,7 +128,7 @@ async def fetch_ufora_announcements(session: AsyncSession) -> list[UforaNotifica
if settings.UFORA_RSS_TOKEN is None: if settings.UFORA_RSS_TOKEN is None:
return notifications return notifications
courses = await crud.get_courses_with_announcements(session) courses = await crud.get_courses_with_announcements(database_session)
for course in courses: for course in courses:
course_announcement_ids = list(map(lambda announcement: announcement.announcement_id, course.announcements)) course_announcement_ids = list(map(lambda announcement: announcement.announcement_id, course.announcements))
@ -134,7 +138,9 @@ async def fetch_ufora_announcements(session: AsyncSession) -> list[UforaNotifica
) )
# Get the updated feed # Get the updated feed
feed = feedparser.parse(course_url) with async_timeout.timeout(10):
async with http_session.get(course_url) as response:
feed = feedparser.parse(await response.text())
# Remove old notifications # Remove old notifications
fresh_feed: list[dict] = [] fresh_feed: list[dict] = []
@ -161,6 +167,6 @@ async def fetch_ufora_announcements(session: AsyncSession) -> list[UforaNotifica
notifications.append(notification) notifications.append(notification)
# Create new db entry # Create new db entry
await crud.create_new_announcement(session, notification_id, course, notification.published_dt) await crud.create_new_announcement(database_session, notification_id, course, notification.published_dt)
return notifications return notifications

View File

@ -1,6 +1,7 @@
import os import os
import discord import discord
from aiohttp import ClientSession
from discord.ext import commands from discord.ext import commands
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
@ -14,6 +15,7 @@ class Didier(commands.Bot):
"""DIDIER <3""" """DIDIER <3"""
initial_extensions: tuple[str, ...] = () initial_extensions: tuple[str, ...] = ()
http_session: ClientSession
def __init__(self): def __init__(self):
activity = discord.Activity(type=discord.ActivityType.playing, name=settings.DISCORD_STATUS_MESSAGE) activity = discord.Activity(type=discord.ActivityType.playing, name=settings.DISCORD_STATUS_MESSAGE)
@ -43,6 +45,9 @@ class Didier(commands.Bot):
await self._load_initial_extensions() await self._load_initial_extensions()
await self._load_directory_extensions("didier/cogs") await self._load_directory_extensions("didier/cogs")
# Create aiohttp session
self.http_session = ClientSession()
async def _load_initial_extensions(self): async def _load_initial_extensions(self):
"""Load all extensions that should be loaded before the others""" """Load all extensions that should be loaded before the others"""
for extension in self.initial_extensions: for extension in self.initial_extensions:

View File

View File

@ -0,0 +1,25 @@
import math
def interest_upgrade_price(level: int) -> int:
"""Calculate the price to upgrade your interest level"""
base_cost = 600
growth_rate = 1.8
return math.floor(base_cost * (growth_rate**level))
def capacity_upgrade_price(level: int) -> int:
"""Calculate the price to upgrade your capacity level"""
base_cost = 800
growth_rate = 1.6
return math.floor(base_cost * (growth_rate**level))
def rob_upgrade_price(level: int) -> int:
"""Calculate the price to upgrade your rob level"""
base_cost = 950
growth_rate = 1.9
return math.floor(base_cost * (growth_rate**level))