Metadata-Version: 2.4
Name: scormhost
Version: 0.1.0
Summary: Host SCORM 1.2 and 2004 packages on FastAPI — deployable to FastAPI Cloud
Project-URL: Homepage, https://github.com/eddiethedean/scormhost
Project-URL: Documentation, https://github.com/eddiethedean/scormhost#readme
Project-URL: Repository, https://github.com/eddiethedean/scormhost
Project-URL: Issues, https://github.com/eddiethedean/scormhost/issues
Author: scormhost contributors
License: Apache-2.0
License-File: LICENSE
Keywords: elearning,fastapi,lms,scorm,scormhost
Classifier: Development Status :: 3 - Alpha
Classifier: Framework :: FastAPI
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Education
Requires-Python: >=3.10
Requires-Dist: alembic>=1.14.0
Requires-Dist: bcrypt>=4.0.0
Requires-Dist: defusedxml>=0.7.1
Requires-Dist: email-validator>=2.0.0
Requires-Dist: fastapi>=0.115.0
Requires-Dist: pyjwt>=2.8.0
Requires-Dist: python-multipart>=0.0.9
Requires-Dist: sqlalchemy>=2.0.36
Requires-Dist: uvicorn[standard]>=0.32.0
Provides-Extra: dev
Requires-Dist: build>=1.0.0; extra == 'dev'
Requires-Dist: httpx>=0.27.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: ruff==0.15.14; extra == 'dev'
Requires-Dist: ty>=0.0.30; extra == 'dev'
Description-Content-Type: text/markdown

# scormhost

