Compare commits

...

2 Commits

Author SHA1 Message Date
stijndcl fff35c6c44 Bank upgrades 2022-07-03 17:44:16 +02:00
stijndcl ba86d4a6f2 Make announcements async, work on bank upgrades 2022-07-03 17:19:24 +02:00
14 changed files with 241 additions and 16 deletions

3
.gitignore vendored
View File

@ -154,3 +154,6 @@ cython_debug/
# PyCharm
.idea/
# Debugging files
debug.py

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

@ -5,6 +5,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
from database.crud import users
from database.exceptions import currency as exceptions
from database.models import Bank
from database.utils.math.currency import rob_upgrade_price, interest_upgrade_price, capacity_upgrade_price
NIGHTLY_AMOUNT = 420
@ -41,3 +42,57 @@ async def claim_nightly(session: AsyncSession, user_id: int):
session.add(bank)
session.add(nightly_data)
await session.commit()
async def upgrade_capacity(database_session: AsyncSession, user_id: int) -> int:
"""Upgrade capacity level"""
bank = await get_bank(database_session, user_id)
upgrade_price = capacity_upgrade_price(bank.capacity_level)
# Can't afford this upgrade
if upgrade_price > bank.dinks:
raise exceptions.NotEnoughDinks
bank.dinks -= upgrade_price
bank.capacity_level += 1
database_session.add(bank)
await database_session.commit()
return bank.capacity_level
async def upgrade_interest(database_session: AsyncSession, user_id: int) -> int:
"""Upgrade interest level"""
bank = await get_bank(database_session, user_id)
upgrade_price = interest_upgrade_price(bank.interest_level)
# Can't afford this upgrade
if upgrade_price > bank.dinks:
raise exceptions.NotEnoughDinks
bank.dinks -= upgrade_price
bank.interest_level += 1
database_session.add(bank)
await database_session.commit()
return bank.interest_level
async def upgrade_rob(database_session: AsyncSession, user_id: int) -> int:
"""Upgrade rob level"""
bank = await get_bank(database_session, user_id)
upgrade_price = rob_upgrade_price(bank.rob_level)
# Can't afford this upgrade
if upgrade_price > bank.dinks:
raise exceptions.NotEnoughDinks
bank.dinks -= upgrade_price
bank.rob_level += 1
database_session.add(bank)
await database_session.commit()
return bank.rob_level

View File

@ -1,2 +1,6 @@
class DoubleNightly(Exception):
"""Exception raised when claiming nightlies multiple times per day"""
class NotEnoughDinks(Exception):
"""Exception raised when trying to do something you don't have the Dinks for"""

View File

@ -17,16 +17,17 @@ class Bank(Base):
bank_id: int = Column(Integer, primary_key=True)
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_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
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
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")
@ -67,7 +68,7 @@ class NightlyData(Base):
nightly_id: int = Column(Integer, primary_key=True)
user_id: int = Column(BigInteger, ForeignKey("users.user_id"))
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")
@ -81,7 +82,7 @@ class UforaCourse(Base):
name: str = Column(Text, nullable=False, unique=True)
code: str = Column(Text, nullable=False, unique=True)
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(
"UforaAnnouncement", back_populates="course", cascade="all, delete-orphan", lazy="selectin"

View File

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))

View File

@ -4,10 +4,11 @@ import discord
from discord.ext import commands
from database.crud import currency as crud
from database.exceptions.currency import DoubleNightly
from database.exceptions.currency import DoubleNightly, NotEnoughDinks
from didier import Didier
from didier.utils.discord.checks import is_owner
from didier.utils.discord.converters import abbreviated_number
from database.utils.math.currency import capacity_upgrade_price, interest_upgrade_price, rob_upgrade_price
from didier.utils.types.string import pluralize
@ -34,11 +35,75 @@ class Currency(commands.Cog):
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):
"""Show your Didier Bank information"""
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)
@bank_upgrades.command(name="Capacity", aliases=["C"])
async def bank_upgrade_capacity(self, ctx: commands.Context):
"""Upgrade the capacity level of your bank"""
async with self.client.db_session as session:
try:
await crud.upgrade_capacity(session, ctx.author.id)
await ctx.message.add_reaction("")
except NotEnoughDinks:
await ctx.reply("Je hebt niet genoeg Didier Dinks om dit te doen.", mention_author=False)
await self.client.reject_message(ctx.message)
@bank_upgrades.command(name="Interest", aliases=["I"])
async def bank_upgrade_interest(self, ctx: commands.Context):
"""Upgrade the interest level of your bank"""
async with self.client.db_session as session:
try:
await crud.upgrade_interest(session, ctx.author.id)
await ctx.message.add_reaction("")
except NotEnoughDinks:
await ctx.reply("Je hebt niet genoeg Didier Dinks om dit te doen.", mention_author=False)
await self.client.reject_message(ctx.message)
@bank_upgrades.command(name="Rob", aliases=["R"])
async def bank_upgrade_rob(self, ctx: commands.Context):
"""Upgrade the rob level of your bank"""
async with self.client.db_session as session:
try:
await crud.upgrade_rob(session, ctx.author.id)
await ctx.message.add_reaction("")
except NotEnoughDinks:
await ctx.reply("Je hebt niet genoeg Didier Dinks om dit te doen.", mention_author=False)
await self.client.reject_message(ctx.message)
@commands.hybrid_command(name="dinks")
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:
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 = await fetch_ufora_announcements(session)
announcements = await fetch_ufora_announcements(self.client.http_session, db_session)
for announcement in announcements:
await announcements_channel.send(embed=announcement.to_embed())

View File

@ -3,9 +3,11 @@ from dataclasses import dataclass, field
from datetime import datetime
from typing import Optional
import async_timeout
import discord
import feedparser
import pytz
from aiohttp import ClientSession
from markdownify import markdownify as md
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])
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"""
notifications: list[UforaNotification] = []
@ -124,7 +128,7 @@ async def fetch_ufora_announcements(session: AsyncSession) -> list[UforaNotifica
if settings.UFORA_RSS_TOKEN is None:
return notifications
courses = await crud.get_courses_with_announcements(session)
courses = await crud.get_courses_with_announcements(database_session)
for course in courses:
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
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
fresh_feed: list[dict] = []
@ -161,6 +167,6 @@ async def fetch_ufora_announcements(session: AsyncSession) -> list[UforaNotifica
notifications.append(notification)
# 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

View File

@ -1,6 +1,7 @@
import os
import discord
from aiohttp import ClientSession
from discord.ext import commands
from sqlalchemy.ext.asyncio import AsyncSession
@ -14,6 +15,7 @@ class Didier(commands.Bot):
"""DIDIER <3"""
initial_extensions: tuple[str, ...] = ()
http_session: ClientSession
def __init__(self):
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_directory_extensions("didier/cogs")
# Create aiohttp session
self.http_session = ClientSession()
async def _load_initial_extensions(self):
"""Load all extensions that should be loaded before the others"""
for extension in self.initial_extensions:

View File

@ -30,7 +30,8 @@ disable = [
"missing-module-docstring",
"too-few-public-methods",
"too-many-arguments",
"too-many-instance-attributes"
"too-many-instance-attributes",
"too-many-locals"
]
[tool.pylint.format]