From 67b641068709e819d292e635200e3ffeb2c4e591 Mon Sep 17 00:00:00 2001 From: cato447 Date: Mon, 12 Jan 2026 18:12:30 +0100 Subject: [PATCH] docker ready deployment --- .gitignore | 4 +- app/.gitignore | 2 + app/Dockerfile | 18 ++++++++ app/{config.py.example => config.py} | 7 ++- app/requirements.txt | 48 ++++++++++++++++++++ discord/.gitignore | 2 +- discord/Dockerfile | 9 ++++ discord/config.py.example | 3 -- discord/discord_bot.py | 57 ++++++++++++++---------- discord/requirements.txt | 36 +++++++++++++++ docker-compose.yml | 34 ++++++++++++++ pyproject.toml | 2 + uv.lock | 66 ++++++++++++++++++++++++++++ 13 files changed, 253 insertions(+), 35 deletions(-) create mode 100644 app/.gitignore create mode 100644 app/Dockerfile rename app/{config.py.example => config.py} (63%) create mode 100644 app/requirements.txt create mode 100644 discord/Dockerfile delete mode 100644 discord/config.py.example create mode 100644 discord/requirements.txt create mode 100644 docker-compose.yml diff --git a/.gitignore b/.gitignore index 25a103a..832b30f 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,4 @@ wheels/ # Virtual environments .venv -instance - -app/config.py +data diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..17bcd2e --- /dev/null +++ b/app/.gitignore @@ -0,0 +1,2 @@ +.env.db +.env.web diff --git a/app/Dockerfile b/app/Dockerfile new file mode 100644 index 0000000..1a84515 --- /dev/null +++ b/app/Dockerfile @@ -0,0 +1,18 @@ +FROM python:3.12-slim + +WORKDIR /src + +# Install dependencies +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +# Copy the entire project +COPY . ./app/ + +# Expose Gunicorn port +EXPOSE 8000 + +# Gunicorn command for a package structure +# "app:create_app()" assumes you have a factory function in __init__.py +# If your Flask instance is just named 'app' inside __init__.py, use "app:app" +CMD ["gunicorn", "--preload", "-w", "4", "-b", "0.0.0.0:8000", "app:create_app()"] diff --git a/app/config.py.example b/app/config.py similarity index 63% rename from app/config.py.example rename to app/config.py index 29379df..516b86d 100644 --- a/app/config.py.example +++ b/app/config.py @@ -3,12 +3,11 @@ import os class Config: SECRET_KEY = os.environ.get('SECRET_KEY') - basedir = os.path.abspath(os.path.dirname(__file__)) - SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \ - 'sqlite:///' + os.path.join(basedir, '../instance/registration.db') + SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') SQLALCHEMY_TRACK_MODIFICATIONS = False - MAIL_SERVER = 'mail.your-server.de' + # Email Settings (Update these!) + MAIL_SERVER = os.environ.get('MAIL_SERVER') MAIL_PORT = 587 MAIL_USE_TLS = True MAIL_USERNAME = os.environ.get('EMAIL_USER') diff --git a/app/requirements.txt b/app/requirements.txt new file mode 100644 index 0000000..0f79662 --- /dev/null +++ b/app/requirements.txt @@ -0,0 +1,48 @@ +# This file was autogenerated by uv via the following command: +# uv export --format requirements-txt -o requirements.txt --no-hashes +blinker==1.9.0 + # via + # flask + # flask-mail +click==8.3.1 + # via flask +colorama==0.4.6 ; sys_platform == 'win32' + # via click +dnspython==2.8.0 + # via email-validator +email-validator==2.3.0 + # via register-website +flask==3.1.2 + # via + # flask-mail + # flask-sqlalchemy + # register-website +flask-mail==0.10.0 + # via register-website +flask-sqlalchemy==3.1.1 + # via register-website +greenlet==3.3.0 ; platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64' + # via sqlalchemy +gunicorn==23.0.0 + # via register-website +idna==3.11 + # via email-validator +itsdangerous==2.2.0 + # via flask +jinja2==3.1.6 + # via flask +markupsafe==3.0.3 + # via + # flask + # jinja2 + # werkzeug +packaging==25.0 + # via gunicorn +psycopg2-binary==2.9.11 + # via register-website +sqlalchemy==2.0.45 + # via flask-sqlalchemy +typing-extensions==4.15.0 + # via sqlalchemy +werkzeug==3.1.4 + # via flask diff --git a/discord/.gitignore b/discord/.gitignore index 4acd06b..32e94de 100644 --- a/discord/.gitignore +++ b/discord/.gitignore @@ -1 +1 @@ -config.py +.env.bot diff --git a/discord/Dockerfile b/discord/Dockerfile new file mode 100644 index 0000000..a4cb843 --- /dev/null +++ b/discord/Dockerfile @@ -0,0 +1,9 @@ +FROM python:3.12-slim +WORKDIR /app +RUN apt-get update && apt-get install -y libpq-dev gcc && rm -rf /var/lib/apt/lists/* +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt +COPY . . +RUN useradd -m botuser +USER botuser +CMD ["python", "discord_bot.py"] diff --git a/discord/config.py.example b/discord/config.py.example deleted file mode 100644 index 9ebf641..0000000 --- a/discord/config.py.example +++ /dev/null @@ -1,3 +0,0 @@ -TOKEN = -ROLE_NAME = "Participant" -DATABASE_FILE = diff --git a/discord/discord_bot.py b/discord/discord_bot.py index 8f61e02..b4d8579 100644 --- a/discord/discord_bot.py +++ b/discord/discord_bot.py @@ -1,7 +1,7 @@ import discord from discord import app_commands, ui -import sqlite3 -from config import TOKEN, ROLE_NAME, DATABASE_FILE +import psycopg2 +import os class VerificationModal(ui.Modal, title='Server Verification'): token_input = ui.TextInput( @@ -15,31 +15,40 @@ class VerificationModal(ui.Modal, title='Server Verification'): async def on_submit(self, interaction: discord.Interaction): token = self.token_input.value - conn = sqlite3.connect(DATABASE_FILE) - cursor = conn.cursor() - cursor.execute("SELECT id, discord_user_id FROM participant WHERE discord_token = ?", (token,)) - result = cursor.fetchone() + try: + # Connect using your Postgres credentials + conn = psycopg2.connect(database=os.environ.get("POSTGRES_DB"), username=os.environ.get("POSTGRES_USER"), password=os.environ.get("POSTGRES_PASSWORD")) + with conn.cursor() as cursor: + # Postgres uses %s as placeholders instead of ? + cursor.execute("SELECT id, discord_user_id FROM participant WHERE discord_token = %s", (token,)) + result = cursor.fetchone() - if not result: - await interaction.response.send_message("Invalid token. Check your email.", ephemeral=True) - return + if not result: + await interaction.response.send_message("Invalid token. Check your email.", ephemeral=True) + return - db_id, existing_user_id = result - if existing_user_id: - await interaction.response.send_message("This token is already linked to an account.", ephemeral=True) - return + db_id, existing_user_id = result + if existing_user_id: + await interaction.response.send_message("This token is already linked to an account.", ephemeral=True) + return - # Update DB and Role - cursor.execute("UPDATE participant SET discord_user_id = ? WHERE id = ?", (str(interaction.user.id), db_id)) - conn.commit() - conn.close() + # Update DB + cursor.execute("UPDATE participant SET discord_user_id = %s WHERE id = %s", (str(interaction.user.id), db_id)) + conn.commit() + + conn.close() - role = discord.utils.get(interaction.guild.roles, name=ROLE_NAME) - if role: - await interaction.user.add_roles(role) - await interaction.response.send_message("Verified! Welcome to the server.", ephemeral=True) - else: - await interaction.response.send_message("Verification successful, but role not found. Contact staff.", ephemeral=True) + # Role Logic + role = discord.utils.get(interaction.guild.roles, name=os.environ.get("ROLE_NAME")) + if role: + await interaction.user.add_roles(role) + await interaction.response.send_message("Verified! Welcome to the server.", ephemeral=True) + else: + await interaction.response.send_message("Verification successful, but role not found. Contact staff.", ephemeral=True) + + except Exception as e: + print(f"Database Error: {e}") + await interaction.response.send_message("A database error occurred. Please try again later.", ephemeral=True) class PersistentView(ui.View): def __init__(self): @@ -85,4 +94,4 @@ async def setup_welcome(interaction: discord.Interaction): await interaction.channel.send(embed=embed, view=PersistentView()) await interaction.response.send_message("Setup complete!", ephemeral=True) -bot.run(TOKEN) +bot.run(os.environ.get("TOKEN")) diff --git a/discord/requirements.txt b/discord/requirements.txt new file mode 100644 index 0000000..3299047 --- /dev/null +++ b/discord/requirements.txt @@ -0,0 +1,36 @@ +# This file was autogenerated by uv via the following command: +# uv export --format requirements-txt -o requirements.txt --no-hashes +aiohappyeyeballs==2.6.1 + # via aiohttp +aiohttp==3.13.3 + # via discord-py +aiosignal==1.4.0 + # via aiohttp +attrs==25.4.0 + # via aiohttp +audioop-lts==0.2.2 ; python_full_version >= '3.13' + # via discord-py +discord==2.3.2 + # via test +discord-py==2.6.4 + # via discord +frozenlist==1.8.0 + # via + # aiohttp + # aiosignal +idna==3.11 + # via yarl +multidict==6.7.0 + # via + # aiohttp + # yarl +propcache==0.4.1 + # via + # aiohttp + # yarl +psycopg2-binary==2.9.11 + # via test +typing-extensions==4.15.0 ; python_full_version < '3.13' + # via aiosignal +yarl==1.22.0 + # via aiohttp diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..d04cfa1 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,34 @@ +services: + db: + image: postgres:18-alpine + restart: always + env_file: ./app/.env.db + volumes: + - ./data/postgres:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] + interval: 5s + timeout: 5s + retries: 5 + + flask-register: + build: + context: ./app + dockerfile: Dockerfile + env_file: ./app/.env.web + ports: + - "8000:8000" + depends_on: + db: + condition: service_healthy + restart: on-failure + + discord-bot: + build: + context: ./discord + dockerfile: Dockerfile + env_file: ./discord/.env.bot + depends_on: + db: + condition: service_healthy + restart: on-failure diff --git a/pyproject.toml b/pyproject.toml index e58c9b7..3936b9b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,4 +10,6 @@ dependencies = [ "flask>=3.1.2", "flask-mail>=0.10.0", "flask-sqlalchemy>=3.1.1", + "gunicorn>=23.0.0", + "psycopg2-binary>=2.9.11", ] diff --git a/uv.lock b/uv.lock index 86f5d3c..ac89d44 100644 --- a/uv.lock +++ b/uv.lock @@ -426,6 +426,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4f/dc/041be1dff9f23dac5f48a43323cd0789cb798342011c19a248d9c9335536/greenlet-3.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c10513330af5b8ae16f023e8ddbfb486ab355d04467c4679c5cfe4659975dd9", size = 1676034, upload-time = "2025-12-04T14:27:33.531Z" }, ] +[[package]] +name = "gunicorn" +version = "23.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/34/72/9614c465dc206155d93eff0ca20d42e1e35afc533971379482de953521a4/gunicorn-23.0.0.tar.gz", hash = "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec", size = 375031, upload-time = "2024-08-10T20:25:27.378Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/7d/6dac2a6e1eba33ee43f318edbed4ff29151a49b5d37f080aad1e6469bca4/gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d", size = 85029, upload-time = "2024-08-10T20:25:24.996Z" }, +] + [[package]] name = "idna" version = "3.11" @@ -618,6 +630,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/da/7d22601b625e241d4f23ef1ebff8acfc60da633c9e7e7922e24d10f592b3/multidict-6.7.0-py3-none-any.whl", hash = "sha256:394fc5c42a333c9ffc3e421a4c85e08580d990e08b99f6bf35b4132114c5dcb3", size = 12317, upload-time = "2025-10-06T14:52:29.272Z" }, ] +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + [[package]] name = "propcache" version = "0.4.1" @@ -702,6 +723,47 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, ] +[[package]] +name = "psycopg2-binary" +version = "2.9.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ac/6c/8767aaa597ba424643dc87348c6f1754dd9f48e80fdc1b9f7ca5c3a7c213/psycopg2-binary-2.9.11.tar.gz", hash = "sha256:b6aed9e096bf63f9e75edf2581aa9a7e7186d97ab5c177aa6c87797cd591236c", size = 379620, upload-time = "2025-10-10T11:14:48.041Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d8/91/f870a02f51be4a65987b45a7de4c2e1897dd0d01051e2b559a38fa634e3e/psycopg2_binary-2.9.11-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:be9b840ac0525a283a96b556616f5b4820e0526addb8dcf6525a0fa162730be4", size = 3756603, upload-time = "2025-10-10T11:11:52.213Z" }, + { url = "https://files.pythonhosted.org/packages/27/fa/cae40e06849b6c9a95eb5c04d419942f00d9eaac8d81626107461e268821/psycopg2_binary-2.9.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f090b7ddd13ca842ebfe301cd587a76a4cf0913b1e429eb92c1be5dbeb1a19bc", size = 3864509, upload-time = "2025-10-10T11:11:56.452Z" }, + { url = "https://files.pythonhosted.org/packages/2d/75/364847b879eb630b3ac8293798e380e441a957c53657995053c5ec39a316/psycopg2_binary-2.9.11-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ab8905b5dcb05bf3fb22e0cf90e10f469563486ffb6a96569e51f897c750a76a", size = 4411159, upload-time = "2025-10-10T11:12:00.49Z" }, + { url = "https://files.pythonhosted.org/packages/6f/a0/567f7ea38b6e1c62aafd58375665a547c00c608a471620c0edc364733e13/psycopg2_binary-2.9.11-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:bf940cd7e7fec19181fdbc29d76911741153d51cab52e5c21165f3262125685e", size = 4468234, upload-time = "2025-10-10T11:12:04.892Z" }, + { url = "https://files.pythonhosted.org/packages/30/da/4e42788fb811bbbfd7b7f045570c062f49e350e1d1f3df056c3fb5763353/psycopg2_binary-2.9.11-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fa0f693d3c68ae925966f0b14b8edda71696608039f4ed61b1fe9ffa468d16db", size = 4166236, upload-time = "2025-10-10T11:12:11.674Z" }, + { url = "https://files.pythonhosted.org/packages/3c/94/c1777c355bc560992af848d98216148be5f1be001af06e06fc49cbded578/psycopg2_binary-2.9.11-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a1cf393f1cdaf6a9b57c0a719a1068ba1069f022a59b8b1fe44b006745b59757", size = 3983083, upload-time = "2025-10-30T02:55:15.73Z" }, + { url = "https://files.pythonhosted.org/packages/bd/42/c9a21edf0e3daa7825ed04a4a8588686c6c14904344344a039556d78aa58/psycopg2_binary-2.9.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ef7a6beb4beaa62f88592ccc65df20328029d721db309cb3250b0aae0fa146c3", size = 3652281, upload-time = "2025-10-10T11:12:17.713Z" }, + { url = "https://files.pythonhosted.org/packages/12/22/dedfbcfa97917982301496b6b5e5e6c5531d1f35dd2b488b08d1ebc52482/psycopg2_binary-2.9.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:31b32c457a6025e74d233957cc9736742ac5a6cb196c6b68499f6bb51390bd6a", size = 3298010, upload-time = "2025-10-10T11:12:22.671Z" }, + { url = "https://files.pythonhosted.org/packages/66/ea/d3390e6696276078bd01b2ece417deac954dfdd552d2edc3d03204416c0c/psycopg2_binary-2.9.11-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:edcb3aeb11cb4bf13a2af3c53a15b3d612edeb6409047ea0b5d6a21a9d744b34", size = 3044641, upload-time = "2025-10-30T02:55:19.929Z" }, + { url = "https://files.pythonhosted.org/packages/12/9a/0402ded6cbd321da0c0ba7d34dc12b29b14f5764c2fc10750daa38e825fc/psycopg2_binary-2.9.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:62b6d93d7c0b61a1dd6197d208ab613eb7dcfdcca0a49c42ceb082257991de9d", size = 3347940, upload-time = "2025-10-10T11:12:26.529Z" }, + { url = "https://files.pythonhosted.org/packages/b1/d2/99b55e85832ccde77b211738ff3925a5d73ad183c0b37bcbbe5a8ff04978/psycopg2_binary-2.9.11-cp312-cp312-win_amd64.whl", hash = "sha256:b33fabeb1fde21180479b2d4667e994de7bbf0eec22832ba5d9b5e4cf65b6c6d", size = 2714147, upload-time = "2025-10-10T11:12:29.535Z" }, + { url = "https://files.pythonhosted.org/packages/ff/a8/a2709681b3ac11b0b1786def10006b8995125ba268c9a54bea6f5ae8bd3e/psycopg2_binary-2.9.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b8fb3db325435d34235b044b199e56cdf9ff41223a4b9752e8576465170bb38c", size = 3756572, upload-time = "2025-10-10T11:12:32.873Z" }, + { url = "https://files.pythonhosted.org/packages/62/e1/c2b38d256d0dafd32713e9f31982a5b028f4a3651f446be70785f484f472/psycopg2_binary-2.9.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:366df99e710a2acd90efed3764bb1e28df6c675d33a7fb40df9b7281694432ee", size = 3864529, upload-time = "2025-10-10T11:12:36.791Z" }, + { url = "https://files.pythonhosted.org/packages/11/32/b2ffe8f3853c181e88f0a157c5fb4e383102238d73c52ac6d93a5c8bffe6/psycopg2_binary-2.9.11-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8c55b385daa2f92cb64b12ec4536c66954ac53654c7f15a203578da4e78105c0", size = 4411242, upload-time = "2025-10-10T11:12:42.388Z" }, + { url = "https://files.pythonhosted.org/packages/10/04/6ca7477e6160ae258dc96f67c371157776564679aefd247b66f4661501a2/psycopg2_binary-2.9.11-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c0377174bf1dd416993d16edc15357f6eb17ac998244cca19bc67cdc0e2e5766", size = 4468258, upload-time = "2025-10-10T11:12:48.654Z" }, + { url = "https://files.pythonhosted.org/packages/3c/7e/6a1a38f86412df101435809f225d57c1a021307dd0689f7a5e7fe83588b1/psycopg2_binary-2.9.11-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5c6ff3335ce08c75afaed19e08699e8aacf95d4a260b495a4a8545244fe2ceb3", size = 4166295, upload-time = "2025-10-10T11:12:52.525Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7d/c07374c501b45f3579a9eb761cbf2604ddef3d96ad48679112c2c5aa9c25/psycopg2_binary-2.9.11-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:84011ba3109e06ac412f95399b704d3d6950e386b7994475b231cf61eec2fc1f", size = 3983133, upload-time = "2025-10-30T02:55:24.329Z" }, + { url = "https://files.pythonhosted.org/packages/82/56/993b7104cb8345ad7d4516538ccf8f0d0ac640b1ebd8c754a7b024e76878/psycopg2_binary-2.9.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ba34475ceb08cccbdd98f6b46916917ae6eeb92b5ae111df10b544c3a4621dc4", size = 3652383, upload-time = "2025-10-10T11:12:56.387Z" }, + { url = "https://files.pythonhosted.org/packages/2d/ac/eaeb6029362fd8d454a27374d84c6866c82c33bfc24587b4face5a8e43ef/psycopg2_binary-2.9.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b31e90fdd0f968c2de3b26ab014314fe814225b6c324f770952f7d38abf17e3c", size = 3298168, upload-time = "2025-10-10T11:13:00.403Z" }, + { url = "https://files.pythonhosted.org/packages/2b/39/50c3facc66bded9ada5cbc0de867499a703dc6bca6be03070b4e3b65da6c/psycopg2_binary-2.9.11-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:d526864e0f67f74937a8fce859bd56c979f5e2ec57ca7c627f5f1071ef7fee60", size = 3044712, upload-time = "2025-10-30T02:55:27.975Z" }, + { url = "https://files.pythonhosted.org/packages/9c/8e/b7de019a1f562f72ada81081a12823d3c1590bedc48d7d2559410a2763fe/psycopg2_binary-2.9.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:04195548662fa544626c8ea0f06561eb6203f1984ba5b4562764fbeb4c3d14b1", size = 3347549, upload-time = "2025-10-10T11:13:03.971Z" }, + { url = "https://files.pythonhosted.org/packages/80/2d/1bb683f64737bbb1f86c82b7359db1eb2be4e2c0c13b947f80efefa7d3e5/psycopg2_binary-2.9.11-cp313-cp313-win_amd64.whl", hash = "sha256:efff12b432179443f54e230fdf60de1f6cc726b6c832db8701227d089310e8aa", size = 2714215, upload-time = "2025-10-10T11:13:07.14Z" }, + { url = "https://files.pythonhosted.org/packages/64/12/93ef0098590cf51d9732b4f139533732565704f45bdc1ffa741b7c95fb54/psycopg2_binary-2.9.11-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:92e3b669236327083a2e33ccfa0d320dd01b9803b3e14dd986a4fc54aa00f4e1", size = 3756567, upload-time = "2025-10-10T11:13:11.885Z" }, + { url = "https://files.pythonhosted.org/packages/7c/a9/9d55c614a891288f15ca4b5209b09f0f01e3124056924e17b81b9fa054cc/psycopg2_binary-2.9.11-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e0deeb03da539fa3577fcb0b3f2554a97f7e5477c246098dbb18091a4a01c16f", size = 3864755, upload-time = "2025-10-10T11:13:17.727Z" }, + { url = "https://files.pythonhosted.org/packages/13/1e/98874ce72fd29cbde93209977b196a2edae03f8490d1bd8158e7f1daf3a0/psycopg2_binary-2.9.11-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9b52a3f9bb540a3e4ec0f6ba6d31339727b2950c9772850d6545b7eae0b9d7c5", size = 4411646, upload-time = "2025-10-10T11:13:24.432Z" }, + { url = "https://files.pythonhosted.org/packages/5a/bd/a335ce6645334fb8d758cc358810defca14a1d19ffbc8a10bd38a2328565/psycopg2_binary-2.9.11-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:db4fd476874ccfdbb630a54426964959e58da4c61c9feba73e6094d51303d7d8", size = 4468701, upload-time = "2025-10-10T11:13:29.266Z" }, + { url = "https://files.pythonhosted.org/packages/44/d6/c8b4f53f34e295e45709b7568bf9b9407a612ea30387d35eb9fa84f269b4/psycopg2_binary-2.9.11-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:47f212c1d3be608a12937cc131bd85502954398aaa1320cb4c14421a0ffccf4c", size = 4166293, upload-time = "2025-10-10T11:13:33.336Z" }, + { url = "https://files.pythonhosted.org/packages/4b/e0/f8cc36eadd1b716ab36bb290618a3292e009867e5c97ce4aba908cb99644/psycopg2_binary-2.9.11-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e35b7abae2b0adab776add56111df1735ccc71406e56203515e228a8dc07089f", size = 3983184, upload-time = "2025-10-30T02:55:32.483Z" }, + { url = "https://files.pythonhosted.org/packages/53/3e/2a8fe18a4e61cfb3417da67b6318e12691772c0696d79434184a511906dc/psycopg2_binary-2.9.11-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fcf21be3ce5f5659daefd2b3b3b6e4727b028221ddc94e6c1523425579664747", size = 3652650, upload-time = "2025-10-10T11:13:38.181Z" }, + { url = "https://files.pythonhosted.org/packages/76/36/03801461b31b29fe58d228c24388f999fe814dfc302856e0d17f97d7c54d/psycopg2_binary-2.9.11-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:9bd81e64e8de111237737b29d68039b9c813bdf520156af36d26819c9a979e5f", size = 3298663, upload-time = "2025-10-10T11:13:44.878Z" }, + { url = "https://files.pythonhosted.org/packages/97/77/21b0ea2e1a73aa5fa9222b2a6b8ba325c43c3a8d54272839c991f2345656/psycopg2_binary-2.9.11-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:32770a4d666fbdafab017086655bcddab791d7cb260a16679cc5a7338b64343b", size = 3044737, upload-time = "2025-10-30T02:55:35.69Z" }, + { url = "https://files.pythonhosted.org/packages/67/69/f36abe5f118c1dca6d3726ceae164b9356985805480731ac6712a63f24f0/psycopg2_binary-2.9.11-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c3cb3a676873d7506825221045bd70e0427c905b9c8ee8d6acd70cfcbd6e576d", size = 3347643, upload-time = "2025-10-10T11:13:53.499Z" }, + { url = "https://files.pythonhosted.org/packages/e1/36/9c0c326fe3a4227953dfb29f5d0c8ae3b8eb8c1cd2967aa569f50cb3c61f/psycopg2_binary-2.9.11-cp314-cp314-win_amd64.whl", hash = "sha256:4012c9c954dfaccd28f94e84ab9f94e12df76b4afb22331b1f0d3154893a6316", size = 2803913, upload-time = "2025-10-10T11:13:57.058Z" }, +] + [[package]] name = "register-website" version = "0.1.0" @@ -712,6 +774,8 @@ dependencies = [ { name = "flask" }, { name = "flask-mail" }, { name = "flask-sqlalchemy" }, + { name = "gunicorn" }, + { name = "psycopg2-binary" }, ] [package.metadata] @@ -721,6 +785,8 @@ requires-dist = [ { name = "flask", specifier = ">=3.1.2" }, { name = "flask-mail", specifier = ">=0.10.0" }, { name = "flask-sqlalchemy", specifier = ">=3.1.1" }, + { name = "gunicorn", specifier = ">=23.0.0" }, + { name = "psycopg2-binary", specifier = ">=2.9.11" }, ] [[package]]