**Version 0.1.0** — Turn [FastAPI](https://fastapi.tiangolo.com/) into a **SCORM 1.2 / 2004 hosting app** with user accounts, JWT auth, and an admin UI — deployable to [FastAPI Cloud](https://fastapicloud.com/).

Works with packages built by [LXPack](https://github.com/eddiethedean/lxpack) (`lxpack build --target scorm12` / `scorm2004`) and other compliant SCORM ZIPs.

## Features

- **User management** — SQLite database, [Alembic](https://alembic.sqlalchemy.org/) migrations, bcrypt passwords
- **JWT auth** — access + refresh tokens (httpOnly cookies for the browser UI, `Authorization: Bearer` for API clients)
- **Public learning** — anyone can browse and launch courses without logging in
- **Optional login for learners** — progress saved to your account when signed in
- **Anonymous progress** — guests get a browser cookie so progress persists on that device
- **Staff login** — upload/delete courses and manage users (instructor/admin)
- **Roles** — `learner`, `instructor`, `admin` (first registered user becomes `admin`)

## Quick start

```bash
git clone https://github.com/eddiethedean/scormhost.git
cd scormhost
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"

# optional: run migrations manually (also runs on startup by default)
alembic upgrade head

fastapi dev
```

1. Open http://127.0.0.1:8000 — launch any course without an account.
2. Register at `/register` (first user = **admin**) to upload SCORM ZIPs or save progress to your account.

Or use the factory:

```python
from scormhost import create_scorm_app

app = create_scorm_app(
    data_dir="./data",
    title="My SCORM Host",
    secret_key="change-me-in-production",
)
```

Set `require_auth=True` only if you want to force login before taking courses (not the default).

## Database & migrations

Default database: `sqlite:///<data_dir>/scormhost.db` (override with `SCORMHOST_DATABASE_URL`).

```bash
alembic upgrade head    # apply migrations
alembic revision -m "describe change" --autogenerate  # new revision
```

On app startup, migrations run automatically when `SCORMHOST_AUTO_MIGRATE=true` (default).

## Roles

| Role | Capabilities |
|------|----------------|
| `learner` | Launch courses (no login required); signed-in progress tied to account |
| `instructor` | Upload packages, delete own uploads (login required) |
| `admin` | User management, delete any package (login required) |

**Without login:** launch courses; progress stored under a guest cookie on this browser.

**With login:** same, but SCORM progress is keyed to your user id (works across browsers/devices).

## Auth API

| Method | Path | Description |
|--------|------|-------------|
| `POST` | `/api/auth/register` | Create account (sets cookies) |
| `POST` | `/api/auth/login` | Login (sets cookies) |
| `POST` | `/api/auth/refresh` | Rotate refresh token |
| `POST` | `/api/auth/logout` | Revoke refresh token, clear cookies |
| `GET` | `/api/auth/me` | Current user (Bearer or cookie) |
| `PATCH` | `/api/auth/me/password` | Change password |
| `GET` | `/api/users` | List users (admin) |
| `PATCH` | `/api/users/{id}` | Update role / active flag (admin) |
| `DELETE` | `/api/users/{id}` | Delete user (admin) |

HTML: `/login`, `/register`, `/admin/users`

## SCORM API

| Method | Path | Description |
|--------|------|-------------|
| `GET` | `/` | Package catalog (requires login when auth enabled) |
| `GET` | `/api/packages` | Package list JSON (public; no auth required) |
| `GET` | `/launch/{package_id}` | SCORM player |
| `GET` | `/content/{package_id}/{path}` | Package static files |
| `POST` | `/api/packages` | Upload ZIP (instructor/admin) |
| `DELETE` | `/api/packages/{id}` | Delete package |
| `GET/PUT` | `/api/scorm/{id}/cmi` | CMI for authenticated user |

## Environment variables

| Variable | Default | Description |
|----------|---------|-------------|
| `SCORMHOST_DATA_DIR` | `./data` | Packages, sessions, SQLite DB |
| `SCORMHOST_SECRET_KEY` | random per start | **Set in production** — JWT signing |
| `SCORMHOST_DATABASE_URL` | `sqlite:///<data>/scormhost.db` | SQLAlchemy URL |
| `SCORMHOST_REQUIRE_AUTH` | `false` | If `true`, login required to take courses (not just manage) |
| `SCORMHOST_ALLOW_REGISTRATION` | `true` | Public sign-up |
| `SCORMHOST_BOOTSTRAP_ADMIN_EMAIL` | — | Force admin role for matching email on register (only use with trusted registration; no email verification) |
| `SCORMHOST_API_PREFIX` | `` | URL prefix for all routes (e.g. `/scorm` behind a reverse proxy) |
| `SCORMHOST_ACCESS_TOKEN_MINUTES` | `30` | JWT access TTL |
| `SCORMHOST_REFRESH_TOKEN_DAYS` | `7` | Refresh token TTL |
| `SCORMHOST_COOKIE_SECURE` | `false` | Set `true` behind HTTPS |
| `SCORMHOST_AUTO_MIGRATE` | `true` | Run `alembic upgrade head` on startup |
| `SCORMHOST_ALLOW_UPLOAD` | `true` | Global upload toggle |
| `SCORMHOST_TITLE` | `SCORM Host` | Site title |

## Deploy to FastAPI Cloud

```bash
cd examples/cloud
pip install -r requirements.txt
fastapi login
fastapi deploy
```

Set `SCORMHOST_DATA_DIR`, `SCORMHOST_SECRET_KEY`, and `SCORMHOST_COOKIE_SECURE=true` in the dashboard. Always set a stable `SCORMHOST_SECRET_KEY` in production (do not rely on the random per-start default).

## Development

```bash
pip install -e ".[dev]"
ruff format .
ruff check .
ty check
pytest
```

Tests use `require_auth=False` for SCORM flows and a separate DB for auth tests. Migrations live in `src/scormhost/alembic/` and ship inside the wheel; `alembic upgrade head` from the repo root uses `alembic.ini`.

## Releasing

1. Ensure `pyproject.toml` and [CHANGELOG.md](CHANGELOG.md) match the target version.
2. Run `pytest`, `ruff check`, `ty check`, and `python -m build`.
3. Tag `v0.1.0` and publish the GitHub release (attach `dist/*` artifacts if publishing to PyPI manually).

## Limits (v0.1)

- SQLite by default (swap `SCORMHOST_DATABASE_URL` for Postgres in production)
- Package files remain on disk (not in the DB)
- cmi5 / xAPI launch not supported
- SCORM 2004 sequencing not enforced server-side

## License

Apache-2.0 — see [LICENSE](LICENSE).
