From 5f2a61ea75072398b2ed6071e02e7d2f6fcc30ad Mon Sep 17 00:00:00 2001 From: Ryan Westfall Date: Sat, 14 Mar 2026 06:12:56 -0500 Subject: [PATCH] inital checkin --- .gitignore | 10 + .python-version | 1 + Dockerfile | 40 ++++ README.md | 0 docker-compose.yml | 26 ++ main.py | 6 + manage.py | 22 ++ pyproject.toml | 14 ++ raffle/__init__.py | 0 raffle/admin.py | 16 ++ raffle/apps.py | 5 + raffle/forms.py | 7 + raffle/management/__init__.py | 0 raffle/management/commands/__init__.py | 0 raffle/management/commands/seed_data.py | 53 ++++ raffle/migrations/0001_initial.py | 69 ++++++ raffle/migrations/__init__.py | 0 raffle/models.py | 25 ++ raffle/tests.py | 3 + raffle/urls.py | 16 ++ raffle/views.py | 80 +++++++ rigby_raffle/__init__.py | 0 rigby_raffle/asgi.py | 16 ++ rigby_raffle/settings.py | 131 ++++++++++ rigby_raffle/urls.py | 28 +++ rigby_raffle/wsgi.py | 16 ++ static/style.css | 279 ++++++++++++++++++++++ templates/base.html | 106 ++++++++ templates/raffle/item_confirm_delete.html | 16 ++ templates/raffle/item_detail.html | 54 +++++ templates/raffle/item_form.html | 15 ++ templates/raffle/item_list.html | 102 ++++++++ templates/registration/login.html | 13 + templates/registration/register.html | 13 + uv.lock | 219 +++++++++++++++++ 35 files changed, 1401 insertions(+) create mode 100644 .gitignore create mode 100644 .python-version create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 docker-compose.yml create mode 100644 main.py create mode 100755 manage.py create mode 100644 pyproject.toml create mode 100644 raffle/__init__.py create mode 100644 raffle/admin.py create mode 100644 raffle/apps.py create mode 100644 raffle/forms.py create mode 100644 raffle/management/__init__.py create mode 100644 raffle/management/commands/__init__.py create mode 100644 raffle/management/commands/seed_data.py create mode 100644 raffle/migrations/0001_initial.py create mode 100644 raffle/migrations/__init__.py create mode 100644 raffle/models.py create mode 100644 raffle/tests.py create mode 100644 raffle/urls.py create mode 100644 raffle/views.py create mode 100644 rigby_raffle/__init__.py create mode 100644 rigby_raffle/asgi.py create mode 100644 rigby_raffle/settings.py create mode 100644 rigby_raffle/urls.py create mode 100644 rigby_raffle/wsgi.py create mode 100644 static/style.css create mode 100644 templates/base.html create mode 100644 templates/raffle/item_confirm_delete.html create mode 100644 templates/raffle/item_detail.html create mode 100644 templates/raffle/item_form.html create mode 100644 templates/raffle/item_list.html create mode 100644 templates/registration/login.html create mode 100644 templates/registration/register.html create mode 100644 uv.lock diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..505a3b1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +# Python-generated files +__pycache__/ +*.py[oc] +build/ +dist/ +wheels/ +*.egg-info + +# Virtual environments +.venv diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..e4fba21 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.12 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..0a17634 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,40 @@ +FROM ubuntu:24.04 + +# Prevent interactive prompts during package installation +ENV DEBIAN_FRONTEND=noninteractive +ENV PYTHONUNBUFFERED=1 + +# Install system dependencies +RUN apt-get update && apt-get install -y \ + python3 \ + python3-pip \ + python3-venv \ + libpq-dev \ + libjpeg-dev \ + curl \ + && rm -rf /var/lib/apt/lists/* + +# Install uv plugin +RUN curl -LsSf https://astral.sh/uv/install.sh | sh + +ENV PATH="/root/.local/bin:$PATH" + +WORKDIR /app + +# Copy dependency files +COPY pyproject.toml uv.lock ./ + +# Install dependencies into a venv +RUN uv venv /opt/venv +ENV VIRTUAL_ENV="/opt/venv" +ENV PATH="/opt/venv/bin:$PATH" +RUN uv pip install -r pyproject.toml + +# Copy project files +COPY . . + +# Expose django port +EXPOSE 8000 + +# default command +CMD ["uv", "run", "gunicorn", "rigby_raffle.wsgi:application", "--bind", "0.0.0.0:8000"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..e58bc38 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,26 @@ +services: + db: + image: postgres:16 + environment: + POSTGRES_DB: rigby_db + POSTGRES_USER: rigby_user + POSTGRES_PASSWORD: rigby_password + volumes: + - postgres_data:/var/lib/postgresql/data + ports: + - "5433:5432" + + web: + build: . + command: uv run python manage.py runserver 0.0.0.0:8000 + volumes: + - .:/app + ports: + - "8888:8000" + environment: + - DATABASE_URL=postgres://rigby_user:rigby_password@db:5432/rigby_db + depends_on: + - db + +volumes: + postgres_data: diff --git a/main.py b/main.py new file mode 100644 index 0000000..3599b6f --- /dev/null +++ b/main.py @@ -0,0 +1,6 @@ +def main(): + print("Hello from raffle-site!") + + +if __name__ == "__main__": + main() diff --git a/manage.py b/manage.py new file mode 100755 index 0000000..ea59b26 --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'rigby_raffle.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..6522149 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,14 @@ +[project] +name = "raffle-site" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.12" +dependencies = [ + "django>=6.0.3", + "django-environ", + "dj-database-url", + "psycopg2-binary", + "pillow", + "gunicorn" +] diff --git a/raffle/__init__.py b/raffle/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/raffle/admin.py b/raffle/admin.py new file mode 100644 index 0000000..e445e17 --- /dev/null +++ b/raffle/admin.py @@ -0,0 +1,16 @@ +from django.contrib import admin +from django.contrib.auth.admin import UserAdmin +from .models import User, Item, Favorite + +class CustomUserAdmin(UserAdmin): + fieldsets = UserAdmin.fieldsets + ( + ('Custom Role', {'fields': ('is_auctioneer',)}), + ) + add_fieldsets = UserAdmin.add_fieldsets + ( + ('Custom Role', {'fields': ('is_auctioneer',)}), + ) + list_display = ('username', 'email', 'is_staff', 'is_auctioneer') + +admin.site.register(User, CustomUserAdmin) +admin.site.register(Item) +admin.site.register(Favorite) diff --git a/raffle/apps.py b/raffle/apps.py new file mode 100644 index 0000000..96a67ff --- /dev/null +++ b/raffle/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class RaffleConfig(AppConfig): + name = 'raffle' diff --git a/raffle/forms.py b/raffle/forms.py new file mode 100644 index 0000000..6ff3ab9 --- /dev/null +++ b/raffle/forms.py @@ -0,0 +1,7 @@ +from django.contrib.auth.forms import UserCreationForm +from .models import User + +class CustomUserCreationForm(UserCreationForm): + class Meta(UserCreationForm.Meta): + model = User + fields = UserCreationForm.Meta.fields + ('email',) diff --git a/raffle/management/__init__.py b/raffle/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/raffle/management/commands/__init__.py b/raffle/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/raffle/management/commands/seed_data.py b/raffle/management/commands/seed_data.py new file mode 100644 index 0000000..d814149 --- /dev/null +++ b/raffle/management/commands/seed_data.py @@ -0,0 +1,53 @@ +import random +from django.core.management.base import BaseCommand +from raffle.models import User, Item, Favorite + +class Command(BaseCommand): + help = 'Pre-populates the database with initial users and items for RigbyRaffle' + + def handle(self, *args, **kwargs): + self.stdout.write('Seeding database...') + + # 1. Create Auctioneer + auctioneer, created = User.objects.get_or_create(username='admin', defaults={'email': 'admin@rigbyraffle.com'}) + if created: + auctioneer.set_password('admin') + auctioneer.is_staff = True + auctioneer.is_superuser = True + auctioneer.is_auctioneer = True + auctioneer.save() + self.stdout.write(self.style.SUCCESS('Created Auctioneer (username: admin, password: admin)')) + + # 2. Create Visitors + visitors = [] + for i in range(1, 4): + visitor, created = User.objects.get_or_create(username=f'visitor{i}', defaults={'email': f'visitor{i}@example.com'}) + if created: + visitor.set_password('password') + visitor.save() + visitors.append(visitor) + self.stdout.write(self.style.SUCCESS(f'Created {len(visitors)} Visitors (password: password)')) + + # 3. Create Items + items_data = [ + {'item_number': '101', 'title': 'Vintage Leather Jacket', 'description': 'A beautiful, timeless vintage leather jacket in superb condition.'}, + {'item_number': '102', 'title': 'Handcrafted Wooden Coffee Table', 'description': 'Solid oak handcrafted coffee table with a polished finish.'}, + {'item_number': '103', 'title': 'Professional Espresso Machine', 'description': 'High-end barista-grade espresso machine for coffee lovers.'}, + {'item_number': '104', 'title': 'Set of 4 Rare Vinyls', 'description': 'A curated collection of rare classic rock vinyl records.'}, + {'item_number': '105', 'title': 'Mountain Bike', 'description': '21-speed professional mountain bike, barely used.'}, + ] + + items = [] + for data in items_data: + item, created = Item.objects.get_or_create(item_number=data['item_number'], defaults=data) + items.append(item) + self.stdout.write(self.style.SUCCESS(f'Created {len(items)} Items')) + + # 4. Create Random Favorites + for visitor in visitors: + # Each visitor favorites 2 random items + fav_items = random.sample(items, 2) + for item in fav_items: + Favorite.objects.get_or_create(user=visitor, item=item) + + self.stdout.write(self.style.SUCCESS('Database successfully pre-populated!')) diff --git a/raffle/migrations/0001_initial.py b/raffle/migrations/0001_initial.py new file mode 100644 index 0000000..ee5b95a --- /dev/null +++ b/raffle/migrations/0001_initial.py @@ -0,0 +1,69 @@ +# Generated by Django 6.0.3 on 2026-03-12 18:10 + +import django.contrib.auth.models +import django.contrib.auth.validators +import django.db.models.deletion +import django.utils.timezone +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ] + + operations = [ + migrations.CreateModel( + name='Item', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('item_number', models.CharField(max_length=50, unique=True)), + ('title', models.CharField(max_length=200)), + ('description', models.TextField()), + ('picture', models.ImageField(blank=True, null=True, upload_to='item_pictures/')), + ], + ), + migrations.CreateModel( + name='User', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), + ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), + ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), + ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), + ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), + ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), + ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), + ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), + ('is_auctioneer', models.BooleanField(default=False)), + ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')), + ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')), + ], + options={ + 'verbose_name': 'user', + 'verbose_name_plural': 'users', + 'abstract': False, + }, + managers=[ + ('objects', django.contrib.auth.models.UserManager()), + ], + ), + migrations.CreateModel( + name='Favorite', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='favorites', to=settings.AUTH_USER_MODEL)), + ('item', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='favorited_by', to='raffle.item')), + ], + options={ + 'unique_together': {('user', 'item')}, + }, + ), + ] diff --git a/raffle/migrations/__init__.py b/raffle/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/raffle/models.py b/raffle/models.py new file mode 100644 index 0000000..37b5797 --- /dev/null +++ b/raffle/models.py @@ -0,0 +1,25 @@ +from django.contrib.auth.models import AbstractUser +from django.db import models + +class User(AbstractUser): + is_auctioneer = models.BooleanField(default=False) + +class Item(models.Model): + item_number = models.CharField(max_length=50, unique=True) + title = models.CharField(max_length=200) + description = models.TextField() + picture = models.ImageField(upload_to='item_pictures/', blank=True, null=True) + + def __str__(self): + return f"{self.item_number} - {self.title}" + +class Favorite(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='favorites') + item = models.ForeignKey(Item, on_delete=models.CASCADE, related_name='favorited_by') + created_at = models.DateTimeField(auto_now_add=True) + + class Meta: + unique_together = ('user', 'item') + + def __str__(self): + return f"{self.user.username} favorited {self.item.title}" diff --git a/raffle/tests.py b/raffle/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/raffle/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/raffle/urls.py b/raffle/urls.py new file mode 100644 index 0000000..0250c0d --- /dev/null +++ b/raffle/urls.py @@ -0,0 +1,16 @@ +from django.urls import path +from django.contrib.auth import views as auth_views +from . import views + +urlpatterns = [ + path('login/', auth_views.LoginView.as_view(template_name='registration/login.html'), name='login'), + path('logout/', auth_views.LogoutView.as_view(), name='logout'), + path('register/', views.RegisterView.as_view(), name='register'), + + path('', views.ItemListView.as_view(), name='item_list'), + path('item/new/', views.ItemCreateView.as_view(), name='item_create'), + path('item//', views.ItemDetailView.as_view(), name='item_detail'), + path('item//edit/', views.ItemUpdateView.as_view(), name='item_update'), + path('item//delete/', views.ItemDeleteView.as_view(), name='item_delete'), + path('item//favorite/', views.ToggleFavoriteView.as_view(), name='toggle_favorite'), +] diff --git a/raffle/views.py b/raffle/views.py new file mode 100644 index 0000000..eb0e836 --- /dev/null +++ b/raffle/views.py @@ -0,0 +1,80 @@ +from django.shortcuts import render, redirect, get_object_or_404 +from django.contrib.auth import login +from django.contrib.auth.decorators import login_required +from django.views.generic import CreateView, ListView, DetailView, UpdateView, DeleteView, View +from django.urls import reverse_lazy +from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin +from django.http import JsonResponse +from .models import Item, Favorite +from .forms import CustomUserCreationForm + +class RegisterView(CreateView): + form_class = CustomUserCreationForm + template_name = 'registration/register.html' + success_url = reverse_lazy('item_list') + + def form_valid(self, form): + response = super().form_valid(form) + login(self.request, self.object) + return response + +class AuctioneerRequiredMixin(UserPassesTestMixin): + def test_func(self): + return self.request.user.is_authenticated and self.request.user.is_auctioneer + +class ItemListView(LoginRequiredMixin, ListView): + model = Item + template_name = 'raffle/item_list.html' + context_object_name = 'items' + + def get_queryset(self): + qs = super().get_queryset() + favorites_only = self.request.GET.get('favorites') + if favorites_only == '1': + return qs.filter(favorited_by__user=self.request.user) + return qs + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + user_favorites = Favorite.objects.filter(user=self.request.user).values_list('item_id', flat=True) + context['user_favorites'] = list(user_favorites) + return context + +class ItemCreateView(AuctioneerRequiredMixin, CreateView): + model = Item + fields = ['item_number', 'title', 'description', 'picture'] + template_name = 'raffle/item_form.html' + success_url = reverse_lazy('item_list') + +class ItemUpdateView(AuctioneerRequiredMixin, UpdateView): + model = Item + fields = ['item_number', 'title', 'description', 'picture'] + template_name = 'raffle/item_form.html' + success_url = reverse_lazy('item_list') + +class ItemDeleteView(AuctioneerRequiredMixin, DeleteView): + model = Item + template_name = 'raffle/item_confirm_delete.html' + success_url = reverse_lazy('item_list') + +class ItemDetailView(AuctioneerRequiredMixin, DetailView): + model = Item + template_name = 'raffle/item_detail.html' + context_object_name = 'item' + +class ToggleFavoriteView(LoginRequiredMixin, View): + def post(self, request, pk): + try: + item = Item.objects.get(pk=pk) + favorite, created = Favorite.objects.get_or_create(user=request.user, item=item) + if not created: + favorite.delete() + is_favorite = False + else: + is_favorite = True + + # Count how many favorited + count = item.favorited_by.count() + return JsonResponse({'status': 'success', 'is_favorite': is_favorite, 'count': count}) + except Item.DoesNotExist: + return JsonResponse({'status': 'error', 'message': 'Item not found'}, status=404) diff --git a/rigby_raffle/__init__.py b/rigby_raffle/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rigby_raffle/asgi.py b/rigby_raffle/asgi.py new file mode 100644 index 0000000..29788a0 --- /dev/null +++ b/rigby_raffle/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for rigby_raffle project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/6.0/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'rigby_raffle.settings') + +application = get_asgi_application() diff --git a/rigby_raffle/settings.py b/rigby_raffle/settings.py new file mode 100644 index 0000000..33b4858 --- /dev/null +++ b/rigby_raffle/settings.py @@ -0,0 +1,131 @@ +""" +Django settings for rigby_raffle project. + +Generated by 'django-admin startproject' using Django 6.0.3. + +For more information on this file, see +https://docs.djangoproject.com/en/6.0/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/6.0/ref/settings/ +""" + +import os +import dj_database_url +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-+y^v_02)x=4i9la8#1c158#wf9zujapy46javmg-6^w^kl@v0w' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = ['*'] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'raffle', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'rigby_raffle.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [BASE_DIR / 'templates'], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'rigby_raffle.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/6.0/ref/settings/#databases + +DATABASES = { + 'default': dj_database_url.config( + default=os.environ.get('DATABASE_URL', f'sqlite:///{BASE_DIR}/db.sqlite3'), + conn_max_age=600, + conn_health_checks=True, + ) +} + + +# Password validation +# https://docs.djangoproject.com/en/6.0/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/6.0/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/6.0/howto/static-files/ + +STATIC_URL = 'static/' +STATIC_ROOT = BASE_DIR / 'staticfiles' +STATICFILES_DIRS = [BASE_DIR / 'static'] + +MEDIA_URL = 'media/' +MEDIA_ROOT = BASE_DIR / 'media' + +AUTH_USER_MODEL = 'raffle.User' +LOGIN_URL = 'login' +LOGIN_REDIRECT_URL = 'item_list' +LOGOUT_REDIRECT_URL = 'login' diff --git a/rigby_raffle/urls.py b/rigby_raffle/urls.py new file mode 100644 index 0000000..7ff91bf --- /dev/null +++ b/rigby_raffle/urls.py @@ -0,0 +1,28 @@ +""" +URL configuration for rigby_raffle project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/6.0/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path, include +from django.conf import settings +from django.conf.urls.static import static + +urlpatterns = [ + path('admin/', admin.site.urls), + path('', include('raffle.urls')), +] + +if settings.DEBUG: + urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/rigby_raffle/wsgi.py b/rigby_raffle/wsgi.py new file mode 100644 index 0000000..79316b5 --- /dev/null +++ b/rigby_raffle/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for rigby_raffle project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/6.0/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'rigby_raffle.settings') + +application = get_wsgi_application() diff --git a/static/style.css b/static/style.css new file mode 100644 index 0000000..2f02070 --- /dev/null +++ b/static/style.css @@ -0,0 +1,279 @@ +/* Light Mode (Default) */ +:root { + --primary: #6366f1; + --primary-hover: #4f46e5; + --secondary: rgba(0, 0, 0, 0.05); + --bg-color: #f1f5f9; + --text-main: #334155; + --text-muted: #64748b; + --glass-bg: rgba(255, 255, 255, 0.8); + --glass-border: rgba(0, 0, 0, 0.1); +} + +/* Dark Mode */ +[data-theme="dark"] { + --primary: #818cf8; + --primary-hover: #6366f1; + --secondary: rgba(255, 255, 255, 0.1); + --bg-color: #0f172a; + --text-main: #f8fafc; + --text-muted: #94a3b8; + --glass-bg: rgba(30, 41, 59, 0.7); + --glass-border: rgba(255, 255, 255, 0.08); +} + +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +body { + font-family: 'Inter', sans-serif; + background-color: var(--bg-color); + color: var(--text-main); + min-height: 100vh; + overflow-x: hidden; + position: relative; + line-height: 1.5; +} + +.blob-bg { + position: fixed; + top: -50%; + left: -50%; + width: 200%; + height: 200%; + background: radial-gradient(circle at 50% 50%, rgba(99, 102, 241, 0.15), transparent 60%), + radial-gradient(circle at 80% 20%, rgba(168, 85, 247, 0.15), transparent 50%); + z-index: -1; + pointer-events: none; +} + +.glass-nav { + display: flex; + justify-content: space-between; + align-items: center; + padding: 1.25rem 5%; + background: var(--glass-bg); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + border-bottom: 1px solid var(--glass-border); + position: sticky; + top: 0; + z-index: 100; +} + +.logo { + font-size: 1.5rem; + font-weight: 800; + color: var(--text-main); + text-decoration: none; + letter-spacing: -0.5px; +} + +.logo span { + color: var(--primary); +} + +.nav-links { + display: flex; + align-items: center; + gap: 1.5rem; +} + +.welcome-text { + color: var(--text-muted); + font-size: 0.95rem; +} + +.btn-primary, +.btn-primary-small, +.btn-danger, +.btn-secondary { + background: var(--primary); + color: white; + border: none; + border-radius: 8px; + font-weight: 600; + cursor: pointer; + transition: all 0.2s ease; + text-decoration: none; + display: inline-flex; + align-items: center; + justify-content: center; +} + +.btn-primary:hover, +.btn-primary-small:hover { + background: var(--primary-hover); + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3); +} + +.btn-primary { + padding: 0.875rem 1.5rem; + width: 100%; + font-size: 1rem; + margin-top: 1rem; +} + +.btn-primary-small { + padding: 0.5rem 1rem; + font-size: 0.9rem; +} + +.btn-secondary { + background: var(--secondary); + margin-top: 1rem; + padding: 0.875rem 1.5rem; + width: 100%; +} + +.btn-secondary:hover { + background: rgba(255, 255, 255, 0.2); +} + +.btn-danger { + background: #ef4444; +} + +.btn-danger:hover { + background: #dc2626; + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(239, 68, 68, 0.3); +} + +.btn-secondary-small { + background: transparent; + color: var(--text-main); + border: 1px solid var(--glass-border); + border-radius: 8px; + padding: 0.5rem 1rem; + font-size: 0.9rem; + cursor: pointer; + text-decoration: none; + transition: all 0.2s; +} + +.btn-secondary-small:hover { + background: var(--secondary); + border-color: rgba(255, 255, 255, 0.2); +} + +.container { + max-width: 1200px; + margin: 3rem auto; + padding: 0 5%; +} + +.glassmorphism { + background: var(--glass-bg); + backdrop-filter: blur(16px); + -webkit-backdrop-filter: blur(16px); + border: 1px solid var(--glass-border); + border-radius: 16px; + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2); +} + +.auth-card { + max-width: 420px; + margin: 4rem auto; + padding: 2.5rem; +} + +.auth-card h2 { + font-size: 1.75rem; + margin-bottom: 0.5rem; + font-weight: 800; +} + +.subtitle { + color: var(--text-muted); + margin-bottom: 2rem; + font-size: 0.95rem; +} + +.auth-form p { + margin-bottom: 1.25rem; + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.auth-form label { + font-size: 0.9rem; + color: var(--text-muted); + font-weight: 600; +} + +.auth-form input, +.auth-form textarea { + width: 100%; + padding: 0.75rem 1rem; + background: var(--bg-color); + border: 1px solid var(--glass-border); + border-radius: 8px; + color: var(--text-main); + font-family: inherit; + transition: all 0.2s; +} + +.auth-form input:focus, +.auth-form textarea:focus { + outline: none; + border-color: var(--primary); + box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2); +} + +.auth-form ul.errorlist { + color: #ef4444; + list-style: none; + font-size: 0.85rem; + margin-top: 0.25rem; +} + +.auth-footer { + margin-top: 1.5rem; + text-align: center; + font-size: 0.9rem; + color: var(--text-muted); +} + +.auth-footer a { + color: var(--primary); + text-decoration: none; + font-weight: 600; +} + +.auth-footer a:hover { + text-decoration: underline; +} + +/* Base layouts for later use */ +.item-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + gap: 2rem; +} + +.item-card { + padding: 1.5rem; + display: flex; + flex-direction: column; + gap: 1rem; + transition: transform 0.3s ease, box-shadow 0.3s ease; +} + +.item-card:hover { + transform: translateY(-5px); + box-shadow: 0 25px 50px rgba(0, 0, 0, 0.3); +} + +.item-img { + width: 100%; + height: 200px; + object-fit: cover; + border-radius: 8px; + background: var(--bg-color); +} \ No newline at end of file diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..1661387 --- /dev/null +++ b/templates/base.html @@ -0,0 +1,106 @@ + + + + + + + RigbyRaffle + + {% load static %} + + + + + +
+ +
+ {% block content %} + {% endblock %} +
+ + + + + \ No newline at end of file diff --git a/templates/raffle/item_confirm_delete.html b/templates/raffle/item_confirm_delete.html new file mode 100644 index 0000000..c1c0292 --- /dev/null +++ b/templates/raffle/item_confirm_delete.html @@ -0,0 +1,16 @@ +{% extends 'base.html' %} +{% block content %} +
+

