Refactor README.md to enhance clarity and structure, update project features, and improve setup instructions
This commit is contained in:
parent
81c360dca4
commit
e52ab7f78c
1 changed files with 118 additions and 178 deletions
308
README.md
308
README.md
|
|
@ -1,222 +1,162 @@
|
||||||
# 📚 Anny Booking Automation
|
# Anny Booking Automation
|
||||||
|
|
||||||
This Python project automates booking of study spaces or resources via the [anny.eu](https://anny.eu) platform used by university library systems. It logs in automatically using SAML SSO (with pluggable provider support), searches for available slots, and makes bookings without user interaction — ideal for recurring reservations.
|
Automate study space reservations on [anny.eu](https://anny.eu) platforms used by university libraries. Logs in via SAML SSO, finds available slots, and books them automatically.
|
||||||
|
|
||||||
---
|
## Features
|
||||||
|
|
||||||
## ⚙️ Features
|
- **Pluggable SSO** - KIT provider included, easily extendable for other universities
|
||||||
|
- **Smart scheduling** - Waits until midnight when slots open, or runs immediately for testing
|
||||||
|
- **Configurable time slots** - Set your preferred booking times in order of priority
|
||||||
|
- **Automated execution** - Runs via GitHub Actions + cron-job.org for precise timing
|
||||||
|
|
||||||
- 🔐 Pluggable SSO providers (KIT included, easily extendable for other universities)
|
## Quick Start
|
||||||
- 📆 Configurable 3-days-ahead reservation window
|
|
||||||
- 🔎 Auto-detection of available time slots
|
|
||||||
- ⏳ Smart midnight wait: only waits if within 10 minutes of midnight, otherwise executes immediately
|
|
||||||
- 🛠️ Clean and modular object-oriented codebase
|
|
||||||
- 🔁 Fully automated execution using [cron-job.org](https://cron-job.org) + GitHub API
|
|
||||||
- 📦 Easy to extend and maintain
|
|
||||||
|
|
||||||
---
|
### 1. Clone and install
|
||||||
|
|
||||||
## 🗂️ Project Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
anny_booking/
|
|
||||||
├── .env # Credentials (excluded from version control)
|
|
||||||
├── main.py # Entry point for script execution
|
|
||||||
├── requirements.txt # Python dependencies
|
|
||||||
│
|
|
||||||
├── auth/
|
|
||||||
│ ├── session.py # AnnySession class (login logic)
|
|
||||||
│ └── providers/ # SSO provider implementations
|
|
||||||
│ ├── __init__.py # Provider registry
|
|
||||||
│ ├── base.py # Abstract base class for providers
|
|
||||||
│ └── kit.py # KIT (Karlsruhe) SSO provider
|
|
||||||
│
|
|
||||||
├── booking/
|
|
||||||
│ └── client.py # BookingClient class (resource booking)
|
|
||||||
│
|
|
||||||
├── config/
|
|
||||||
│ └── constants.py # API URLs, timezone, SSO provider, and shared constants
|
|
||||||
│
|
|
||||||
├── utils/
|
|
||||||
│ └── helpers.py # Utility functions
|
|
||||||
│
|
|
||||||
└── .github/
|
|
||||||
└── workflows/
|
|
||||||
└── schedule.yml # GitHub Actions workflow (manual trigger)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🚀 Setup & Installation
|
|
||||||
|
|
||||||
### 1. Clone the repository
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/your-username/anny-booking-automation.git
|
git clone https://github.com/wiestju/anny-booking-automation.git
|
||||||
cd anny-booking-automation
|
cd anny-booking-automation
|
||||||
```
|
python -m venv venv
|
||||||
|
source venv/bin/activate # Windows: venv\Scripts\activate
|
||||||
### 2. Set up a Python virtual environment
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python3 -m venv venv
|
|
||||||
source venv/bin/activate
|
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. Configure environment variables
|
### 2. Configure credentials
|
||||||
|
|
||||||
Create a `.env` file in the root of the project:
|
Create a `.env` file:
|
||||||
|
|
||||||
```
|
```env
|
||||||
USERNAME=your_kit_username
|
USERNAME=your_university_username
|
||||||
PASSWORD=your_kit_password
|
PASSWORD=your_university_password
|
||||||
```
|
```
|
||||||
|
|
||||||
> 🔒 Never commit this file to version control!
|
### 3. Configure booking settings
|
||||||
|
|
||||||
### 4. Configure SSO provider
|
Edit `config/constants.py`:
|
||||||
|
|
||||||
In `config/constants.py`, set your SSO provider:
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
SSO_PROVIDER = "kit" # Available: kit (add more in auth/providers/)
|
SSO_PROVIDER = "kit" # Your university's SSO provider
|
||||||
|
RESOURCE_ID = None # Auto-detect, or set a specific resource ID
|
||||||
|
|
||||||
|
BOOKING_TIMES = [
|
||||||
|
{'start': '14:00:00', 'end': '19:00:00'}, # First priority
|
||||||
|
{'start': '09:00:00', 'end': '13:00:00'}, # Second priority
|
||||||
|
{'start': '20:00:00', 'end': '23:45:00'}, # Third priority
|
||||||
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
### 4. Run locally
|
||||||
|
|
||||||
## 🔌 Adding a New SSO Provider
|
```bash
|
||||||
|
python main.py
|
||||||
To add support for another university (e.g., TUM), create a new file `auth/providers/tum.py`:
|
|
||||||
|
|
||||||
```python
|
|
||||||
from auth.providers.base import SSOProvider
|
|
||||||
from utils.helpers import extract_html_value
|
|
||||||
|
|
||||||
class TUMProvider(SSOProvider):
|
|
||||||
name = "TUM"
|
|
||||||
domain = "tum.de"
|
|
||||||
|
|
||||||
def authenticate(self) -> str:
|
|
||||||
# Implement TUM-specific SAML authentication
|
|
||||||
# Use self.session, self.redirect_response, self.username, self.password
|
|
||||||
# Return the HTML containing the SAMLResponse
|
|
||||||
pass
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Then register it in `auth/providers/__init__.py`:
|
## Automated Scheduling
|
||||||
|
|
||||||
```python
|
For daily automated bookings, use GitHub Actions triggered by [cron-job.org](https://cron-job.org).
|
||||||
from auth.providers.tum import TUMProvider
|
|
||||||
|
|
||||||
PROVIDERS: dict[str, type[SSOProvider]] = {
|
### Why cron-job.org instead of GitHub's schedule?
|
||||||
"kit": KITProvider,
|
|
||||||
"tum": TUMProvider,
|
GitHub Actions `on: schedule` has two issues:
|
||||||
}
|
- **Queue delays** - Workflows can be delayed by minutes, missing the booking window
|
||||||
|
- **UTC only** - No timezone support, requiring manual DST adjustments
|
||||||
|
|
||||||
|
cron-job.org provides precise, timezone-aware scheduling with no delays.
|
||||||
|
|
||||||
|
### Setup
|
||||||
|
|
||||||
|
#### 1. Add GitHub Secrets
|
||||||
|
|
||||||
|
In your repository: **Settings > Secrets and variables > Actions**
|
||||||
|
|
||||||
|
| Secret | Value |
|
||||||
|
|--------|-------|
|
||||||
|
| `USERNAME` | Your university username |
|
||||||
|
| `PASSWORD` | Your university password |
|
||||||
|
|
||||||
|
#### 2. Create a GitHub Personal Access Token
|
||||||
|
|
||||||
|
1. Go to [GitHub Settings > Developer settings > Personal access tokens](https://github.com/settings/tokens)
|
||||||
|
2. Generate a token with `repo` scope (or fine-grained with Actions read/write)
|
||||||
|
3. Copy the token
|
||||||
|
|
||||||
|
#### 3. Configure cron-job.org
|
||||||
|
|
||||||
|
Create a new cron job with these settings:
|
||||||
|
|
||||||
|
| Setting | Value |
|
||||||
|
|---------|-------|
|
||||||
|
| URL | `https://api.github.com/repos/YOUR_USERNAME/anny-booking-automation/actions/workflows/schedule.yml/dispatches` |
|
||||||
|
| Schedule | `58 23 * * *` (23:58 daily) |
|
||||||
|
| Timezone | `Europe/Berlin` (or your timezone) |
|
||||||
|
| Request method | `POST` |
|
||||||
|
|
||||||
|
**Headers:**
|
||||||
```
|
```
|
||||||
|
Authorization: Bearer YOUR_GITHUB_TOKEN
|
||||||
---
|
|
||||||
|
|
||||||
## ⏱️ Automated Execution via cron-job.org + GitHub API
|
|
||||||
|
|
||||||
To maximize booking success, the script is triggered **two minutes before midnight** (e.g., 23:58).
|
|
||||||
It logs in to the KIT SAML SSO in advance, keeps the session alive, and **waits internally until exactly 00:00** to instantly book the best available slot as soon as new reservations open.
|
|
||||||
|
|
||||||
The trigger is handled by:
|
|
||||||
|
|
||||||
- `cron-job.org` for precise scheduling (e.g., 23:58 Europe/Berlin)
|
|
||||||
- GitHub Actions to run the actual script with credentials passed via GitHub Secrets
|
|
||||||
|
|
||||||
### Why not just use `on: schedule`?
|
|
||||||
|
|
||||||
GitHub Actions only supports fixed cron expressions (e.g., once per hour) and does **not** allow more frequent triggers like every 5 or 10 minutes.
|
|
||||||
Additionally, it suffers from two major issues:
|
|
||||||
|
|
||||||
- ⏳ **Queue delay**: Workflows triggered via GitHub's `schedule` event are sometimes delayed by several minutes due to internal queue congestion. This can cause the booking script to miss the optimal reservation window.
|
|
||||||
- 🕒 **Timezone limitations**: GitHub's cron system uses UTC without native timezone support. That means you need to manually convert your desired local time (e.g. Europe/Berlin) and keep adjusting for daylight saving time changes.
|
|
||||||
|
|
||||||
For these reasons, we use [cron-job.org](https://cron-job.org), which offers:
|
|
||||||
|
|
||||||
- ✅ Precise minute-level scheduling
|
|
||||||
- ✅ Native timezone selection (e.g. Europe/Berlin)
|
|
||||||
- ✅ Immediate webhook execution with no delay
|
|
||||||
|
|
||||||
This ensures your booking script runs exactly when needed — already logged in and ready to act at 00:00.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### How it works
|
|
||||||
|
|
||||||
1. `cron-job.org` triggers the GitHub Actions workflow at **23:58** (Europe/Berlin).
|
|
||||||
2. The script logs in via your configured SSO provider and maintains an active session.
|
|
||||||
3. If within 10 minutes of midnight, it waits until **00:00**. Otherwise, it executes immediately (useful for testing or manual runs).
|
|
||||||
4. As soon as new booking slots are released, it instantly reserves the first suitable slot.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Setup steps
|
|
||||||
|
|
||||||
1. Set up a cron job on `cron-job.org` that sends a POST request to:
|
|
||||||
|
|
||||||
```
|
|
||||||
https://api.github.com/repos/your-username/anny-booking-automation/actions/workflows/schedule.yml/dispatches
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Include the following JSON payload:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{"ref": "main"}
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Add this header:
|
|
||||||
|
|
||||||
```
|
|
||||||
Authorization: Bearer YOUR_GITHUB_PERSONAL_ACCESS_TOKEN
|
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
Accept: application/vnd.github.v3+json
|
Accept: application/vnd.github.v3+json
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Your GitHub workflow (`.github/workflows/schedule.yml`) listens for this event:
|
**Request body:**
|
||||||
|
```json
|
||||||
```yaml
|
{"ref": "main"}
|
||||||
name: Daily Library Reservation Automation
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
run-script:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
- name: Set up Python
|
|
||||||
uses: actions/setup-python@v2
|
|
||||||
with:
|
|
||||||
python-version: '3.x'
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
pip install -r requirements.txt
|
|
||||||
- name: Run script
|
|
||||||
env:
|
|
||||||
USERNAME: ${{ secrets.USERNAME }}
|
|
||||||
PASSWORD: ${{ secrets.PASSWORD }}
|
|
||||||
run: |
|
|
||||||
python main.py
|
|
||||||
```
|
```
|
||||||
|
|
||||||
> 💡 Store your university credentials securely as [GitHub Secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets): `USERNAME` and `PASSWORD`.
|
### How it works
|
||||||
|
|
||||||
---
|
1. cron-job.org triggers the workflow at **23:58**
|
||||||
|
2. The script logs in and establishes a session
|
||||||
|
3. It waits until **00:00** when new slots become available
|
||||||
|
4. Instantly books the first available slot from your priority list
|
||||||
|
|
||||||
## 🤝 Contributing
|
## Project Structure
|
||||||
|
|
||||||
Pull requests are welcome! Feel free to open an issue or suggest features or improvements.
|
```
|
||||||
|
anny-booking-automation/
|
||||||
|
├── main.py # Entry point
|
||||||
|
├── config/
|
||||||
|
│ └── constants.py # URLs, timezone, booking times
|
||||||
|
├── auth/
|
||||||
|
│ ├── session.py # Login session handling
|
||||||
|
│ └── providers/ # SSO provider implementations
|
||||||
|
│ ├── base.py # Abstract base class
|
||||||
|
│ └── kit.py # KIT provider
|
||||||
|
├── booking/
|
||||||
|
│ └── client.py # Booking API client
|
||||||
|
└── utils/
|
||||||
|
└── helpers.py # Utility functions
|
||||||
|
```
|
||||||
|
|
||||||
---
|
## Adding a New SSO Provider
|
||||||
|
|
||||||
## 📎 Related Tools
|
Create `auth/providers/youruni.py`:
|
||||||
|
|
||||||
- [cron-job.org](https://cron-job.org)
|
```python
|
||||||
- [GitHub Actions](https://github.com/features/actions)
|
from auth.providers.base import SSOProvider
|
||||||
- [anny.eu](https://anny.eu)
|
|
||||||
|
class YourUniProvider(SSOProvider):
|
||||||
|
name = "youruni"
|
||||||
|
domain = "youruni.edu"
|
||||||
|
|
||||||
|
def authenticate(self) -> str:
|
||||||
|
# Implement SAML authentication flow
|
||||||
|
# Use self.session, self.redirect_response, self.username, self.password
|
||||||
|
# Return HTML containing SAMLResponse
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
Register in `auth/providers/__init__.py`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from auth.providers.youruni import YourUniProvider
|
||||||
|
|
||||||
|
PROVIDERS = {
|
||||||
|
"kit": KITProvider,
|
||||||
|
"youruni": YourUniProvider,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue