From 20b5086800eb709519b80c2a9130efa095d6e827 Mon Sep 17 00:00:00 2001 From: KenwoodFox Date: Wed, 3 Dec 2025 12:47:17 -0500 Subject: [PATCH] Inital simple hand-made ver --- .gitignore | 60 +++++++ Dockerfile | 11 ++ Pipfile | 12 ++ Pipfile.lock | 46 +++++ README.md | 24 +++ manage.py | 23 +++ requirements.txt | 2 + seduttomachineworks_project/__init__.py | 0 seduttomachineworks_project/asgi.py | 17 ++ seduttomachineworks_project/settings.py | 100 +++++++++++ seduttomachineworks_project/urls.py | 16 ++ seduttomachineworks_project/views.py | 11 ++ seduttomachineworks_project/wsgi.py | 17 ++ templates/quote_upload.html | 214 ++++++++++++++++++++++++ 14 files changed, 553 insertions(+) create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 Pipfile create mode 100644 Pipfile.lock create mode 100644 README.md create mode 100644 manage.py create mode 100644 requirements.txt create mode 100644 seduttomachineworks_project/__init__.py create mode 100644 seduttomachineworks_project/asgi.py create mode 100644 seduttomachineworks_project/settings.py create mode 100644 seduttomachineworks_project/urls.py create mode 100644 seduttomachineworks_project/views.py create mode 100644 seduttomachineworks_project/wsgi.py create mode 100644 templates/quote_upload.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3669209 --- /dev/null +++ b/.gitignore @@ -0,0 +1,60 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# Virtual environments +venv/ +env/ +ENV/ +.venv + +# Django +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal +/media +/staticfiles + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ +.DS_Store + +# Environment +.env +.env.local + +# Testing +.coverage +.pytest_cache/ +htmlcov/ +.tox/ + +# Docker +.dockerignore + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..950ee36 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM python:3.11-slim + +WORKDIR /app + +COPY . /app + +RUN pip install --upgrade pip +RUN pip install --upgrade gunicorn +RUN pip install --no-cache-dir -r requirements.txt + +CMD ["gunicorn", "seduttomachineworks_project.wsgi:application", "--bind", "0.0.0.0:8000"] diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..4d46502 --- /dev/null +++ b/Pipfile @@ -0,0 +1,12 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +django = "<5.0,>=4.2" + +[dev-packages] + +[requires] +python_version = "3.11" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..ff0cd9e --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,46 @@ +{ + "_meta": { + "hash": { + "sha256": "bd4cb91114d0c833ac47abdad00410896c666f4553053870c3c7655342c703a0" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.11" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "asgiref": { + "hashes": [ + "sha256:aef8a81283a34d0ab31630c9b7dfe70c812c95eba78171367ca8745e88124734", + "sha256:d89f2d8cd8b56dada7d52fa7dc8075baa08fb836560710d38c292a7a3f78c04e" + ], + "markers": "python_version >= '3.9'", + "version": "==3.10.0" + }, + "django": { + "hashes": [ + "sha256:9398e487bcb55e3f142cb56d19fbd9a83e15bb03a97edc31f408361ee76d9d7a", + "sha256:c96e64fc3c359d051a6306871bd26243db1bd02317472a62ffdbe6c3cae14280" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==4.2.26" + }, + "sqlparse": { + "hashes": [ + "sha256:09f67787f56a0b16ecdbde1bfc7f5d9c3371ca683cfeaa8e6ff60b4807ec9272", + "sha256:cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca" + ], + "markers": "python_version >= '3.8'", + "version": "==0.5.3" + } + }, + "develop": {} +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..802fd9d --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# Qoute Upload Box + +More could actually go in here! But for now this is *just* an advanced upload box. +Configurable with some server-side storage (a little) and an email system. + +Allows somewhat large uploads, some text for qoutes, drawings, etc. And keeps things +simple-ish! + +uses sqlite3 stored alongside the customer files. + +## Compose Example + +```yaml +services: + web_upload: + volumes: + - /var/seduttomachineworks/data:/app/store + ports: + - "8000:8000" + environment: + - SECRET_KEY=your-very-secret-production-key + - ALLOWED_HOSTS=yourdomain.com,localhost,127.0.0.1 + restart: always +``` \ No newline at end of file diff --git a/manage.py b/manage.py new file mode 100644 index 0000000..d790550 --- /dev/null +++ b/manage.py @@ -0,0 +1,23 @@ +#!/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', 'seduttomachineworks_project.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/requirements.txt b/requirements.txt new file mode 100644 index 0000000..752fa44 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +Django>=4.2,<5.0 + diff --git a/seduttomachineworks_project/__init__.py b/seduttomachineworks_project/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/seduttomachineworks_project/asgi.py b/seduttomachineworks_project/asgi.py new file mode 100644 index 0000000..1d07d70 --- /dev/null +++ b/seduttomachineworks_project/asgi.py @@ -0,0 +1,17 @@ +""" +ASGI config for seduttomotorsports 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/4.2/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'seduttomachineworks_project.settings') + +application = get_asgi_application() + diff --git a/seduttomachineworks_project/settings.py b/seduttomachineworks_project/settings.py new file mode 100644 index 0000000..bceb821 --- /dev/null +++ b/seduttomachineworks_project/settings.py @@ -0,0 +1,100 @@ +""" +Django settings for seduttomotorsports project. +""" + +from pathlib import Path +import os + +# 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/4.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = os.environ.get("SECRET_KEY", "django-insecure-change-this-in-production") + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = os.environ.get("DEBUG", "True") == "True" + +ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS", "*").split(",") + + +# Application definition + +INSTALLED_APPS = [ + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", +] + +MIDDLEWARE = [ + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", +] + +ROOT_URLCONF = "seduttomachineworks_project.urls" + +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [BASE_DIR / "templates"], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.messages.context_processors.messages", + ], + }, + }, +] + +WSGI_APPLICATION = "seduttomachineworks_project.wsgi.application" + + +# Database +# https://docs.djangoproject.com/en/4.2/ref/settings/#databases + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": BASE_DIR / "db.sqlite3", + } +} + + +# Internationalization +# https://docs.djangoproject.com/en/4.2/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/4.2/howto/static-files/ + +STATIC_URL = "static/" +STATIC_ROOT = BASE_DIR / "staticfiles" + +MEDIA_URL = "media/" +MEDIA_ROOT = BASE_DIR / "media" + +# Default primary key field type +# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" + +# Allow iframe embedding (for the quoting upload box) +# Note: We'll handle this per-view using @xframe_options_exempt decorator diff --git a/seduttomachineworks_project/urls.py b/seduttomachineworks_project/urls.py new file mode 100644 index 0000000..b5ec606 --- /dev/null +++ b/seduttomachineworks_project/urls.py @@ -0,0 +1,16 @@ +""" +URL configuration for seduttomotorsports project. +""" +from django.urls import path +from . import views +from django.conf import settings +from django.conf.urls.static import static + +urlpatterns = [ + path('', views.quote_upload, name='quote_upload'), +] + +if settings.DEBUG: + urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) + diff --git a/seduttomachineworks_project/views.py b/seduttomachineworks_project/views.py new file mode 100644 index 0000000..2fd1736 --- /dev/null +++ b/seduttomachineworks_project/views.py @@ -0,0 +1,11 @@ +from django.shortcuts import render +from django.views.decorators.clickjacking import xframe_options_exempt + + +@xframe_options_exempt +def quote_upload(request): + """ + Simple embeddable quote upload box. + TODO: Implement file upload and email integration + """ + return render(request, 'quote_upload.html') diff --git a/seduttomachineworks_project/wsgi.py b/seduttomachineworks_project/wsgi.py new file mode 100644 index 0000000..c75270b --- /dev/null +++ b/seduttomachineworks_project/wsgi.py @@ -0,0 +1,17 @@ +""" +WSGI config for seduttomotorsports 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/4.2/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'seduttomachineworks_project.settings') + +application = get_wsgi_application() + diff --git a/templates/quote_upload.html b/templates/quote_upload.html new file mode 100644 index 0000000..52ccad3 --- /dev/null +++ b/templates/quote_upload.html @@ -0,0 +1,214 @@ + + + + + + + Request a Quote + + + + +
+

Request a Quote

+
+

Drag & drop files here

+

or click to browse

+ +
+
+ +
+ TODO: Implement file upload functionality +
+ +
+ + + + + \ No newline at end of file