Delete Item

+

Are you sure you want to delete "{{ object.title }}"?

+ +
+ {% csrf_token %} +
+ + Cancel +
+
+
+{% endblock %} \ No newline at end of file diff --git a/templates/raffle/item_detail.html b/templates/raffle/item_detail.html new file mode 100644 index 0000000..d100863 --- /dev/null +++ b/templates/raffle/item_detail.html @@ -0,0 +1,54 @@ +{% extends 'base.html' %} +{% block content %} +
+
+
+ #{{ item.item_number }} +

{{ item.title }}

+
+
+ Edit + Delete +
+
+ +
+
+ {% if item.picture %} + {{ item.title }} + {% else %} +
+ No Image Available
+ {% endif %} + +

{{ item.description|linebreaksbr + }}

+
+ +
+
+

Favorite Activity

+

Total Favorites: {{ item.favorited_by.count }}

+ + {% if item.favorited_by.count > 0 %} +
    + {% for fav in item.favorited_by.all %} +
  • +
    + {{ fav.user.username }} + {{ + fav.created_at|date:"M d, Y" }} +
  • + {% endfor %} +
+ {% else %} +

No one has favorited this item yet.

+ {% endif %} +
+
+
+
+{% endblock %} \ No newline at end of file diff --git a/templates/raffle/item_form.html b/templates/raffle/item_form.html new file mode 100644 index 0000000..017ce11 --- /dev/null +++ b/templates/raffle/item_form.html @@ -0,0 +1,15 @@ +{% extends 'base.html' %} +{% block content %} +
+

