# WebQuiz
A modern web-based quiz and testing system built with Python and aiohttp that allows users to take multiple-choice tests with real-time answer validation and performance tracking.
## โจ Features
- **User Management**: Unique username registration with UUID-based session tracking
- **Question System**: YAML-based config with automatic file generation
- **Auto-Generated Files**: Creates default config.yaml and index.html if missing
- **Real-time Validation**: Server-side answer checking and timing
- **Session Persistence**: Cookie-based user sessions for seamless experience
- **Performance Tracking**: Server-side timing for accurate response measurement
- **Data Export**: Automatic CSV export of user responses with configurable file paths
- **Responsive UI**: Clean web interface with dark/light theme support
- **Comprehensive Testing**: Full test suite with integration and unit tests
- **Flexible File Paths**: Configurable paths for config, log, CSV, and static files
## ๐ Quick Start
### Prerequisites
- Python 3.9+ (required by aiohttp)
- Poetry (recommended) or pip
- Git
### Installation with Poetry (Recommended)
1. **Clone the repository**
```bash
git clone git@github.com:oduvan/webquiz.git
cd webquiz
```
2. **Install with Poetry**
```bash
poetry install
```
3. **Run the server**
```bash
webquiz # Foreground mode
webquiz -d # Daemon mode
```
4. **Open your browser**
```
http://localhost:8080
```
### Alternative Installation with pip
1. **Clone and set up virtual environment**
```bash
git clone git@github.com:oduvan/webquiz.git
cd webquiz
python3 -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
```
2. **Install dependencies**
```bash
pip install -r requirements.txt
```
3. **Run the server**
```bash
python -m webquiz.cli
```
That's it! The server will automatically create:
- **config.yaml** with sample questions if missing
- **index.html** web interface if missing
- **CSV files** for user response tracking
## ๐ Project Structure
```
webquiz/
โโโ pyproject.toml # Poetry configuration and dependencies
โโโ requirements.txt # Legacy pip dependencies
โโโ .gitignore # Git ignore rules
โโโ CLAUDE.md # Project documentation
โโโ README.md # This file
โโโ webquiz/ # Main package
โ โโโ __init__.py # Package initialization
โ โโโ cli.py # CLI entry point (webquiz command)
โ โโโ server.py # Main application server
โโโ static/ # Frontend files
โ โโโ index.html # Single-page web application
โโโ tests/ # Test suite
โ โโโ conftest.py # Test configuration
โ โโโ test_integration.py # Integration tests (11 tests)
โ โโโ test_server.py # Unit tests (3 tests)
โโโ venv/ # Virtual environment (excluded from git)
# Generated at runtime (excluded from git):
โโโ config.yaml # Configuration and question database (auto-created)
โโโ user_responses.csv # User response data
โโโ server.log # Server logs
โโโ webquiz.pid # Daemon process ID
โโโ static/
โโโ index.html # Web interface (auto-created if missing)
โโโ questions_for_client.json # Client-safe questions (auto-generated)
```
## ๐ง API Reference
### Authentication
- User sessions managed via UUID stored in browser cookies
- No passwords required - username-based registration
### Endpoints
#### `POST /api/register`
Register a new user with unique username.
**Request:**
```json
{
"username": "john_doe"
}
```
**Response:**
```json
{
"username": "john_doe",
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"message": "User registered successfully"
}
```
#### `POST /api/submit-answer`
Submit an answer for a question.
**Request:**
```json
{
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"question_id": 1,
"selected_answer": 2
}
```
**Response:**
```json
{
"is_correct": true,
"time_taken": 5.23,
"message": "Answer submitted successfully"
}
```
#### `GET /api/verify-user/{user_id}`
Verify user session and get progress information.
**Response:**
```json
{
"valid": true,
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"username": "john_doe",
"next_question_index": 2,
"total_questions": 5,
"last_answered_question_id": 1
}
```
## ๐ฅ๏ธ CLI Commands
The `webquiz` command provides several options:
```bash
# Start server in foreground (default)
webquiz
# Start server with custom files
webquiz --config my-config.yaml
webquiz --log-file /var/log/webquiz.log
webquiz --csv-file /data/responses.csv
webquiz --static /var/www/quiz
# Combine multiple custom paths
webquiz --config quiz.yaml --log-file quiz.log --csv-file quiz.csv --static web/
# Start server as daemon (background)
webquiz -d
webquiz --daemon
# Stop daemon server
webquiz --stop
# Check daemon status
webquiz --status
# Show help
webquiz --help
# Show version
webquiz --version
```
### Daemon Mode Features
- **Background execution**: Server runs independently in background
- **PID file management**: Automatic process tracking via `webquiz.pid`
- **Graceful shutdown**: Proper cleanup on stop
- **Status monitoring**: Check if daemon is running
- **Log preservation**: All output still goes to `server.log`
## ๐งช Testing
Run the comprehensive test suite:
```bash
# With Poetry
poetry run pytest
# Or directly
pytest tests/
# Run with verbose output
pytest tests/ -v
# Run only integration tests
pytest tests/test_integration.py
# Run only unit tests
pytest tests/test_server.py
```
### Test Coverage
- **11 Integration Tests**: End-to-end API testing with real HTTP requests
- **3 Unit Tests**: Internal functionality testing (CSV, YAML, data structures)
- **Total**: 14 tests covering all critical functionality
## ๐ Configuration Format
Questions are stored in `config.yaml` (auto-generated if missing):
```yaml
questions:
- id: 1
question: "What is 2 + 2?"
options:
- "3"
- "4"
- "5"
- "6"
correct_answer: 1 # 0-indexed (option "4")
- id: 2
question: "What is the capital of France?"
options:
- "London"
- "Berlin"
- "Paris"
- "Madrid"
correct_answer: 2 # 0-indexed (option "Paris")
```
## ๐ Data Export
User responses are automatically exported to `user_responses.csv`:
```csv
user_id,username,question_text,selected_answer_text,correct_answer_text,is_correct,time_taken_seconds
550e8400-e29b-41d4-a716-446655440000,john_doe,"What is 2 + 2?","4","4",True,3.45
```
## ๐จ Customization
### Adding Your Own Questions
1. **Edit config.yaml** (created automatically on first run)
2. **Restart the server** to load new questions
3. **Questions must have unique IDs** and 0-indexed correct answers
4. **Use custom file paths**:
- Config: `webquiz --config my-questions.yaml`
- Logs: `webquiz --log-file /var/log/quiz.log`
- CSV: `webquiz --csv-file /data/responses.csv`
- Static files: `webquiz --static /var/www/quiz`
### Styling
- Modify `static/index.html` for UI changes
- Built-in dark/light theme toggle
- Responsive design works on mobile and desktop
## ๐ ๏ธ Development
### Key Technical Decisions
- **Server-side timing**: All timing calculated server-side for accuracy
- **UUID-based sessions**: Secure user identification without passwords
- **Middleware error handling**: Clean error management with proper HTTP status codes
- **CSV module usage**: Proper escaping for data with commas/quotes
- **Auto-file generation**: Zero-configuration setup with sensible defaults
### Architecture
- **Backend**: Python 3.9+ with aiohttp async web framework
- **Frontend**: Vanilla HTML/CSS/JavaScript (no frameworks)
- **Storage**: In-memory with periodic CSV backups (30-second intervals)
- **Session Management**: Cookie-based with server-side validation
## ๐ Troubleshooting
### Common Issues
**Port already in use:**
```bash
# Kill process using port 8080
lsof -ti:8080 | xargs kill -9
```
**Virtual environment issues:**
```bash
# Recreate virtual environment
rm -rf venv
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
```
**Questions not loading:**
- Check that `config.yaml` has valid YAML syntax
- Restart server after editing config file
- Check server logs for errors
- Use custom file paths:
- `--config` for custom config file
- `--log-file` for custom log location
- `--csv-file` for custom CSV output location
- `--static` for custom static files directory
## ๐ License
This project is open source. Feel free to use and modify as needed.
## ๐ค Contributing
1. Fork the repository
2. Create a feature branch
3. Add tests for new functionality
4. Ensure all tests pass
5. Submit a pull request
## ๐ Support
For questions or issues:
- Check the server logs (`server.log`)
- Run the test suite to verify setup
- Review this README and `CLAUDE.md` for detailed documentation
Raw data
{
"_id": null,
"home_page": "https://github.com/oduvan/webquiz",
"name": "webquiz",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.9",
"maintainer_email": null,
"keywords": "quiz, testing, aiohttp, web, assessment, education",
"author": "Oleksandr Liabakh",
"author_email": "oduvan@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/f7/72/0a2fcfdaa2bc5869baed5caed19f51dc469d588b29fb7f6b6f9d54c85321/webquiz-1.0.5.tar.gz",
"platform": null,
"description": "# WebQuiz\n\nA modern web-based quiz and testing system built with Python and aiohttp that allows users to take multiple-choice tests with real-time answer validation and performance tracking.\n\n## \u2728 Features\n\n- **User Management**: Unique username registration with UUID-based session tracking\n- **Question System**: YAML-based config with automatic file generation\n- **Auto-Generated Files**: Creates default config.yaml and index.html if missing\n- **Real-time Validation**: Server-side answer checking and timing\n- **Session Persistence**: Cookie-based user sessions for seamless experience\n- **Performance Tracking**: Server-side timing for accurate response measurement\n- **Data Export**: Automatic CSV export of user responses with configurable file paths\n- **Responsive UI**: Clean web interface with dark/light theme support\n- **Comprehensive Testing**: Full test suite with integration and unit tests\n- **Flexible File Paths**: Configurable paths for config, log, CSV, and static files\n\n## \ud83d\ude80 Quick Start\n\n### Prerequisites\n\n- Python 3.9+ (required by aiohttp)\n- Poetry (recommended) or pip\n- Git\n\n### Installation with Poetry (Recommended)\n\n1. **Clone the repository**\n ```bash\n git clone git@github.com:oduvan/webquiz.git\n cd webquiz\n ```\n\n2. **Install with Poetry**\n ```bash\n poetry install\n ```\n\n3. **Run the server**\n ```bash\n webquiz # Foreground mode\n webquiz -d # Daemon mode\n ```\n\n4. **Open your browser**\n ```\n http://localhost:8080\n ```\n\n### Alternative Installation with pip\n\n1. **Clone and set up virtual environment**\n ```bash\n git clone git@github.com:oduvan/webquiz.git\n cd webquiz\n python3 -m venv venv\n source venv/bin/activate # On Windows: venv\\Scripts\\activate\n ```\n\n2. **Install dependencies**\n ```bash\n pip install -r requirements.txt\n ```\n\n3. **Run the server**\n ```bash\n python -m webquiz.cli\n ```\n\nThat's it! The server will automatically create:\n- **config.yaml** with sample questions if missing\n- **index.html** web interface if missing\n- **CSV files** for user response tracking\n\n## \ud83d\udcc1 Project Structure\n\n```\nwebquiz/\n\u251c\u2500\u2500 pyproject.toml # Poetry configuration and dependencies\n\u251c\u2500\u2500 requirements.txt # Legacy pip dependencies \n\u251c\u2500\u2500 .gitignore # Git ignore rules\n\u251c\u2500\u2500 CLAUDE.md # Project documentation\n\u251c\u2500\u2500 README.md # This file\n\u251c\u2500\u2500 webquiz/ # Main package\n\u2502 \u251c\u2500\u2500 __init__.py # Package initialization\n\u2502 \u251c\u2500\u2500 cli.py # CLI entry point (webquiz command)\n\u2502 \u2514\u2500\u2500 server.py # Main application server\n\u251c\u2500\u2500 static/ # Frontend files\n\u2502 \u2514\u2500\u2500 index.html # Single-page web application\n\u251c\u2500\u2500 tests/ # Test suite\n\u2502 \u251c\u2500\u2500 conftest.py # Test configuration\n\u2502 \u251c\u2500\u2500 test_integration.py # Integration tests (11 tests)\n\u2502 \u2514\u2500\u2500 test_server.py # Unit tests (3 tests)\n\u2514\u2500\u2500 venv/ # Virtual environment (excluded from git)\n\n# Generated at runtime (excluded from git):\n\u251c\u2500\u2500 config.yaml # Configuration and question database (auto-created)\n\u251c\u2500\u2500 user_responses.csv # User response data \n\u251c\u2500\u2500 server.log # Server logs\n\u251c\u2500\u2500 webquiz.pid # Daemon process ID\n\u2514\u2500\u2500 static/\n \u251c\u2500\u2500 index.html # Web interface (auto-created if missing)\n \u2514\u2500\u2500 questions_for_client.json # Client-safe questions (auto-generated)\n```\n\n## \ud83d\udd27 API Reference\n\n### Authentication\n- User sessions managed via UUID stored in browser cookies\n- No passwords required - username-based registration\n\n### Endpoints\n\n#### `POST /api/register`\nRegister a new user with unique username.\n\n**Request:**\n```json\n{\n \"username\": \"john_doe\"\n}\n```\n\n**Response:**\n```json\n{\n \"username\": \"john_doe\",\n \"user_id\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"message\": \"User registered successfully\"\n}\n```\n\n#### `POST /api/submit-answer`\nSubmit an answer for a question.\n\n**Request:**\n```json\n{\n \"user_id\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"question_id\": 1,\n \"selected_answer\": 2\n}\n```\n\n**Response:**\n```json\n{\n \"is_correct\": true,\n \"time_taken\": 5.23,\n \"message\": \"Answer submitted successfully\"\n}\n```\n\n#### `GET /api/verify-user/{user_id}`\nVerify user session and get progress information.\n\n**Response:**\n```json\n{\n \"valid\": true,\n \"user_id\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"username\": \"john_doe\",\n \"next_question_index\": 2,\n \"total_questions\": 5,\n \"last_answered_question_id\": 1\n}\n```\n\n## \ud83d\udda5\ufe0f CLI Commands\n\nThe `webquiz` command provides several options:\n\n```bash\n# Start server in foreground (default)\nwebquiz\n\n# Start server with custom files\nwebquiz --config my-config.yaml\nwebquiz --log-file /var/log/webquiz.log\nwebquiz --csv-file /data/responses.csv\nwebquiz --static /var/www/quiz\n\n# Combine multiple custom paths\nwebquiz --config quiz.yaml --log-file quiz.log --csv-file quiz.csv --static web/\n\n# Start server as daemon (background)\nwebquiz -d\nwebquiz --daemon\n\n# Stop daemon server\nwebquiz --stop\n\n# Check daemon status\nwebquiz --status\n\n# Show help\nwebquiz --help\n\n# Show version\nwebquiz --version\n```\n\n### Daemon Mode Features\n\n- **Background execution**: Server runs independently in background\n- **PID file management**: Automatic process tracking via `webquiz.pid`\n- **Graceful shutdown**: Proper cleanup on stop\n- **Status monitoring**: Check if daemon is running\n- **Log preservation**: All output still goes to `server.log`\n\n## \ud83e\uddea Testing\n\nRun the comprehensive test suite:\n\n```bash\n# With Poetry\npoetry run pytest\n\n# Or directly\npytest tests/\n\n# Run with verbose output\npytest tests/ -v\n\n# Run only integration tests\npytest tests/test_integration.py\n\n# Run only unit tests \npytest tests/test_server.py\n```\n\n### Test Coverage\n- **11 Integration Tests**: End-to-end API testing with real HTTP requests\n- **3 Unit Tests**: Internal functionality testing (CSV, YAML, data structures)\n- **Total**: 14 tests covering all critical functionality\n\n## \ud83d\udccb Configuration Format\n\nQuestions are stored in `config.yaml` (auto-generated if missing):\n\n```yaml\nquestions:\n - id: 1\n question: \"What is 2 + 2?\"\n options:\n - \"3\"\n - \"4\"\n - \"5\"\n - \"6\"\n correct_answer: 1 # 0-indexed (option \"4\")\n \n - id: 2\n question: \"What is the capital of France?\"\n options:\n - \"London\"\n - \"Berlin\"\n - \"Paris\"\n - \"Madrid\"\n correct_answer: 2 # 0-indexed (option \"Paris\")\n```\n\n## \ud83d\udcca Data Export\n\nUser responses are automatically exported to `user_responses.csv`:\n\n```csv\nuser_id,username,question_text,selected_answer_text,correct_answer_text,is_correct,time_taken_seconds\n550e8400-e29b-41d4-a716-446655440000,john_doe,\"What is 2 + 2?\",\"4\",\"4\",True,3.45\n```\n\n## \ud83c\udfa8 Customization\n\n### Adding Your Own Questions\n\n1. **Edit config.yaml** (created automatically on first run)\n2. **Restart the server** to load new questions \n3. **Questions must have unique IDs** and 0-indexed correct answers\n4. **Use custom file paths**: \n - Config: `webquiz --config my-questions.yaml`\n - Logs: `webquiz --log-file /var/log/quiz.log`\n - CSV: `webquiz --csv-file /data/responses.csv`\n - Static files: `webquiz --static /var/www/quiz`\n\n### Styling\n\n- Modify `static/index.html` for UI changes\n- Built-in dark/light theme toggle\n- Responsive design works on mobile and desktop\n\n## \ud83d\udee0\ufe0f Development\n\n### Key Technical Decisions\n\n- **Server-side timing**: All timing calculated server-side for accuracy\n- **UUID-based sessions**: Secure user identification without passwords \n- **Middleware error handling**: Clean error management with proper HTTP status codes\n- **CSV module usage**: Proper escaping for data with commas/quotes\n- **Auto-file generation**: Zero-configuration setup with sensible defaults\n\n### Architecture\n\n- **Backend**: Python 3.9+ with aiohttp async web framework\n- **Frontend**: Vanilla HTML/CSS/JavaScript (no frameworks)\n- **Storage**: In-memory with periodic CSV backups (30-second intervals)\n- **Session Management**: Cookie-based with server-side validation\n\n## \ud83d\udc1b Troubleshooting\n\n### Common Issues\n\n**Port already in use:**\n```bash\n# Kill process using port 8080\nlsof -ti:8080 | xargs kill -9\n```\n\n**Virtual environment issues:**\n```bash\n# Recreate virtual environment\nrm -rf venv\npython3 -m venv venv\nsource venv/bin/activate\npip install -r requirements.txt\n```\n\n**Questions not loading:**\n- Check that `config.yaml` has valid YAML syntax\n- Restart server after editing config file\n- Check server logs for errors\n- Use custom file paths:\n - `--config` for custom config file\n - `--log-file` for custom log location\n - `--csv-file` for custom CSV output location\n - `--static` for custom static files directory\n\n## \ud83d\udcdd License\n\nThis project is open source. Feel free to use and modify as needed.\n\n## \ud83e\udd1d Contributing\n\n1. Fork the repository\n2. Create a feature branch\n3. Add tests for new functionality\n4. Ensure all tests pass\n5. Submit a pull request\n\n## \ud83d\udcde Support\n\nFor questions or issues:\n- Check the server logs (`server.log`)\n- Run the test suite to verify setup\n- Review this README and `CLAUDE.md` for detailed documentation",
"bugtrack_url": null,
"license": "MIT",
"summary": "A modern web-based quiz and testing system built with Python and aiohttp",
"version": "1.0.5",
"project_urls": {
"Bug Tracker": "https://github.com/oduvan/webquiz/issues",
"Documentation": "https://github.com/oduvan/webquiz",
"Homepage": "https://github.com/oduvan/webquiz",
"Repository": "https://github.com/oduvan/webquiz"
},
"split_keywords": [
"quiz",
" testing",
" aiohttp",
" web",
" assessment",
" education"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "7496db3156c955e06662c08db416d0b856243593dc029f48a4ad3a2fbe251177",
"md5": "1753e2584d8366ec7752706909fc7221",
"sha256": "81ce5246d72a7a2dcfe3b5250680923ba365795cda2ffb16aa3a3a82f68e6cc5"
},
"downloads": -1,
"filename": "webquiz-1.0.5-py3-none-any.whl",
"has_sig": false,
"md5_digest": "1753e2584d8366ec7752706909fc7221",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.9",
"size": 40275,
"upload_time": "2025-08-22T22:06:52",
"upload_time_iso_8601": "2025-08-22T22:06:52.002273Z",
"url": "https://files.pythonhosted.org/packages/74/96/db3156c955e06662c08db416d0b856243593dc029f48a4ad3a2fbe251177/webquiz-1.0.5-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "f7720a2fcfdaa2bc5869baed5caed19f51dc469d588b29fb7f6b6f9d54c85321",
"md5": "a564a8851e7a172e9f7ff22067aaed6d",
"sha256": "755af8d4d0c0389fe4316736afb2824a45a17f36e433aec80d5e20c03358f516"
},
"downloads": -1,
"filename": "webquiz-1.0.5.tar.gz",
"has_sig": false,
"md5_digest": "a564a8851e7a172e9f7ff22067aaed6d",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.9",
"size": 40111,
"upload_time": "2025-08-22T22:06:53",
"upload_time_iso_8601": "2025-08-22T22:06:53.483905Z",
"url": "https://files.pythonhosted.org/packages/f7/72/0a2fcfdaa2bc5869baed5caed19f51dc469d588b29fb7f6b6f9d54c85321/webquiz-1.0.5.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-22 22:06:53",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "oduvan",
"github_project": "webquiz",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [
{
"name": "aiohttp",
"specs": [
[
"==",
"3.12.13"
]
]
},
{
"name": "PyYAML",
"specs": [
[
"==",
"6.0.2"
]
]
},
{
"name": "aiofiles",
"specs": [
[
"==",
"24.1.0"
]
]
},
{
"name": "pytest",
"specs": [
[
"==",
"8.3.3"
]
]
},
{
"name": "pytest-asyncio",
"specs": [
[
"==",
"0.24.0"
]
]
}
],
"lcname": "webquiz"
}