From f077bf1f0f0740342390637c43ea55b71144fad8 Mon Sep 17 00:00:00 2001 From: Oleksandr Kozachuk Date: Sun, 8 Jun 2025 13:49:38 +0200 Subject: [PATCH] Complete the repo. --- .gitignore | 169 +++++--------------------- README.md | 343 ++++++++++++++++++++++++++++++++++++++++++++++++++++- tour.ini | 3 + 3 files changed, 371 insertions(+), 144 deletions(-) create mode 100644 tour.ini diff --git a/.gitignore b/.gitignore index 0dbf2f2..e267029 100644 --- a/.gitignore +++ b/.gitignore @@ -1,170 +1,55 @@ -# ---> Python -# Byte-compiled / optimized / DLL files -__pycache__/ +# Byte-compiled files + +**pycache**/ *.py[cod] *$py.class -# C extensions -*.so +# Virtual environments + +.env/ +.venv/ +env/ +venv/ + +# Distribution -# Distribution / packaging -.Python build/ -develop-eggs/ dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ *.egg-info/ -.installed.cfg *.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec # Installer logs + pip-log.txt pip-delete-this-directory.txt -# Unit test / coverage reports +# Python coverage + htmlcov/ .tox/ -.nox/ .coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py,cover -.hypothesis/ .pytest_cache/ -cover/ +.nox/ -# Translations -*.mo -*.pot +# Logs -# Django stuff: *.log -local_settings.py -db.sqlite3 -db.sqlite3-journal -# Flask stuff: -instance/ -.webassets-cache +# IDEs -# Scrapy stuff: -.scrapy +.vscode/ +.idea/ -# Sphinx documentation -docs/_build/ +# macOS -# PyBuilder -.pybuilder/ -target/ +.DS_Store -# Jupyter Notebook -.ipynb_checkpoints +# Linux -# IPython -profile_default/ -ipython_config.py +*~ -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# UV -# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -#uv.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -#pdm.lock -# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it -# in version control. -# https://pdm.fming.dev/latest/usage/project/#working-with-version-control -.pdm.toml -.pdm-python -.pdm-build/ - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# pytype static type analyzer -.pytype/ - -# Cython debug symbols -cython_debug/ - -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ +# Data files and locks +data/ +*.json +*.lock diff --git a/README.md b/README.md index 1339ff2..540bf60 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,342 @@ -# TourPlanner +# Tour Voting App -Tour Planner is a lightweight FastAPI-based service that lets you create “tours,” propose ideas for each tour, and vote on those ideas. It stores each tour as a JSON file in a configurable data directory (with file‐level locking for safe concurrent access), and ships with a minimal static HTML/JavaScript frontend along with helper scripts for local development or deployment under Supervisor. \ No newline at end of file +Tour Voting App is a full-stack web application for planning tours, proposing ideas, and voting on those ideas. It consists of: + +* **Backend API** built with FastAPI +* **Data persistence** using per-tour JSON files in a configurable directory, with concurrency safety via file locks +* **Frontend**: Single-page HTML/JavaScript application that consumes the API +* **Helper scripts** for local development or Supervisor-based deployment + +## Table of Contents + +1. Features +2. Tech Stack +3. Prerequisites +4. Installation +5. Configuration +6. Development +7. Running in Production +8. Frontend Usage +9. API Reference + * Models + * Endpoints +10. Directory Structure +11. Contributing +12. License + +## Features + +* Create and manage tours with metadata (name, start/end dates, description) +* Add multiple ideas per tour, each with its own name, description, and optional time window +* Vote on ideas by recording unique voter names +* No external database: JSON file–based persistence +* Concurrency-safe via file locking +* Minimal static HTML/JavaScript frontend for user interaction +* Helper scripts for local development or Supervisor deployment + +## Tech Stack + +* **Backend**: Python 3.10+, FastAPI, Uvicorn, Pydantic, filelock +* **Frontend**: HTML, CSS, JavaScript (Fetch API) +* **Process Control (optional)**: Supervisor +* **Data storage**: JSON files, one per tour + +## Prerequisites + +* Python 3.10 or higher +* pip (Python package installer) +* (Optional) Supervisor for process management + +## Installation + +1. **Clone the repository** + git clone [https://github.com/your-organization/tour-voting-app.git](https://github.com/your-organization/tour-voting-app.git) + cd tour-voting-app + +2. **Create virtual environment and install dependencies** + python3 -m venv .venv + source .venv/bin/activate + pip install -r requirements.txt + + If `requirements.txt` is not provided, install directly: + pip install fastapi uvicorn pydantic filelock + +## Configuration + +Configure via environment variables or command-line flags: + +* **DATA\_DIR**: directory to store tour JSON files (default: `./data`) +* **HOST**: address to bind the API (default: `0.0.0.0`) +* **PORT**: port for the API (default: `8000`) + +Example using environment variables: + +``` +export DATA_DIR=./data +export HOST=0.0.0.0 +export PORT=8000 +``` + +Or via flags: + +``` +python server.py --data-dir ./data --host 0.0.0.0 --port 8000 +``` + +## Development + +1. Activate your virtual environment. +2. Start the server in reload mode: + + ``` + uvicorn server:app --reload --host 0.0.0.0 --port 8000 + ``` +3. Open `index.html` in your browser (or serve it via a local HTTP server to avoid CORS issues). + +## Running in Production + +Use the provided `service.sh` script and Supervisor config: + +**service.sh** + +```bash +#!/usr/bin/env bash +cd /path/to/tour-voting-app || exit 1 +exec uvicorn server:app \ + --host 0.0.0.0 \ + --port 3002 \ + --loop uvloop \ + --workers 2 \ + --access-log \ + --log-level info +``` + +**tour.ini** (Supervisor) + +```ini +[program:tour_voting_app] +command=/path/to/service.sh +directory=/path/to/tour-voting-app +autostart=true +autorestart=true +stderr_logfile=/var/log/tour_voting_app.err.log +stdout_logfile=/var/log/tour_voting_app.out.log +``` + +## Frontend Usage + +The frontend is a single `index.html` file that interacts with the API. By default, `API_URL` is set to `http://localhost:8000/tour/v1`. To point it at a remote server, edit the `API_URL` constant near the top of `index.html`. + +## API Reference + +Base path: `/tour/v1` + +### Models + +**Tour** + +```json +{ + "id": "string", + "name": "string", + "description": "string", + "startDate": "ISO-8601 timestamp", + "endDate": "ISO-8601 timestamp", + "createdAt": "ISO-8601 timestamp", + "ideas": [ Idea ] +} +``` + +**Idea** + +```json +{ + "id": "string", + "name": "string", + "description": "string", + "startTime": "ISO-8601 timestamp | null", + "endTime": "ISO-8601 timestamp | null", + "voters": [ "string" ] +} +``` + +### Endpoints + +#### 1. List Tours + +* **Method**: GET +* **URL**: `/tours` +* **Response**: `200 OK` + + ```json + [ { Tour }, ... ] + ``` + +#### 2. Create a Tour + +* **Method**: POST +* **URL**: `/tours` +* **Request Body**: + + ```json + { + "name": "Europe Explorer", + "description": "A tour across Europe", + "startDate": "2025-07-01T00:00:00Z", + "endDate": "2025-07-15T00:00:00Z" + } + ``` +* **Response**: `201 Created` + + ```json + { Tour } + ``` + +#### 3. Get Tour Details + +* **Method**: GET +* **URL**: `/tours/{tour_id}` +* **Path Parameters**: + + * `tour_id` (string): ID of the tour +* **Response**: `200 OK` + + ```json + { Tour } + ``` +* **Error**: `404 Not Found` if tour does not exist. + +#### 4. Add an Idea to a Tour + +* **Method**: POST +* **URL**: `/tours/{tour_id}/ideas` +* **Path Parameters**: + + * `tour_id` (string): ID of the tour +* **Request Body**: + + ```json + { + "name": "Visit the Louvre", + "description": "Guided museum tour", + "startTime": "2025-07-03T10:00:00Z", + "endTime": "2025-07-03T14:00:00Z" + } + ``` +* **Response**: `201 Created` + + ```json + { Idea } + ``` +* **Error**: `404 Not Found` if tour does not exist. + +#### 5. Vote for an Idea + +* **Method**: POST +* **URL**: `/tours/{tour_id}/ideas/{idea_id}/vote` +* **Path Parameters**: + + * `tour_id` (string): ID of the tour + * `idea_id` (string): ID of the idea +* **Request Body**: + + ```json + { "voterName": "alice@example.com" } + ``` +* **Response**: `200 OK` + + ```json + { Idea } // Updated idea with new voter + ``` +* **Errors**: + + * `404 Not Found` if tour or idea does not exist. + * `400 Bad Request` if voter name is missing or already voted. + +## Directory Structure + +``` +tour-voting-app/ +├── server.py # FastAPI application +├── index.html # Static frontend +├── service.sh # Startup helper script +├── tour.ini # Supervisor config +├── data/ # JSON files for tours (runtime) +├── requirements.txt # Python dependencies (optional) +└── README.md # Project documentation +``` + +## Contributing + +1. Fork the repository. +2. Create a feature branch: + git checkout -b feature/my-feature +3. Commit your changes: + git commit -m "Add my feature" +4. Push to your branch: + git push origin feature/my-feature +5. Open a pull request. + +## License + +This project is licensed under the WTFPL License. + +--- + +.gitignore + +# Byte-compiled files + +**pycache**/ +\*.py\[cod] +\*\$py.class + +# Virtual environments + +.env/ +.venv/ +env/ +venv/ + +# Distribution + +build/ +dist/ +\*.egg-info/ +\*.egg + +# Installer logs + +pip-log.txt +pip-delete-this-directory.txt + +# Python coverage + +htmlcov/ +.tox/ +.coverage +.pytest\_cache/ +.nox/ + +# Logs + +\*.log + +# IDEs + +.vscode/ +.idea/ + +# macOS + +.DS\_Store + +# Linux + +\*\~ + +# Data files and locks + +data/ +\*.json +\*.lock diff --git a/tour.ini b/tour.ini new file mode 100644 index 0000000..bd3f7ed --- /dev/null +++ b/tour.ini @@ -0,0 +1,3 @@ +[program:tour] +command=/home/kaizen/repos/tourplanner/service.sh +startsecs=60