diff --git a/alembic/versions/9fb84b4d9f0b_add_free_games.py b/alembic/versions/9fb84b4d9f0b_add_free_games.py deleted file mode 100644 index d04f223..0000000 --- a/alembic/versions/9fb84b4d9f0b_add_free_games.py +++ /dev/null @@ -1,30 +0,0 @@ -"""Add free games - -Revision ID: 9fb84b4d9f0b -Revises: 11388e39bb90 -Create Date: 2022-10-13 19:17:58.032182 - -""" -import sqlalchemy as sa - -from alembic import op - -# revision identifiers, used by Alembic. -revision = "9fb84b4d9f0b" -down_revision = "11388e39bb90" -branch_labels = None -depends_on = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.create_table( - "free_games", sa.Column("free_game_id", sa.Integer(), nullable=False), sa.PrimaryKeyConstraint("free_game_id") - ) - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_table("free_games") - # ### end Alembic commands ### diff --git a/database/crud/free_games.py b/database/crud/free_games.py deleted file mode 100644 index b2d835d..0000000 --- a/database/crud/free_games.py +++ /dev/null @@ -1,20 +0,0 @@ -from sqlalchemy import select -from sqlalchemy.ext.asyncio import AsyncSession - -from database.schemas import FreeGame - -__all__ = ["add_free_games", "filter_present_games"] - - -async def add_free_games(session: AsyncSession, game_ids: list[int]): - """Bulk-add a list of IDs into the database""" - games = [FreeGame(free_game_id=game_id) for game_id in game_ids] - session.add_all(games) - await session.commit() - - -async def filter_present_games(session: AsyncSession, game_ids: list[int]) -> list[int]: - """Filter a list of game IDs down to the ones that aren't in the database yet""" - statement = select(FreeGame.free_game_id).where(FreeGame.free_game_id.in_(game_ids)) - matches: list[int] = (await session.execute(statement)).scalars().all() - return list(set(game_ids).difference(matches)) diff --git a/database/schemas.py b/database/schemas.py index ffda6ba..e5322c1 100644 --- a/database/schemas.py +++ b/database/schemas.py @@ -33,7 +33,6 @@ __all__ = [ "DadJoke", "Deadline", "EasterEgg", - "FreeGame", "GitHubLink", "Link", "MemeTemplate", @@ -175,14 +174,6 @@ class EasterEgg(Base): startswith: bool = Column(Boolean, nullable=False, server_default="1") -class FreeGame(Base): - """A temporarily free game""" - - __tablename__ = "free_games" - - free_game_id: int = Column(Integer, primary_key=True) - - class GitHubLink(Base): """A user's GitHub link""" diff --git a/didier/cogs/tasks.py b/didier/cogs/tasks.py index 81136b8..14e7699 100644 --- a/didier/cogs/tasks.py +++ b/didier/cogs/tasks.py @@ -18,8 +18,7 @@ from didier.data.embeds.schedules import ( get_schedule_for_day, parse_schedule_from_content, ) -from didier.data.rss_feeds.free_games import fetch_free_games -from didier.data.rss_feeds.ufora import fetch_ufora_announcements +from didier.data.embeds.ufora.announcements import fetch_ufora_announcements from didier.decorators.tasks import timed_task from didier.utils.discord.checks import is_owner from didier.utils.types.datetime import LOCAL_TIMEZONE, tz_aware_now @@ -49,7 +48,6 @@ class Tasks(commands.Cog): self._tasks = { "birthdays": self.check_birthdays, - "free_games": self.pull_free_games, "schedules": self.pull_schedules, "reminders": self.reminders, "ufora": self.pull_ufora_announcements, @@ -63,17 +61,12 @@ class Tasks(commands.Cog): if settings.BIRTHDAY_ANNOUNCEMENT_CHANNEL is not None: self.check_birthdays.start() - # Only pull free gmaes if a channel was provided - if settings.FREE_GAMES_CHANNEL is not None: - self.pull_free_games.start() - # Only pull announcements if a token was provided if settings.UFORA_RSS_TOKEN is not None and settings.UFORA_ANNOUNCEMENTS_CHANNEL is not None: self.pull_ufora_announcements.start() self.remove_old_ufora_announcements.start() # Start other tasks - self.init_schedules.start() self.reminders.start() self.reset_wordle_word.start() self.pull_schedules.start() @@ -135,36 +128,6 @@ class Tasks(commands.Cog): async def _before_check_birthdays(self): await self.client.wait_until_ready() - @tasks.loop(count=1) - async def init_schedules(self, **kwargs): - """Tasks that loads the schedules in memory on startup""" - _ = kwargs - await self.client.load_schedules() - - @init_schedules.before_loop - async def _before_init_schedules(self): - await self.client.wait_until_ready() - - @tasks.loop(minutes=15) - async def pull_free_games(self, **kwargs): - """Task that checks for free games occasionally""" - _ = kwargs - - # No channel to send the embeds to - if settings.FREE_GAMES_CHANNEL is None: - return - - async with self.client.postgres_session as session: - games = await fetch_free_games(self.client.http_session, session) - channel = self.client.get_channel(settings.FREE_GAMES_CHANNEL) - - for game in games: - await channel.send(embed=game.to_embed()) - - @pull_free_games.before_loop - async def _before_free_games(self): - await self.client.wait_until_ready() - @tasks.loop(time=DAILY_RESET_TIME) @timed_task(enums.TaskType.SCHEDULES) async def pull_schedules(self, **kwargs): @@ -203,10 +166,6 @@ class Tasks(commands.Cog): # Only replace cached version if all schedules succeeded self.client.schedules = new_schedules - @pull_schedules.before_loop - async def _before_pull_schedules(self): - await self.client.wait_until_ready() - @tasks.loop(minutes=10) @timed_task(enums.TaskType.UFORA_ANNOUNCEMENTS) async def pull_ufora_announcements(self, **kwargs): diff --git a/didier/data/embeds/free_games.py b/didier/data/embeds/free_games.py deleted file mode 100644 index d37e0b7..0000000 --- a/didier/data/embeds/free_games.py +++ /dev/null @@ -1,122 +0,0 @@ -import html -from typing import Optional - -import discord -from aiohttp import ClientSession -from overrides import overrides -from pydantic import validator - -from didier.data.embeds.base import EmbedPydantic -from didier.data.scrapers.common import GameStorePage -from didier.data.scrapers.steam import get_steam_webpage_info -from didier.utils.discord import colours - -__all__ = ["SEPARATOR", "FreeGameEmbed"] - -from didier.utils.discord.constants import Limits -from didier.utils.types.string import abbreviate - -SEPARATOR = " • Free • " - - -def _get_store_info(store: str) -> tuple[Optional[str], discord.Colour]: - """Get the image url for a given store""" - store = store.lower() - - if "epic" in store: - return ( - "https://cdn2.unrealengine.com/" - "Unreal+Engine%2Feg-logo-filled-1255x1272-0eb9d144a0f981d1cbaaa1eb957de7a3207b31bb.png", - colours.epic_games_white(), - ) - - if "gog" in store: - return ( - "https://upload.wikimedia.org/wikipedia/commons/thumb/2/2e/GOG.com_logo.svg/1679px-GOG.com_logo.svg.png", - colours.gog_purple(), - ) - - if "steam" in store: - return ( - "https://upload.wikimedia.org/wikipedia/commons/thumb/8/83/" - "Steam_icon_logo.svg/2048px-Steam_icon_logo.svg.png", - colours.steam_blue(), - ) - - return None, discord.Colour.random() - - -class FreeGameEmbed(EmbedPydantic): - """Embed for free games""" - - dc_identifier: int - link: str - title: str - - name: Optional[str] = None - store: Optional[str] = None - - store_page: Optional[GameStorePage] = None - - @validator("title") - def _clean_title(cls, value: str) -> str: - return html.unescape(value) - - async def update(self, http_session: ClientSession): - """Scrape the store page to fetch some information""" - self.name, self.store = self.title.split(SEPARATOR) - - store = (self.store or "").lower() - - if "steam" in store: - self.store_page = await get_steam_webpage_info(http_session, self.link) - elif "epic" in store: - self.link = "https://store.epicgames.com/free-games" - - if self.store_page is not None and self.store_page.url is not None: - self.link = self.store_page.url - - @overrides - def to_embed(self, **kwargs) -> discord.Embed: - embed = discord.Embed() - embed.set_author(name=self.store) - - store_image, store_colour = _get_store_info(self.store or "") - if store_image is not None: - embed.set_thumbnail(url=store_image) - - # Populate with scraped info - if self.store_page is not None: - embed.title = self.store_page.title - embed.set_image(url=self.store_page.image) - embed.description = abbreviate(self.store_page.description, Limits.EMBED_DESCRIPTION_LENGTH) - - if self.store_page.original_price is not None and self.store_page.discounted_price is not None: - if self.store_page.discount_percentage is not None: - discount_pct_str = f" ({self.store_page.discount_percentage})" - else: - discount_pct_str = "" - - embed.add_field( - name="Price", - value=f"~~{self.store_page.original_price}~~ **{self.store_page.discounted_price}** " - f"{discount_pct_str}", - inline=False, - ) - - embed.add_field(name="Open in browser", value=f"[{self.link}]({self.link})") - - if self.store_page.xdg_open_url is not None: - - embed.add_field( - name="Open in app", value=f"[{self.store_page.xdg_open_url}]({self.store_page.xdg_open_url})" - ) - else: - embed.title = self.name - embed.add_field(name="Open in browser", value=f"[{self.link}]({self.link})") - - embed.url = self.link - - embed.colour = store_colour - - return embed diff --git a/didier/data/embeds/ufora/announcements.py b/didier/data/embeds/ufora/announcements.py index abca631..7ded012 100644 --- a/didier/data/embeds/ufora/announcements.py +++ b/didier/data/embeds/ufora/announcements.py @@ -1,11 +1,18 @@ +import re from dataclasses import dataclass, field from datetime import datetime from typing import Optional from zoneinfo import ZoneInfo +import async_timeout import discord +import feedparser +from aiohttp import ClientSession from markdownify import markdownify as md +from sqlalchemy.ext.asyncio import AsyncSession +import settings +from database.crud import ufora_announcements as crud from database.schemas import UforaCourse from didier.data.embeds.base import EmbedBaseModel from didier.utils.discord.colours import ghent_university_blue @@ -13,6 +20,8 @@ from didier.utils.types.datetime import LOCAL_TIMEZONE, int_to_weekday from didier.utils.types.string import leading __all__ = [ + "fetch_ufora_announcements", + "parse_ids", "UforaNotification", ] @@ -98,3 +107,68 @@ class UforaNotification(EmbedBaseModel): ":" f"{leading('0', str(self.published_dt.second))}" ) + + +def parse_ids(url: str) -> Optional[tuple[int, int]]: + """Parse the notification & course id out of a notification url""" + match = re.search(r"\d+-\d+$", url) + + if not match: + return None + + spl = match[0].split("-") + return int(spl[0]), int(spl[1]) + + +async def fetch_ufora_announcements( + http_session: ClientSession, database_session: AsyncSession +) -> list[UforaNotification]: + """Fetch all new announcements""" + notifications: list[UforaNotification] = [] + + # No token provided, don't fetch announcements + if settings.UFORA_RSS_TOKEN is None: + return notifications + + 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)) + + course_url = ( + f"https://ufora.ugent.be/d2l/le/news/rss/{course.course_id}/course?token={settings.UFORA_RSS_TOKEN}" + ) + + # Get the updated feed + 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] = [] + for entry in feed["entries"]: + parsed = parse_ids(entry["id"]) + if parsed is None: + continue + + if parsed[0] not in course_announcement_ids: + fresh_feed.append(entry) + + if fresh_feed: + for item in fresh_feed: + # Parse id's out + # Technically this can't happen but Mypy angry + parsed = parse_ids(item["id"]) + + if parsed is None: + continue + + # Create a new notification + notification_id, course_id = parsed + notification = UforaNotification(item, course, notification_id, course_id) + notifications.append(notification) + + # Create new db entry + await crud.create_new_announcement(database_session, notification_id, course, notification.published_dt) + + return notifications diff --git a/didier/data/rss_feeds/__init__.py b/didier/data/rss_feeds/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/didier/data/rss_feeds/free_games.py b/didier/data/rss_feeds/free_games.py deleted file mode 100644 index fcc02c9..0000000 --- a/didier/data/rss_feeds/free_games.py +++ /dev/null @@ -1,51 +0,0 @@ -import logging -from http import HTTPStatus - -import feedparser -from aiohttp import ClientSession -from sqlalchemy.ext.asyncio import AsyncSession - -from database.crud.free_games import add_free_games, filter_present_games -from didier.data.embeds.free_games import SEPARATOR, FreeGameEmbed - -logger = logging.getLogger(__name__) - - -__all__ = ["fetch_free_games"] - - -async def fetch_free_games(http_session: ClientSession, database_session: AsyncSession) -> list[FreeGameEmbed]: - """Get a fresh list of free games""" - url = "https://pepeizqdeals.com/?call_custom_simple_rss=1&csrp_cat=12" - async with http_session.get(url) as response: - if response.status != HTTPStatus.OK: - logger.error("Free games GET-request failed with status code %d." % response.status) - return [] - - feed = feedparser.parse(await response.text()) - - games: list[FreeGameEmbed] = [] - game_ids: list[int] = [] - - for entry in feed["entries"]: - # Game isn't free - if SEPARATOR not in entry["title"]: - continue - - game = FreeGameEmbed.parse_obj(entry) - games.append(game) - game_ids.append(game.dc_identifier) - - # Filter out games that we already know - filtered_ids = await filter_present_games(database_session, game_ids) - - # Insert new games into the database - await add_free_games(database_session, filtered_ids) - - games = list(filter(lambda x: x.dc_identifier in filtered_ids, games)) - - # Look up additional info - for game in games: - await game.update(http_session) - - return games diff --git a/didier/data/rss_feeds/ufora.py b/didier/data/rss_feeds/ufora.py deleted file mode 100644 index 97db8eb..0000000 --- a/didier/data/rss_feeds/ufora.py +++ /dev/null @@ -1,78 +0,0 @@ -import re -from typing import Optional - -import async_timeout -import feedparser -from aiohttp import ClientSession -from sqlalchemy.ext.asyncio import AsyncSession - -import settings -from database.crud import ufora_announcements as crud -from didier.data.embeds.ufora.announcements import UforaNotification - -__all__ = ["parse_ids", "fetch_ufora_announcements"] - - -def parse_ids(url: str) -> Optional[tuple[int, int]]: - """Parse the notification & course id out of a notification url""" - match = re.search(r"\d+-\d+$", url) - - if not match: - return None - - spl = match[0].split("-") - return int(spl[0]), int(spl[1]) - - -async def fetch_ufora_announcements( - http_session: ClientSession, database_session: AsyncSession -) -> list[UforaNotification]: - """Fetch all new announcements""" - notifications: list[UforaNotification] = [] - - # No token provided, don't fetch announcements - if settings.UFORA_RSS_TOKEN is None: - return notifications - - 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)) - - course_url = ( - f"https://ufora.ugent.be/d2l/le/news/rss/{course.course_id}/course?token={settings.UFORA_RSS_TOKEN}" - ) - - # Get the updated feed - 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] = [] - for entry in feed["entries"]: - parsed = parse_ids(entry["id"]) - if parsed is None: - continue - - if parsed[0] not in course_announcement_ids: - fresh_feed.append(entry) - - if fresh_feed: - for item in fresh_feed: - # Parse id's out - # Technically this can't happen but Mypy angry - parsed = parse_ids(item["id"]) - - if parsed is None: - continue - - # Create a new notification - notification_id, course_id = parsed - notification = UforaNotification(item, course, notification_id, course_id) - notifications.append(notification) - - # Create new db entry - await crud.create_new_announcement(database_session, notification_id, course, notification.published_dt) - - return notifications diff --git a/didier/data/scrapers/common.py b/didier/data/scrapers/common.py deleted file mode 100644 index 3eafcd2..0000000 --- a/didier/data/scrapers/common.py +++ /dev/null @@ -1,58 +0,0 @@ -from dataclasses import dataclass -from typing import Optional, cast - -from bs4 import BeautifulSoup, Tag - -__all__ = ["GameStorePage", "parse_open_graph_tags"] - - -@dataclass -class GameStorePage: - """Dataclass for information on a game's store page""" - - description: str - image: str - title: str - xdg_open_url: Optional[str] = None - url: Optional[str] = None - discount_expiry: Optional[int] = None # TODO - discounted_price: Optional[str] = None - original_price: Optional[str] = None - discount_percentage: Optional[str] = None - - -def parse_open_graph_tags(soup: BeautifulSoup) -> Optional[GameStorePage]: - """Parse Open Graph Protocol tags out of a webpage - - If any of the required tags were not found, this returns None - """ - head = soup.find("head") - - if head is None: - return None - - head = cast(Tag, head) - - title_tag = head.find("meta", property="og:title") - if title_tag is None: - return None - - description_tag = head.find("meta", property="og:description") - if description_tag is None: - return None - - image_tag = head.find("meta", property="og:image") - if image_tag is None: - return None - - url_tag = head.find("meta", property="og:url") - if url_tag is None: - url = None - else: - url = str(url_tag["content"]) # type: ignore - - description = str(description_tag["content"]) # type: ignore - image = str(image_tag["content"]) # type: ignore - title = str(title_tag["content"]) # type: ignore - - return GameStorePage(title=title, description=description, url=url, image=image) diff --git a/didier/data/scrapers/google.py b/didier/data/scrapers/google.py index 389e9ae..9ebb003 100644 --- a/didier/data/scrapers/google.py +++ b/didier/data/scrapers/google.py @@ -74,10 +74,15 @@ def get_search_results(bs: BeautifulSoup) -> list[str]: async def google_search(http_client: ClientSession, query: str): """Get the first 10 Google search results""" + headers = { + "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) " + "Chrome/83.0.4103.97 Safari/537.36" + } + query = urlencode({"q": query}) # Request 20 results in case of duplicates, bad matches, ... - async with http_client.get(f"https://www.google.com/search?{query}&num=20&hl=en") as response: + async with http_client.get(f"https://www.google.com/search?{query}&num=20&hl=en", headers=headers) as response: # Something went wrong if response.status != http.HTTPStatus.OK: return SearchData(query, response.status) diff --git a/didier/data/scrapers/steam.py b/didier/data/scrapers/steam.py deleted file mode 100644 index 39d0837..0000000 --- a/didier/data/scrapers/steam.py +++ /dev/null @@ -1,123 +0,0 @@ -import re -from dataclasses import dataclass -from http import HTTPStatus -from typing import Optional, cast - -from aiohttp import ClientSession -from bs4 import BeautifulSoup, Tag - -from didier.data.scrapers.common import GameStorePage, parse_open_graph_tags - -__all__ = ["get_steam_webpage_info"] - - -@dataclass -class _PriceInfo: - # These are strings because they aren't used as floats, - # and this avoids possible rounding errors - original_price: str - discounted_price: str - discount_percentage: Optional[str] - - def __post_init__(self): - """Fix the price formats""" - self.original_price = "€" + self.original_price.replace(",--", ",00").removesuffix("€") - self.discounted_price = "€" + self.discounted_price.replace(",--", ",00").removesuffix("€") - if self.discounted_price == "€0,00": - self.discounted_price = "Free" - - -def _shorten_url(url: str) -> str: - match = re.search(r"https://store.steampowered.com/app/(\d+)/", url) - if match is None or not match.groups(): - return url - - return f"https://s.team/a/{match.groups()[0]}" - - -def _parse_xdg_open_url(url: str) -> Optional[str]: - match = re.search(r"/app/(\d+)/", url) - if match is None or not match.groups(): - return None - - return f"steam://store/{match.groups()[0]}" - - -def _get_steam_discounts(soup: BeautifulSoup) -> Optional[_PriceInfo]: - discount_wrapper_tag = soup.find("div", class_="discount_block") - if discount_wrapper_tag is None: - return None - - discount_wrapper_tag = cast(Tag, discount_wrapper_tag) - - # Parsing the original (non-discounted) price - original_price_tag = discount_wrapper_tag.find("div", class_="discount_original_price") - if original_price_tag is None: - return None - - original_price_tag = cast(Tag, original_price_tag) - original_price = original_price_tag.text - if original_price is None: - return None - - # Parsing the discounted price - discounted_price_tag = discount_wrapper_tag.find("div", class_="discount_final_price") - if discounted_price_tag is None: - return None - - discounted_price_tag = cast(Tag, discounted_price_tag) - discounted_price = discounted_price_tag.text - if discounted_price is None: - return None - - percentage_tag = discount_wrapper_tag.find("div", class_="discount_pct") - if percentage_tag is None: - percentage = None - else: - percentage = percentage_tag.text - - return _PriceInfo(original_price=original_price, discounted_price=discounted_price, discount_percentage=percentage) - - -def _clean_title(title: str) -> str: - match = re.search(r"Save [\d,]+% on (.*) on Steam", title) - if match is None or not match.groups(): - return title - - return match.groups()[0] - - -async def get_steam_webpage_info(http_session: ClientSession, url: str) -> Optional[GameStorePage]: - """Scrape a Steam page""" - # If not currently on a Steam page, follow a redirect chain until you are - if not url.startswith("https://store.steampowered.com/"): - async with http_session.head(url, allow_redirects=True) as response: - url = str(response.url) - - async with http_session.get(url) as response: - if response.status != HTTPStatus.OK: - return None - - page = await response.text() - - soup = BeautifulSoup(page, "html.parser") - - page_tags = parse_open_graph_tags(soup) - if page_tags is None: - return None - - if page_tags.url is None: - page_tags.url = url - - page_tags.title = _clean_title(page_tags.title) - page_tags.xdg_open_url = _parse_xdg_open_url(page_tags.url) - page_tags.url = _shorten_url(page_tags.url) - - price_info = _get_steam_discounts(soup) - - if price_info is not None: - page_tags.original_price = price_info.original_price - page_tags.discounted_price = price_info.discounted_price - page_tags.discount_percentage = price_info.discount_percentage - - return page_tags diff --git a/didier/didier.py b/didier/didier.py index cd82ec8..06db727 100644 --- a/didier/didier.py +++ b/didier/didier.py @@ -78,6 +78,9 @@ class Didier(commands.Bot): # Create directories that are ignored on GitHub self._create_ignored_directories() + # Load schedules + await self.load_schedules() + # Load the Wordle dictionary self._load_wordle_words() @@ -87,12 +90,7 @@ class Didier(commands.Bot): await self.database_caches.initialize_caches(session) # Create aiohttp session - self.http_session = ClientSession( - headers={ - "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) " - "Chrome/105.0.0.0 Safari/537.36" - } - ) + self.http_session = ClientSession() # Load extensions await self._load_initial_extensions() diff --git a/didier/utils/discord/colours.py b/didier/utils/discord/colours.py index dc58608..e0ebb5c 100644 --- a/didier/utils/discord/colours.py +++ b/didier/utils/discord/colours.py @@ -1,21 +1,15 @@ import discord __all__ = [ - "epic_games_white", "error_red", "github_white", "ghent_university_blue", "ghent_university_yellow", "google_blue", - "steam_blue", "urban_dictionary_green", ] -def epic_games_white() -> discord.Colour: - return discord.Colour.from_rgb(255, 255, 255) - - def error_red() -> discord.Colour: return discord.Colour.red() @@ -32,17 +26,9 @@ def ghent_university_yellow() -> discord.Colour: return discord.Colour.from_rgb(255, 210, 0) -def gog_purple() -> discord.Colour: - return discord.Colour.purple() - - def google_blue() -> discord.Colour: return discord.Colour.from_rgb(66, 133, 244) -def steam_blue() -> discord.Colour: - return discord.Colour.from_rgb(102, 192, 244) - - def urban_dictionary_green() -> discord.Colour: return discord.Colour.from_rgb(220, 255, 0) diff --git a/settings.py b/settings.py index 3342ea0..aa0f6fe 100644 --- a/settings.py +++ b/settings.py @@ -27,8 +27,6 @@ __all__ = [ "DISCORD_TEST_GUILDS", "DISCORD_BOOS_REACT", "DISCORD_CUSTOM_COMMAND_PREFIX", - "ERRORS_CHANNEL", - "FREE_GAMES_CHANNEL", "UFORA_ANNOUNCEMENTS_CHANNEL", "UFORA_RSS_TOKEN", "IMGFLIP_NAME", @@ -67,7 +65,6 @@ DISCORD_BOOS_REACT: str = env.str("DISCORD_BOOS_REACT", "<:boos:6296037858402631 DISCORD_CUSTOM_COMMAND_PREFIX: str = env.str("DISCORD_CUSTOM_COMMAND_PREFIX", "?") BIRTHDAY_ANNOUNCEMENT_CHANNEL: Optional[int] = env.int("BIRTHDAY_ANNOUNCEMENT_CHANNEL", None) ERRORS_CHANNEL: Optional[int] = env.int("ERRORS_CHANNEL", None) -FREE_GAMES_CHANNEL: Optional[int] = env.int("FREE_GAMES_CHANNEL", None) UFORA_ANNOUNCEMENTS_CHANNEL: Optional[int] = env.int("UFORA_ANNOUNCEMENTS_CHANNEL", None) """Discord Role ID's""" diff --git a/tests/conftest.py b/tests/conftest.py index 2a1a4a2..c218524 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,7 +1,5 @@ import asyncio -import json -import pathlib -from typing import AsyncGenerator, Generator, Union +from typing import AsyncGenerator, Generator from unittest.mock import MagicMock import pytest @@ -68,22 +66,3 @@ def mock_client() -> Didier: mock_client.user = mock_user return mock_client - - -"""Data providers""" - - -def _provide(name: str) -> Union[dict, str]: - location = pathlib.Path(__file__).parent / "test_data" / name - - with open(location, "r") as fp: - if name.endswith(".json"): - return json.load(fp) - - return fp.read() - - -@pytest.fixture -def free_games_response() -> str: - """Fixture to get an example response from the free games RSS feed""" - return _provide("free_games.rss") diff --git a/tests/test_data/free_games.rss b/tests/test_data/free_games.rss deleted file mode 100644 index 8df12a4..0000000 --- a/tests/test_data/free_games.rss +++ /dev/null @@ -1,40 +0,0 @@ - - - - pepeizq's deals - Follow the latest deals for PC games from legit stores such as Steam, Humble, Fanatical, Gamesplanet, GOG and more - https://pepeizqdeals.com - Thu, 13 Oct 2022 17:11:24 +0000 - - <![CDATA[Minion Masters – Torment • Free • Steam]]> - - Thu, 13 Oct 2022 18:08:41 +0100 - pepeizq - 55623 - 2022-10-13 18:08:59 - 2022-10-13 18:08:41 - 12 - - - - <![CDATA[Darkwood + ToeJam & Earl: Back in the Groove! • Free • Epic Games Store]]> - - Thu, 13 Oct 2022 17:03:59 +0100 - pepeizq - 55616 - 2022-10-13 17:04:17 - 2022-10-13 17:03:59 - 12 - - - - <![CDATA[Rebel Inc: Escalation – Sand & Secrets • Free • Steam]]> - - Tue, 20 Sep 2022 18:08:52 +0100 - pepeizq - 54874 - 2022-09-20 18:09:03 - 2022-09-20 18:08:52 - 12 - - diff --git a/tests/test_database/test_crud/test_free_games.py b/tests/test_database/test_crud/test_free_games.py deleted file mode 100644 index d05df15..0000000 --- a/tests/test_database/test_crud/test_free_games.py +++ /dev/null @@ -1,17 +0,0 @@ -from sqlalchemy import select -from sqlalchemy.ext.asyncio import AsyncSession - -from database.crud import free_games as crud -from database.schemas import FreeGame - - -async def test_add_games(postgres: AsyncSession): - """Test adding new games""" - statement = select(FreeGame) - games = (await postgres.execute(statement)).scalars().all() - assert not games - - await crud.add_free_games(postgres, [1, 2, 3, 4]) - - games = (await postgres.execute(statement)).scalars().all() - assert len(games) == 4