{% if object %}Edit Item{% else %}Add New Item{% endif %}

+
+ {% csrf_token %} + {{ form.as_p }} + +
+ + Cancel +
+
+
+{% endblock %} \ No newline at end of file diff --git a/templates/raffle/item_list.html b/templates/raffle/item_list.html new file mode 100644 index 0000000..0212476 --- /dev/null +++ b/templates/raffle/item_list.html @@ -0,0 +1,102 @@ +{% extends 'base.html' %} +{% block content %} +
+

Raffle Items

+ +
+ +
+ {% for item in items %} +
+ {% if item.picture %} + {{ item.title }} + {% else %} +
+ No Image
+ {% endif %} + +
+ #{{ + item.item_number }} +

{{ item.title }}

+

{{ item.description|linebreaksbr + }}

+
+ +
+
+ {% if user.is_auctioneer %} + View + Edit + {% endif %} +
+ + +
+
+ {% empty %} +
+

No items found.

+
+ {% endfor %} +
+ + +{% endblock %} \ No newline at end of file diff --git a/templates/registration/login.html b/templates/registration/login.html new file mode 100644 index 0000000..2a2a2bc --- /dev/null +++ b/templates/registration/login.html @@ -0,0 +1,13 @@ +{% extends 'base.html' %} +{% block content %} +
+

