diff --git a/.env.example b/.env.example index e9db963..a24a778 100644 --- a/.env.example +++ b/.env.example @@ -3,5 +3,3 @@ DEBUG=True EMAIL_HOST_USER= EMAIL_HOST_PASSWORD= DISCORD_WEBHOOK_URL= -TWITCH_CLIENT_ID= -TWITCH_CLIENT_SECRET= diff --git a/.vscode/settings.json b/.vscode/settings.json index 1049259..e7c2d83 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -11,6 +11,8 @@ "cacd", "cellspacing", "collectstatic", + "createcachetable", + "createsuperuser", "djade", "docstrings", "dotenv", @@ -41,6 +43,7 @@ "pyupgrade", "requirepass", "rewardcampaign", + "runserver", "sitewide", "socialaccount", "staticfiles", @@ -55,6 +58,7 @@ "ttvdrops", "ulimits", "Valair", + "venv", "whitenoise", "xdefiant" ], diff --git a/README.md b/README.md index 1c5cd7b..8a37714 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,43 @@ # twitch-drop-notifier Get notified when a new drop is available on Twitch + +## Development + +- [Python 3.13](https://www.python.org/downloads/) is required to run this project. + +```bash +# Create and activate a virtual environment. +python -m venv .venv +source .venv/bin/activate + +# Remember to run `source .venv/bin/activate` before running the following commands: +# You will need to run this command every time you open a new terminal. +# VSCode will automatically activate the virtual environment if you have the Python extension installed. + +# Install dependencies. +pip install -r requirements.txt +pip install -r requirements-dev.txt + +# Run the following to get passwords for the .env file. +python -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())' + +# Rename .env.example to .env and fill in the required values. +# DISCORD_WEBHOOK_URL and EMAIL_* can be left empty. +mv .env.example .env + +# Run the migrations. +python manage.py migrate + +# Create cache table. +python manage.py createcachetable + +# Create a superuser. +python manage.py createsuperuser + +# Run the server. +python manage.py runserver + +# Run the tests. +pytest +``` diff --git a/core/models.py b/core/models.py index 42e0d76..451836f 100644 --- a/core/models.py +++ b/core/models.py @@ -4,7 +4,6 @@ import logging from typing import TYPE_CHECKING, ClassVar, Self import auto_prefetch -import pghistory from django.contrib.auth.models import AbstractUser from django.db import models @@ -46,7 +45,6 @@ class ScrapedJson(auto_prefetch.Model): return f"{'' if self.imported_at else 'Not imported - '}{self.created_at}" -@pghistory.track() class Owner(auto_prefetch.Model): """The company or person that owns the game. @@ -102,7 +100,6 @@ class Owner(auto_prefetch.Model): return self -@pghistory.track() class Game(auto_prefetch.Model): """The game the drop campaign is for. Note that some reward campaigns are not tied to a game. @@ -240,7 +237,6 @@ class Game(auto_prefetch.Model): return self -@pghistory.track() class DropCampaign(auto_prefetch.Model): """This is the drop campaign we will see on the front end.""" @@ -345,7 +341,6 @@ class DropCampaign(auto_prefetch.Model): return self -@pghistory.track() class TimeBasedDrop(auto_prefetch.Model): """This is the drop we will see on the front end. @@ -475,7 +470,6 @@ class TimeBasedDrop(auto_prefetch.Model): return self -@pghistory.track() class Benefit(auto_prefetch.Model): """Benefits are the rewards for the drops.""" diff --git a/core/settings.py b/core/settings.py index e348591..2994fd4 100644 --- a/core/settings.py +++ b/core/settings.py @@ -2,15 +2,10 @@ import os from pathlib import Path from typing import Literal -import django_stubs_ext from django.contrib import messages from dotenv import load_dotenv from platformdirs import user_data_dir -# Monkeypatching Django, so stubs will work for all generics, -# see: https://github.com/typeddjango/django-stubs -django_stubs_ext.monkeypatch() - # Parse a .env file and then load all the variables found as environment variables. load_dotenv(verbose=True) @@ -109,7 +104,6 @@ DISCORD_WEBHOOK_URL: str = os.getenv(key="DISCORD_WEBHOOK_URL", default="") # Be sure to add pghistory.admin above the django.contrib.admin, otherwise the custom admin templates won't be used. INSTALLED_APPS: list[str] = [ "core.apps.CoreConfig", - "pghistory.admin", "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", @@ -118,10 +112,6 @@ INSTALLED_APPS: list[str] = [ "django.contrib.staticfiles", "django.contrib.sites", "debug_toolbar", - "pgclone", - "pghistory", - "pgstats", - "pgtrigger", ] # Middleware is a framework of hooks into Django's request/response processing. @@ -161,18 +151,20 @@ TEMPLATES: list[dict[str, str | list[Path] | bool | dict[str, list[str] | list[t }, ] -# TODO(TheLovinator): Run psycopg[c] in production. -# https://www.psycopg.org/psycopg3/docs/basic/install.html#local-installation -DATABASES: dict[str, dict[str, str | dict[str, bool]]] = { +DATABASES: dict[str, dict[str, str | Path | dict[str, str | int]]] = { "default": { - "ENGINE": "django.db.backends.postgresql", - "NAME": os.getenv(key="DB_NAME", default=""), - "USER": os.getenv(key="DB_USER", default=""), - "PASSWORD": os.getenv(key="DB_PASSWORD", default=""), - "HOST": os.getenv(key="DB_HOST", default=""), - "PORT": os.getenv(key="DB_PORT", default=""), + "ENGINE": "django.db.backends.sqlite3", + "NAME": DATA_DIR / "db.sqlite3", "OPTIONS": { - "pool": True, # TODO(TheLovinator): Benchmark this. # noqa: TD003 + "transaction_mode": "IMMEDIATE", + "timeout": 5, + "init_command": """ + PRAGMA journal_mode=WAL; + PRAGMA synchronous=NORMAL; + PRAGMA mmap_size=134217728; + PRAGMA journal_size_limit=27103364; + PRAGMA cache_size=2000; + """, }, }, } diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 07a6485..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,36 +0,0 @@ -services: - garnet: - container_name: garnet - image: "ghcr.io/microsoft/garnet" - user: "1000:1000" - restart: always - ulimits: - memlock: -1 - command: [ "--auth", "Password", "--password", "${GARNET_PASSWORD}", "--storage-tier", "--logdir", "/logs", "--aof", "--port", "6380" ] - ports: - - "6380:6380" - volumes: - - /Docker/ttvdrops/Garnet/data:/data - - /Docker/ttvdrops/Garnet/logs:/logs - networks: - - ttvdrops_garnet - - postgres: - container_name: ttvdrops_postgres - image: postgres:16 - user: "1000:1000" - ports: - - 5433:5432 - restart: always - environment: - - POSTGRES_USER=${POSTGRES_USER} - - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - - POSTGRES_DB=${POSTGRES_DB} - volumes: - - /Docker/ttvdrops/Postgres:/var/lib/postgresql/data - networks: - - ttvdrops_db - -networks: - ttvdrops_garnet: - ttvdrops_db: diff --git a/pyproject.toml b/pyproject.toml index 08beeea..6f7cba6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,14 +7,9 @@ requires-python = ">=3.13" dependencies = [ "discord-webhook", "django-debug-toolbar", - "django-stubs-ext", "django", "platformdirs", - "psycopg[binary,pool]", "python-dotenv", - "django-pghistory", - "django-pgclone", - "django-pgstats", "django-auto-prefetch", ] @@ -22,15 +17,7 @@ dependencies = [ # Or you can install them with `uv install --dev -r requirements-dev.txt`. # uv can be replaced with `pip`if you don't have uv installed. [dependency-groups] -dev = [ - "djlint", - "pre-commit", - "pytest", - "pytest-django", - "ruff", - "django-stubs[compatible-mypy]", - "black", -] +dev = ["pre-commit", "pytest", "pytest-django", "ruff"] # https://docs.astral.sh/ruff/settings/ [tool.ruff] diff --git a/requirements-dev.txt b/requirements-dev.txt index 545990c..33534c7 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,5 +1,3 @@ -django-stubs[compatible-mypy] -djlint pre-commit pytest pytest-django diff --git a/requirements.txt b/requirements.txt index 742637e..fa2fdc1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,5 +2,4 @@ discord-webhook django django-debug-toolbar platformdirs -psycopg[binary,pool] python-dotenv