Metadata-Version: 2.4
Name: bocconi-sdk
Version: 0.3.1
Summary: Unofficial Python SDK for Bocconi University student services (yoU@B portal, Blackboard, Esse3)
Author: PEW Digital
License-Expression: MIT
Project-URL: Homepage, https://pewdigital.it
Keywords: bocconi,youatb,blackboard,esse3,university,student
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Education
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.31
Requires-Dist: websocket-client>=1.7
Requires-Dist: tzdata>=2024.1; platform_system == "Windows"
Dynamic: license-file

# Bocconi Software Development Kit

Unofficial Python SDK for **Bocconi University student services**. One
username/password login unlocks every subsystem through the shared SAML2 SSO
(`idp.unibocconi.it`). Reverse-engineered from live traffic.

> **Full API reference:** [docs.md](docs.md)

## Subsystems

| Package | System | What you get |
|---|---|---|
| `bocconi.youatb` | **yoU@B portal** (`youatb.unibocconi.it`) | Dashboard widgets (SignalR 2.x `widgethub`), lesson calendar JSON feed, profile/careers, language switching |
| `bocconi.youatb.puntoblu` | **Esse3 / PuntoBlu** (`www.pb.unibocconi.it`) | Student info, exam sessions, grades booklet, fees/certificates/… (HTML scraping) |
| `bocconi.blackboard` | **Blackboard** (`blackboard.unibocconi.it`) | Courses, deadlines/to-dos, messages, announcements, unread counters, activity stream |

## Install

**From PyPI** (recommended):

```powershell
pip install bocconi-sdk
```

```bash
pip install bocconi-sdk    # macOS / Linux
```

Requires Python ≥ 3.9. Dependencies (`requests`, `websocket-client`) are
installed automatically; on Windows a small tz database package (`tzdata`)
is pulled in as well.

**From source** (development):

```powershell
git clone https://github.com/PEW-Development/bocconi-sdk.git
cd bocconi-sdk
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -e .
```

## Quickstart — parent client (recommended)

```python
from datetime import date
from bocconi import BocconiClient

with BocconiClient("1234567", "your-password") as client:
    client.login()                       # one SAML login unlocks everything

    yt = client.youatb                   # yoU@B portal
    print(yt.profile.name, yt.student_id)
    widgets = yt.dashboard()             # SignalR widgethub
    for ev in yt.calendar(date(2026, 8, 31), date(2026, 9, 6)):
        print(ev.start, ev.course_name, ev.room)

    bb = client.blackboard               # Blackboard Ultra
    for course in bb.courses():
        print(course.display_id, course.name)
    for item in bb.todo().future:
        print(item.due_date, item.title)

    pb = yt.puntoblu                     # Esse3
    print(pb.student_info().degree_program)
    print(pb.exam_sessions()[:3])
```

## Standalone children

Each subsystem also works independently (own session, own login):

```python
from bocconi.youatb import YouAtBClient
from bocconi.blackboard import BlackboardClient

with YouAtBClient("1234567", "pw") as yt:
    yt.login()
    print(yt.calendar())

bb = BlackboardClient.authenticate("1234567", "pw")   # SAML via Blackboard's SP
print(bb.me())
```

Or attach children to an existing authenticated session:
`YouAtBClient.from_session(session)`, `BlackboardClient.from_session(session)`.

**Multi-account / no-password mode:** log in once, save the cookie blob, and
rebuild sessions from storage afterwards — ideal for connectors and API
backends that manage many accounts:

```python
blob = client.export_cookies()                  # JSON-safe list -> save to DB
client = BocconiClient.from_cookies(blob)       # no password, later process
```

## API overview

### `BocconiClient(username, password, lang="en")`

- `login()` / `logout()` / `close()` — context manager supported.
- `.youatb` → `YouAtBClient`, `.blackboard` → `BlackboardClient` (lazy).
- `fetch(url)` — GET any Bocconi SP URL with automatic SSO completion.

### `bocconi.youatb.YouAtBClient`

- `login()`, `profile` (name, photo, careers), `student_id`,
  `set_career(...)`, `set_language("ita"|"eng")`
- `dashboard(widget_ids=None)` / `load_widgets(ids)` → `WidgetResult`
  (`WidgetContent`: `.content_type`, `.url`, `.links`, `.text`; widget-ID
  constants exported from `bocconi.youatb`)
- `calendar(start=None, end=None)` → `list[CalendarEvent]` — typed lessons:
  course code/name, class, professors, room/building/floor, lat/lon, tz-aware
  Europe/Rome datetimes
- `.puntoblu` → `PuntoBluClient`

### `bocconi.youatb.puntoblu.PuntoBluClient`

- `student_info()` → `StudentInfo` (bilingual eng/ita, enrolment history)
- `exam_sessions()` → `list[ExamSession]` — dates, type (partial/general),
  enrolment windows, booking status/link
- `booklet()` → `list[BookletEntry]` — credits, year, status, grades
- `menu()`, `get(path)` + `PB_*` path constants; career interstitial handled
  automatically (`select_career(stu_id)`)

### `bocconi.blackboard.BlackboardClient`

- `me()` → `BbUser`; `courses()` / `recent_courses()` → `list[BbCourse]`
- `todo(since=None, until=None)` → `BbTodo` — actionable deadlines grouped
  `.overdue`/.`due_today`/`.future` (>15-day ranges auto-chunked)
- `calendar_items` / `deadlines(since, until)` → `list[BbCalendarItem]`
  (calendar view, keeps completed items)
- `announcements(course_id)`, `conversations(course_id)`,
  `message_summary()`, `announcement_counts` / `conversation_counts` /
  `unread_grades_count` / `discussion_unread_count(course_id)`
- `calendars()`, `terms()`, `course_membership(course_id)`, `stream()`,
  `system_preference(key)`, `entitlements()`, `api_get(path)`

## Notes & caveats

- The portal hub speaks **ASP.NET SignalR 2.x** (`clientProtocol=2.1`) — *not*
  ASP.NET Core SignalR; a minimal 2.x client is bundled
  (`bocconi.youatb.signalr.SignalR2Client`).
- Blackboard's SP sends the SAMLRequest via **HTTP-POST binding** — handled
  transparently by `bocconi.auth` for all services.
- Hub/Esse3 HTML fragments are **untrusted server-rendered markup**; the SDK
  never executes embedded scripts, `.text` strips tags.
- Sessions expire server-side; on `SessionExpiredError` call `login()` again.
- Unofficial project, not affiliated with Università Bocconi. Use
  responsibly: don't hammer the servers, don't share session cookies.

This SDK currently does not cover the full range of features offered by the Bocconi yoU@B/Blackboard ecosystem, so feel free to open a pull request

## License

**PEW Digital** (https://pewdigital.it) — MIT licensed. Free to use, copy
and modify by anyone; if you build your own version of this SDK, please
credit PEW Digital.

Run the full demo:

```powershell
$env:YOUATB_USER = "1234567"
$env:YOUATB_PASS = "your-password"
python examples/demo.py
```