Welcome Back

+

Enter your details to access RigbyRaffle

+
+ {% csrf_token %} + {{ form.as_p }} + +
+ +
+{% endblock %} \ No newline at end of file diff --git a/templates/registration/register.html b/templates/registration/register.html new file mode 100644 index 0000000..04ad3d8 --- /dev/null +++ b/templates/registration/register.html @@ -0,0 +1,13 @@ +{% extends 'base.html' %} +{% block content %} +
+

Join the Raffle

+

Create an account to browse and favorite items

+
+ {% csrf_token %} + {{ form.as_p }} + +
+ +
+{% endblock %} \ No newline at end of file diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..c3e466e --- /dev/null +++ b/uv.lock @@ -0,0 +1,219 @@ +version = 1 +revision = 3 +requires-python = ">=3.12" + +[[package]] +name = "asgiref" +version = "3.11.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/63/40/f03da1264ae8f7cfdbf9146542e5e7e8100a4c66ab48e791df9a03d3f6c0/asgiref-3.11.1.tar.gz", hash = "sha256:5f184dc43b7e763efe848065441eac62229c9f7b0475f41f80e207a114eda4ce", size = 38550, upload-time = "2026-02-03T13:30:14.33Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/0a/a72d10ed65068e115044937873362e6e32fab1b7dce0046aeb224682c989/asgiref-3.11.1-py3-none-any.whl", hash = "sha256:e8667a091e69529631969fd45dc268fa79b99c92c5fcdda727757e52146ec133", size = 24345, upload-time = "2026-02-03T13:30:13.039Z" }, +] + +[[package]] +name = "dj-database-url" +version = "3.1.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/03/f6/00b625e9d371b980aa261011d0dc906a16444cb688f94215e0dc86996eb5/dj_database_url-3.1.2.tar.gz", hash = "sha256:63c20e4bbaa51690dfd4c8d189521f6bf6bc9da9fcdb23d95d2ee8ee87f9ec62", size = 11490, upload-time = "2026-02-19T15:30:23.638Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cf/a9/57c66006373381f1d3e5bd94216f1d371228a89f443d3030e010f73dd198/dj_database_url-3.1.2-py3-none-any.whl", hash = "sha256:544e015fee3efa5127a1eb1cca465f4ace578265b3671fe61d0ed7dbafb5ec8a", size = 8953, upload-time = "2026-02-19T15:30:39.37Z" }, +] + +[[package]] +name = "django" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asgiref" }, + { name = "sqlparse" }, + { name = "tzdata", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/80/e1/894115c6bd70e2c8b66b0c40a3c367d83a5a48c034a4d904d31b62f7c53a/django-6.0.3.tar.gz", hash = "sha256:90be765ee756af8a6cbd6693e56452404b5ad15294f4d5e40c0a55a0f4870fe1", size = 10872701, upload-time = "2026-03-03T13:55:15.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/72/b1/23f2556967c45e34d3d3cf032eb1bd3ef925ee458667fb99052a0b3ea3a6/django-6.0.3-py3-none-any.whl", hash = "sha256:2e5974441491ddb34c3f13d5e7a9f97b07ba03bf70234c0a9c68b79bbb235bc3", size = 8358527, upload-time = "2026-03-03T13:55:10.552Z" }, +] + +[[package]] +name = "django-environ" +version = "0.13.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/3c/60983e6ec9b24a8d8588eecebfd21123cba980bce0a905807a27692f0860/django_environ-0.13.0.tar.gz", hash = "sha256:6c401e4c219442c2c4588c2116d5292b5484a6f69163ed09cd41f3943bfb645f", size = 63529, upload-time = "2026-02-18T01:08:08.791Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c4/00/3767393ece946084e1c6830a33ffb8e39d68642e27ad5ac7d4c8bd5de866/django_environ-0.13.0-py3-none-any.whl", hash = "sha256:37799d14cd78222c6fd8298e48bfe17965ff8e586091ad66a463e52e0e7b799e", size = 20682, upload-time = "2026-02-18T01:08:07.359Z" }, +] + +[[package]] +name = "gunicorn" +version = "25.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/13/ef67f59f6a7896fdc2c1d62b5665c5219d6b0a9a1784938eb9a28e55e128/gunicorn-25.1.0.tar.gz", hash = "sha256:1426611d959fa77e7de89f8c0f32eed6aa03ee735f98c01efba3e281b1c47616", size = 594377, upload-time = "2026-02-13T11:09:58.989Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/73/4ad5b1f6a2e21cf1e85afdaad2b7b1a933985e2f5d679147a1953aaa192c/gunicorn-25.1.0-py3-none-any.whl", hash = "sha256:d0b1236ccf27f72cfe14bce7caadf467186f19e865094ca84221424e839b8b8b", size = 197067, upload-time = "2026-02-13T11:09:57.146Z" }, +] + +[[package]] +name = "packaging" +version = "26.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" }, +] + +[[package]] +name = "pillow" +version = "12.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1f/42/5c74462b4fd957fcd7b13b04fb3205ff8349236ea74c7c375766d6c82288/pillow-12.1.1.tar.gz", hash = "sha256:9ad8fa5937ab05218e2b6a4cff30295ad35afd2f83ac592e68c0d871bb0fdbc4", size = 46980264, upload-time = "2026-02-11T04:23:07.146Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/d3/8df65da0d4df36b094351dce696f2989bec731d4f10e743b1c5f4da4d3bf/pillow-12.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ab323b787d6e18b3d91a72fc99b1a2c28651e4358749842b8f8dfacd28ef2052", size = 5262803, upload-time = "2026-02-11T04:20:47.653Z" }, + { url = "https://files.pythonhosted.org/packages/d6/71/5026395b290ff404b836e636f51d7297e6c83beceaa87c592718747e670f/pillow-12.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:adebb5bee0f0af4909c30db0d890c773d1a92ffe83da908e2e9e720f8edf3984", size = 4657601, upload-time = "2026-02-11T04:20:49.328Z" }, + { url = "https://files.pythonhosted.org/packages/b1/2e/1001613d941c67442f745aff0f7cc66dd8df9a9c084eb497e6a543ee6f7e/pillow-12.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bb66b7cc26f50977108790e2456b7921e773f23db5630261102233eb355a3b79", size = 6234995, upload-time = "2026-02-11T04:20:51.032Z" }, + { url = "https://files.pythonhosted.org/packages/07/26/246ab11455b2549b9233dbd44d358d033a2f780fa9007b61a913c5b2d24e/pillow-12.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aee2810642b2898bb187ced9b349e95d2a7272930796e022efaf12e99dccd293", size = 8045012, upload-time = "2026-02-11T04:20:52.882Z" }, + { url = "https://files.pythonhosted.org/packages/b2/8b/07587069c27be7535ac1fe33874e32de118fbd34e2a73b7f83436a88368c/pillow-12.1.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a0b1cd6232e2b618adcc54d9882e4e662a089d5768cd188f7c245b4c8c44a397", size = 6349638, upload-time = "2026-02-11T04:20:54.444Z" }, + { url = "https://files.pythonhosted.org/packages/ff/79/6df7b2ee763d619cda2fb4fea498e5f79d984dae304d45a8999b80d6cf5c/pillow-12.1.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7aac39bcf8d4770d089588a2e1dd111cbaa42df5a94be3114222057d68336bd0", size = 7041540, upload-time = "2026-02-11T04:20:55.97Z" }, + { url = "https://files.pythonhosted.org/packages/2c/5e/2ba19e7e7236d7529f4d873bdaf317a318896bac289abebd4bb00ef247f0/pillow-12.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ab174cd7d29a62dd139c44bf74b698039328f45cb03b4596c43473a46656b2f3", size = 6462613, upload-time = "2026-02-11T04:20:57.542Z" }, + { url = "https://files.pythonhosted.org/packages/03/03/31216ec124bb5c3dacd74ce8efff4cc7f52643653bad4825f8f08c697743/pillow-12.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:339ffdcb7cbeaa08221cd401d517d4b1fe7a9ed5d400e4a8039719238620ca35", size = 7166745, upload-time = "2026-02-11T04:20:59.196Z" }, + { url = "https://files.pythonhosted.org/packages/1f/e7/7c4552d80052337eb28653b617eafdef39adfb137c49dd7e831b8dc13bc5/pillow-12.1.1-cp312-cp312-win32.whl", hash = "sha256:5d1f9575a12bed9e9eedd9a4972834b08c97a352bd17955ccdebfeca5913fa0a", size = 6328823, upload-time = "2026-02-11T04:21:01.385Z" }, + { url = "https://files.pythonhosted.org/packages/3d/17/688626d192d7261bbbf98846fc98995726bddc2c945344b65bec3a29d731/pillow-12.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:21329ec8c96c6e979cd0dfd29406c40c1d52521a90544463057d2aaa937d66a6", size = 7033367, upload-time = "2026-02-11T04:21:03.536Z" }, + { url = "https://files.pythonhosted.org/packages/ed/fe/a0ef1f73f939b0eca03ee2c108d0043a87468664770612602c63266a43c4/pillow-12.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:af9a332e572978f0218686636610555ae3defd1633597be015ed50289a03c523", size = 2453811, upload-time = "2026-02-11T04:21:05.116Z" }, + { url = "https://files.pythonhosted.org/packages/d5/11/6db24d4bd7685583caeae54b7009584e38da3c3d4488ed4cd25b439de486/pillow-12.1.1-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:d242e8ac078781f1de88bf823d70c1a9b3c7950a44cdf4b7c012e22ccbcd8e4e", size = 4062689, upload-time = "2026-02-11T04:21:06.804Z" }, + { url = "https://files.pythonhosted.org/packages/33/c0/ce6d3b1fe190f0021203e0d9b5b99e57843e345f15f9ef22fcd43842fd21/pillow-12.1.1-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:02f84dfad02693676692746df05b89cf25597560db2857363a208e393429f5e9", size = 4138535, upload-time = "2026-02-11T04:21:08.452Z" }, + { url = "https://files.pythonhosted.org/packages/a0/c6/d5eb6a4fb32a3f9c21a8c7613ec706534ea1cf9f4b3663e99f0d83f6fca8/pillow-12.1.1-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:e65498daf4b583091ccbb2556c7000abf0f3349fcd57ef7adc9a84a394ed29f6", size = 3601364, upload-time = "2026-02-11T04:21:10.194Z" }, + { url = "https://files.pythonhosted.org/packages/14/a1/16c4b823838ba4c9c52c0e6bbda903a3fe5a1bdbf1b8eb4fff7156f3e318/pillow-12.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c6db3b84c87d48d0088943bf33440e0c42370b99b1c2a7989216f7b42eede60", size = 5262561, upload-time = "2026-02-11T04:21:11.742Z" }, + { url = "https://files.pythonhosted.org/packages/bb/ad/ad9dc98ff24f485008aa5cdedaf1a219876f6f6c42a4626c08bc4e80b120/pillow-12.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8b7e5304e34942bf62e15184219a7b5ad4ff7f3bb5cca4d984f37df1a0e1aee2", size = 4657460, upload-time = "2026-02-11T04:21:13.786Z" }, + { url = "https://files.pythonhosted.org/packages/9e/1b/f1a4ea9a895b5732152789326202a82464d5254759fbacae4deea3069334/pillow-12.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:18e5bddd742a44b7e6b1e773ab5db102bd7a94c32555ba656e76d319d19c3850", size = 6232698, upload-time = "2026-02-11T04:21:15.949Z" }, + { url = "https://files.pythonhosted.org/packages/95/f4/86f51b8745070daf21fd2e5b1fe0eb35d4db9ca26e6d58366562fb56a743/pillow-12.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc44ef1f3de4f45b50ccf9136999d71abb99dca7706bc75d222ed350b9fd2289", size = 8041706, upload-time = "2026-02-11T04:21:17.723Z" }, + { url = "https://files.pythonhosted.org/packages/29/9b/d6ecd956bb1266dd1045e995cce9b8d77759e740953a1c9aad9502a0461e/pillow-12.1.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5a8eb7ed8d4198bccbd07058416eeec51686b498e784eda166395a23eb99138e", size = 6346621, upload-time = "2026-02-11T04:21:19.547Z" }, + { url = "https://files.pythonhosted.org/packages/71/24/538bff45bde96535d7d998c6fed1a751c75ac7c53c37c90dc2601b243893/pillow-12.1.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:47b94983da0c642de92ced1702c5b6c292a84bd3a8e1d1702ff923f183594717", size = 7038069, upload-time = "2026-02-11T04:21:21.378Z" }, + { url = "https://files.pythonhosted.org/packages/94/0e/58cb1a6bc48f746bc4cb3adb8cabff73e2742c92b3bf7a220b7cf69b9177/pillow-12.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:518a48c2aab7ce596d3bf79d0e275661b846e86e4d0e7dec34712c30fe07f02a", size = 6460040, upload-time = "2026-02-11T04:21:23.148Z" }, + { url = "https://files.pythonhosted.org/packages/6c/57/9045cb3ff11eeb6c1adce3b2d60d7d299d7b273a2e6c8381a524abfdc474/pillow-12.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a550ae29b95c6dc13cf69e2c9dc5747f814c54eeb2e32d683e5e93af56caa029", size = 7164523, upload-time = "2026-02-11T04:21:25.01Z" }, + { url = "https://files.pythonhosted.org/packages/73/f2/9be9cb99f2175f0d4dbadd6616ce1bf068ee54a28277ea1bf1fbf729c250/pillow-12.1.1-cp313-cp313-win32.whl", hash = "sha256:a003d7422449f6d1e3a34e3dd4110c22148336918ddbfc6a32581cd54b2e0b2b", size = 6332552, upload-time = "2026-02-11T04:21:27.238Z" }, + { url = "https://files.pythonhosted.org/packages/3f/eb/b0834ad8b583d7d9d42b80becff092082a1c3c156bb582590fcc973f1c7c/pillow-12.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:344cf1e3dab3be4b1fa08e449323d98a2a3f819ad20f4b22e77a0ede31f0faa1", size = 7040108, upload-time = "2026-02-11T04:21:29.462Z" }, + { url = "https://files.pythonhosted.org/packages/d5/7d/fc09634e2aabdd0feabaff4a32f4a7d97789223e7c2042fd805ea4b4d2c2/pillow-12.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:5c0dd1636633e7e6a0afe7bf6a51a14992b7f8e60de5789018ebbdfae55b040a", size = 2453712, upload-time = "2026-02-11T04:21:31.072Z" }, + { url = "https://files.pythonhosted.org/packages/19/2a/b9d62794fc8a0dd14c1943df68347badbd5511103e0d04c035ffe5cf2255/pillow-12.1.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0330d233c1a0ead844fc097a7d16c0abff4c12e856c0b325f231820fee1f39da", size = 5264880, upload-time = "2026-02-11T04:21:32.865Z" }, + { url = "https://files.pythonhosted.org/packages/26/9d/e03d857d1347fa5ed9247e123fcd2a97b6220e15e9cb73ca0a8d91702c6e/pillow-12.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5dae5f21afb91322f2ff791895ddd8889e5e947ff59f71b46041c8ce6db790bc", size = 4660616, upload-time = "2026-02-11T04:21:34.97Z" }, + { url = "https://files.pythonhosted.org/packages/f7/ec/8a6d22afd02570d30954e043f09c32772bfe143ba9285e2fdb11284952cd/pillow-12.1.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2e0c664be47252947d870ac0d327fea7e63985a08794758aa8af5b6cb6ec0c9c", size = 6269008, upload-time = "2026-02-11T04:21:36.623Z" }, + { url = "https://files.pythonhosted.org/packages/3d/1d/6d875422c9f28a4a361f495a5f68d9de4a66941dc2c619103ca335fa6446/pillow-12.1.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:691ab2ac363b8217f7d31b3497108fb1f50faab2f75dfb03284ec2f217e87bf8", size = 8073226, upload-time = "2026-02-11T04:21:38.585Z" }, + { url = "https://files.pythonhosted.org/packages/a1/cd/134b0b6ee5eda6dc09e25e24b40fdafe11a520bc725c1d0bbaa5e00bf95b/pillow-12.1.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e9e8064fb1cc019296958595f6db671fba95209e3ceb0c4734c9baf97de04b20", size = 6380136, upload-time = "2026-02-11T04:21:40.562Z" }, + { url = "https://files.pythonhosted.org/packages/7a/a9/7628f013f18f001c1b98d8fffe3452f306a70dc6aba7d931019e0492f45e/pillow-12.1.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:472a8d7ded663e6162dafdf20015c486a7009483ca671cece7a9279b512fcb13", size = 7067129, upload-time = "2026-02-11T04:21:42.521Z" }, + { url = "https://files.pythonhosted.org/packages/1e/f8/66ab30a2193b277785601e82ee2d49f68ea575d9637e5e234faaa98efa4c/pillow-12.1.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:89b54027a766529136a06cfebeecb3a04900397a3590fd252160b888479517bf", size = 6491807, upload-time = "2026-02-11T04:21:44.22Z" }, + { url = "https://files.pythonhosted.org/packages/da/0b/a877a6627dc8318fdb84e357c5e1a758c0941ab1ddffdafd231983788579/pillow-12.1.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:86172b0831b82ce4f7877f280055892b31179e1576aa00d0df3bb1bbf8c3e524", size = 7190954, upload-time = "2026-02-11T04:21:46.114Z" }, + { url = "https://files.pythonhosted.org/packages/83/43/6f732ff85743cf746b1361b91665d9f5155e1483817f693f8d57ea93147f/pillow-12.1.1-cp313-cp313t-win32.whl", hash = "sha256:44ce27545b6efcf0fdbdceb31c9a5bdea9333e664cda58a7e674bb74608b3986", size = 6336441, upload-time = "2026-02-11T04:21:48.22Z" }, + { url = "https://files.pythonhosted.org/packages/3b/44/e865ef3986611bb75bfabdf94a590016ea327833f434558801122979cd0e/pillow-12.1.1-cp313-cp313t-win_amd64.whl", hash = "sha256:a285e3eb7a5a45a2ff504e31f4a8d1b12ef62e84e5411c6804a42197c1cf586c", size = 7045383, upload-time = "2026-02-11T04:21:50.015Z" }, + { url = "https://files.pythonhosted.org/packages/a8/c6/f4fb24268d0c6908b9f04143697ea18b0379490cb74ba9e8d41b898bd005/pillow-12.1.1-cp313-cp313t-win_arm64.whl", hash = "sha256:cc7d296b5ea4d29e6570dabeaed58d31c3fea35a633a69679fb03d7664f43fb3", size = 2456104, upload-time = "2026-02-11T04:21:51.633Z" }, + { url = "https://files.pythonhosted.org/packages/03/d0/bebb3ffbf31c5a8e97241476c4cf8b9828954693ce6744b4a2326af3e16b/pillow-12.1.1-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:417423db963cb4be8bac3fc1204fe61610f6abeed1580a7a2cbb2fbda20f12af", size = 4062652, upload-time = "2026-02-11T04:21:53.19Z" }, + { url = "https://files.pythonhosted.org/packages/2d/c0/0e16fb0addda4851445c28f8350d8c512f09de27bbb0d6d0bbf8b6709605/pillow-12.1.1-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:b957b71c6b2387610f556a7eb0828afbe40b4a98036fc0d2acfa5a44a0c2036f", size = 4138823, upload-time = "2026-02-11T04:22:03.088Z" }, + { url = "https://files.pythonhosted.org/packages/6b/fb/6170ec655d6f6bb6630a013dd7cf7bc218423d7b5fa9071bf63dc32175ae/pillow-12.1.1-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:097690ba1f2efdeb165a20469d59d8bb03c55fb6621eb2041a060ae8ea3e9642", size = 3601143, upload-time = "2026-02-11T04:22:04.909Z" }, + { url = "https://files.pythonhosted.org/packages/59/04/dc5c3f297510ba9a6837cbb318b87dd2b8f73eb41a43cc63767f65cb599c/pillow-12.1.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2815a87ab27848db0321fb78c7f0b2c8649dee134b7f2b80c6a45c6831d75ccd", size = 5266254, upload-time = "2026-02-11T04:22:07.656Z" }, + { url = "https://files.pythonhosted.org/packages/05/30/5db1236b0d6313f03ebf97f5e17cda9ca060f524b2fcc875149a8360b21c/pillow-12.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f7ed2c6543bad5a7d5530eb9e78c53132f93dfa44a28492db88b41cdab885202", size = 4657499, upload-time = "2026-02-11T04:22:09.613Z" }, + { url = "https://files.pythonhosted.org/packages/6f/18/008d2ca0eb612e81968e8be0bbae5051efba24d52debf930126d7eaacbba/pillow-12.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:652a2c9ccfb556235b2b501a3a7cf3742148cd22e04b5625c5fe057ea3e3191f", size = 6232137, upload-time = "2026-02-11T04:22:11.434Z" }, + { url = "https://files.pythonhosted.org/packages/70/f1/f14d5b8eeb4b2cd62b9f9f847eb6605f103df89ef619ac68f92f748614ea/pillow-12.1.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d6e4571eedf43af33d0fc233a382a76e849badbccdf1ac438841308652a08e1f", size = 8042721, upload-time = "2026-02-11T04:22:13.321Z" }, + { url = "https://files.pythonhosted.org/packages/5a/d6/17824509146e4babbdabf04d8171491fa9d776f7061ff6e727522df9bd03/pillow-12.1.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b574c51cf7d5d62e9be37ba446224b59a2da26dc4c1bb2ecbe936a4fb1a7cb7f", size = 6347798, upload-time = "2026-02-11T04:22:15.449Z" }, + { url = "https://files.pythonhosted.org/packages/d1/ee/c85a38a9ab92037a75615aba572c85ea51e605265036e00c5b67dfafbfe2/pillow-12.1.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a37691702ed687799de29a518d63d4682d9016932db66d4e90c345831b02fb4e", size = 7039315, upload-time = "2026-02-11T04:22:17.24Z" }, + { url = "https://files.pythonhosted.org/packages/ec/f3/bc8ccc6e08a148290d7523bde4d9a0d6c981db34631390dc6e6ec34cacf6/pillow-12.1.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f95c00d5d6700b2b890479664a06e754974848afaae5e21beb4d83c106923fd0", size = 6462360, upload-time = "2026-02-11T04:22:19.111Z" }, + { url = "https://files.pythonhosted.org/packages/f6/ab/69a42656adb1d0665ab051eec58a41f169ad295cf81ad45406963105408f/pillow-12.1.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:559b38da23606e68681337ad74622c4dbba02254fc9cb4488a305dd5975c7eeb", size = 7165438, upload-time = "2026-02-11T04:22:21.041Z" }, + { url = "https://files.pythonhosted.org/packages/02/46/81f7aa8941873f0f01d4b55cc543b0a3d03ec2ee30d617a0448bf6bd6dec/pillow-12.1.1-cp314-cp314-win32.whl", hash = "sha256:03edcc34d688572014ff223c125a3f77fb08091e4607e7745002fc214070b35f", size = 6431503, upload-time = "2026-02-11T04:22:22.833Z" }, + { url = "https://files.pythonhosted.org/packages/40/72/4c245f7d1044b67affc7f134a09ea619d4895333d35322b775b928180044/pillow-12.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:50480dcd74fa63b8e78235957d302d98d98d82ccbfac4c7e12108ba9ecbdba15", size = 7176748, upload-time = "2026-02-11T04:22:24.64Z" }, + { url = "https://files.pythonhosted.org/packages/e4/ad/8a87bdbe038c5c698736e3348af5c2194ffb872ea52f11894c95f9305435/pillow-12.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:5cb1785d97b0c3d1d1a16bc1d710c4a0049daefc4935f3a8f31f827f4d3d2e7f", size = 2544314, upload-time = "2026-02-11T04:22:26.685Z" }, + { url = "https://files.pythonhosted.org/packages/6c/9d/efd18493f9de13b87ede7c47e69184b9e859e4427225ea962e32e56a49bc/pillow-12.1.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:1f90cff8aa76835cba5769f0b3121a22bd4eb9e6884cfe338216e557a9a548b8", size = 5268612, upload-time = "2026-02-11T04:22:29.884Z" }, + { url = "https://files.pythonhosted.org/packages/f8/f1/4f42eb2b388eb2ffc660dcb7f7b556c1015c53ebd5f7f754965ef997585b/pillow-12.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1f1be78ce9466a7ee64bfda57bdba0f7cc499d9794d518b854816c41bf0aa4e9", size = 4660567, upload-time = "2026-02-11T04:22:31.799Z" }, + { url = "https://files.pythonhosted.org/packages/01/54/df6ef130fa43e4b82e32624a7b821a2be1c5653a5fdad8469687a7db4e00/pillow-12.1.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:42fc1f4677106188ad9a55562bbade416f8b55456f522430fadab3cef7cd4e60", size = 6269951, upload-time = "2026-02-11T04:22:33.921Z" }, + { url = "https://files.pythonhosted.org/packages/a9/48/618752d06cc44bb4aae8ce0cd4e6426871929ed7b46215638088270d9b34/pillow-12.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:98edb152429ab62a1818039744d8fbb3ccab98a7c29fc3d5fcef158f3f1f68b7", size = 8074769, upload-time = "2026-02-11T04:22:35.877Z" }, + { url = "https://files.pythonhosted.org/packages/c3/bd/f1d71eb39a72fa088d938655afba3e00b38018d052752f435838961127d8/pillow-12.1.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d470ab1178551dd17fdba0fef463359c41aaa613cdcd7ff8373f54be629f9f8f", size = 6381358, upload-time = "2026-02-11T04:22:37.698Z" }, + { url = "https://files.pythonhosted.org/packages/64/ef/c784e20b96674ed36a5af839305f55616f8b4f8aa8eeccf8531a6e312243/pillow-12.1.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6408a7b064595afcab0a49393a413732a35788f2a5092fdc6266952ed67de586", size = 7068558, upload-time = "2026-02-11T04:22:39.597Z" }, + { url = "https://files.pythonhosted.org/packages/73/cb/8059688b74422ae61278202c4e1ad992e8a2e7375227be0a21c6b87ca8d5/pillow-12.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5d8c41325b382c07799a3682c1c258469ea2ff97103c53717b7893862d0c98ce", size = 6493028, upload-time = "2026-02-11T04:22:42.73Z" }, + { url = "https://files.pythonhosted.org/packages/c6/da/e3c008ed7d2dd1f905b15949325934510b9d1931e5df999bb15972756818/pillow-12.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c7697918b5be27424e9ce568193efd13d925c4481dd364e43f5dff72d33e10f8", size = 7191940, upload-time = "2026-02-11T04:22:44.543Z" }, + { url = "https://files.pythonhosted.org/packages/01/4a/9202e8d11714c1fc5951f2e1ef362f2d7fbc595e1f6717971d5dd750e969/pillow-12.1.1-cp314-cp314t-win32.whl", hash = "sha256:d2912fd8114fc5545aa3a4b5576512f64c55a03f3ebcca4c10194d593d43ea36", size = 6438736, upload-time = "2026-02-11T04:22:46.347Z" }, + { url = "https://files.pythonhosted.org/packages/f3/ca/cbce2327eb9885476b3957b2e82eb12c866a8b16ad77392864ad601022ce/pillow-12.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:4ceb838d4bd9dab43e06c363cab2eebf63846d6a4aeaea283bbdfd8f1a8ed58b", size = 7182894, upload-time = "2026-02-11T04:22:48.114Z" }, + { url = "https://files.pythonhosted.org/packages/ec/d2/de599c95ba0a973b94410477f8bf0b6f0b5e67360eb89bcb1ad365258beb/pillow-12.1.1-cp314-cp314t-win_arm64.whl", hash = "sha256:7b03048319bfc6170e93bd60728a1af51d3dd7704935feb228c4d4faab35d334", size = 2546446, upload-time = "2026-02-11T04:22:50.342Z" }, +] + +[[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 = "raffle-site" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "dj-database-url" }, + { name = "django" }, + { name = "django-environ" }, + { name = "gunicorn" }, + { name = "pillow" }, + { name = "psycopg2-binary" }, +] + +[package.metadata] +requires-dist = [ + { name = "dj-database-url" }, + { name = "django", specifier = ">=6.0.3" }, + { name = "django-environ" }, + { name = "gunicorn" }, + { name = "pillow" }, + { name = "psycopg2-binary" }, +] + +[[package]] +name = "sqlparse" +version = "0.5.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/90/76/437d71068094df0726366574cf3432a4ed754217b436eb7429415cf2d480/sqlparse-0.5.5.tar.gz", hash = "sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e", size = 120815, upload-time = "2025-12-19T07:17:45.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl", hash = "sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba", size = 46138, upload-time = "2025-12-19T07:17:46.573Z" }, +] + +[[package]] +name = "tzdata" +version = "2025.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772, upload-time = "2025-12-13T17:45:35.667Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" }, +]