Files
microsoft-365-service/README.md
T
JiriUhlirandClaude Fable 5.1 d80193da8b Hlavicky X-MS365-* jako obycejne hodnoty, GET /users/{user_id}/calendar
- credentials: sifrovani AES-GCM/HKDF odstraneno, tri hlavicky se berou
  tak, jak jsou; bez hlavicek se pouziji hodnoty z prostredi
- zrusena promenna MS365_CREDENTIAL_ENCODING_SECRET a zavislost cryptography
- novy endpoint GET /users/{user_id}/calendar (objekt kalendare schranky,
  id a name) pro read-only overeni pristupu pres e-mail schranky
- C# ukazka posila hodnoty primo, CredentialEncoder smazan
- README: sekce o hlavickach vcetne PowerShell ukazky, zaznam zmen
- .gitignore: bin/ a obj/, zaverzovane obj/ soubory ukazky odstraneny z gitu

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 12:49:25 +02:00

168 lines
7.5 KiB
Markdown

# Microsoft 365 Service
FastAPI služba pro server-to-server komunikaci s Microsoft 365 přes Microsoft Graph.
## Konfigurace
V Microsoft Entra ID vytvořte app registration, přidělte požadovaná aplikační oprávnění pro Microsoft Graph a nastavte tyto environment proměnné:
```env
MS365_TENANT_ID=00000000-0000-0000-0000-000000000000
MS365_CLIENT_ID=00000000-0000-0000-0000-000000000000
MS365_CLIENT_SECRET=secret-value
MS365_GRAPH_BASE_URL=https://graph.microsoft.com/v1.0
MS365_GRAPH_SCOPE=https://graph.microsoft.com/.default
MS365_REQUEST_TIMEOUT_SECONDS=30
```
Služba používá OAuth2 client credentials flow, takže oprávnění pro Microsoft Graph musí být aplikační oprávnění schválená administrátorem.
## Credentials v request hlavičkách
Credentials se posílají v každém requestu v hlavičkách jako obyčejné hodnoty:
```http
X-MS365-Tenant-Id: <tenant id klienta>
X-MS365-Client-Id: <client id aplikace CSBOT>
X-MS365-Client-Secret: <client secret VALUE aplikace CSBOT, ne secret id>
```
Všechny tři hlavičky musí být pohromadě, jinak služba vrátí 400. Když se nepošle
žádná, použijí se `MS365_TENANT_ID`, `MS365_CLIENT_ID` a `MS365_CLIENT_SECRET`
z prostředí služby.
Příklad v PowerShellu:
```powershell
$Headers = @{
"X-MS365-Tenant-Id" = $TenantId
"X-MS365-Client-Id" = $ClientId
"X-MS365-Client-Secret" = $ClientSecret
}
Invoke-RestMethod -Method Get -Headers $Headers `
-Uri "https://services.csbot.cz/apps/microsoft-365-service/users/$UserMailbox/calendar"
```
## Multitenant napojení klientů (CSBOT MS365 Connector)
Služba je stavěná pro jednu multitenant Entra aplikaci CSBOT, přes kterou se připojují
Microsoft 365 tenanty jednotlivých klientů. Podrobné zadání je v Notion stránce
"MS365 práva konektoru".
- `MS365_CLIENT_ID` a `MS365_CLIENT_SECRET` patří aplikaci CSBOT a jsou pro všechny klienty stejné.
- `MS365_TENANT_ID` je tenant konkrétního klienta. Token se získává proti
`https://login.microsoftonline.com/{tenant klienta}/oauth2/v2.0/token`.
- Při volání za různé klienty se tenant id posílá v hlavičce `X-MS365-Tenant-Id`
(viz "Credentials v request hlavičkách"), client id a secret zůstávají stejné.
- Klient nevytváří vlastní App Registration ani nepředává secret. Jeho administrátor jen
schválí admin consent. URL pro consent vrací `GET /admin-consent/url?redirect_uri=...&state=...`
(bere tenant id a client id z hlaviček nebo z env). Callback po consentu (parametry `tenant`
a `admin_consent=True`) zpracovává backend CSBOT, ne tato služba.
- Služba je bezstavová a neověřuje, zda mailbox, plan id nebo bucket id patří danému
zákazníkovi. Tenant isolation (customer id -> tenant id, mailbox, plan id, bucket id)
musí držet volající backend, hodnoty nesmí přicházet přímo od LLM.
Postup testu po consentu klienta: `GET /status`, `GET /users/{mailbox}/calendar`
(vrátí id a name kalendáře, nejlevnější ověření přístupu), `GET /users/{mailbox}/calendar/view`,
`POST /users/{mailbox}/calendar/events` + `DELETE`, `GET /planner/plans/{plan_id}/tasks`,
`POST /planner/tasks` + `DELETE`.
## Implementované služby
- Users: výpis a načtení uživatelů.
- Mail: výpis zpráv a odesílání e-mailů včetně příloh.
- Calendar: načtení kalendáře schránky (id, name), výpis událostí, calendarView v zadaném rozsahu, volné termíny (getSchedule),
načtení, vytvoření, úprava a smazání události včetně Teams online meetingů.
- Planner: výpis plánů skupiny, bucketů a tasků plánu, načtení, vytvoření, úprava
a smazání tasku. Úprava a smazání používají ETag (`If-Match`). Když hlavička chybí,
služba si aktuální ETag načte sama.
- OneDrive: výpis souborů v rootu a upload malých souborů.
- Groups a Teams: výpis skupin a výpis kanálů týmu.
- Admin consent: sestavení consent URL pro administrátora klientského tenantu.
## API
```http
GET /health
GET /version
GET /status
GET /users?top=25&search=jane
GET /users/{user_id}
GET /users/{user_id}/mail/messages?folder=Inbox&top=25
POST /users/{user_id}/mail/send
GET /admin-consent/url?redirect_uri=...&state=...
GET /users/{user_id}/calendar
GET /users/{user_id}/calendar/events?top=25
POST /users/{user_id}/calendar/events
GET /users/{user_id}/calendar/view?start=...&end=...&top=25&time_zone=Europe/Prague
POST /users/{user_id}/calendar/schedule
GET /users/{user_id}/calendar/events/{event_id}
PATCH /users/{user_id}/calendar/events/{event_id}
DELETE /users/{user_id}/calendar/events/{event_id}
GET /users/{user_id}/drive/root/children?top=25
PUT /users/{user_id}/drive/root/{path}
GET /groups?top=25
GET /groups/{group_id}/planner/plans
GET /teams/{team_id}/channels
GET /planner/plans/{plan_id}/buckets
GET /planner/plans/{plan_id}/tasks
POST /planner/tasks
GET /planner/tasks/{task_id}
PATCH /planner/tasks/{task_id} (volitelně hlavička If-Match)
DELETE /planner/tasks/{task_id} (volitelně hlavička If-Match)
```
Parametry `start` a `end` u calendarView jsou ISO 8601 s offsetem, například
`2026-09-08T08:00:00+02:00`. Datumy u Planneru (`due_date_time`, `start_date_time`)
jsou ISO 8601 s offsetem, například `2026-09-10T16:00:00Z`. Řešitelé se předávají
jako Graph user id v `assign_user_ids`, odebírají v `unassign_user_ids`.
`user_id` může být Microsoft Graph user id nebo user principal name, například `jane@example.com`.
## Požadovaná Graph oprávnění
Přidělte pouze oprávnění, která dané nasazení skutečně používá:
- Users: `User.Read.All`
- Čtení mailů: `Mail.Read`
- Odesílání mailů: `Mail.Send`
- Čtení a zápis do kalendáře, calendarView, getSchedule: `Calendars.ReadWrite`
- Planner: `Tasks.ReadWrite.All` (zahrnuje i čtení, `Tasks.Read.All` netřeba)
- Čtení a zápis do OneDrive: `Files.ReadWrite.All`
- Výpis skupin a Teams kanálů: `Group.Read.All`, `Team.ReadBasic.All`, `Channel.ReadBasic.All`
Pro konektor CSBOT (Calendar + Planner) je minimum `Calendars.ReadWrite` a `Tasks.ReadWrite.All`,
obě jako Application permissions. `Calendars.ReadWrite` platí na všechny mailboxy tenantu,
omezení na konkrétní mailbox se řeší na straně klienta v Exchange Online
(application access policy), ne v této službě.
## Ukázky pro klienty
- `examples/csharp/ListUsersTop10`: konzolová aplikace .NET 8, volá `GET /users?top=10`
s hlavičkami `X-MS365-*`. Popis v `examples/csharp/README.md`.
## Lokální spuštění
```bash
pip install -r requirements.txt
uvicorn app.main:app --reload
```
Vygenerované OpenAPI UI otevřete na `http://localhost:8000/docs`.
# job queue test Thu May 28 02:12:07 PM CEST 2026
# job queue test Thu May 28 02:12:28 PM CEST 2026
# websocket logs test Fri May 29 11:03:58 AM CEST 2026
## Záznam změn
- 2026-09-22: šifrování hlaviček `X-MS365-*` odstraněno, hodnoty se posílají tak, jak jsou.
Zrušena proměnná `MS365_CREDENTIAL_ENCODING_SECRET` a závislost `cryptography`.
- 2026-09-22: `GET /users/{user_id}/calendar` (objekt kalendáře schránky, id a name) pro
read-only ověření přístupu ke kalendáři klienta přes e-mail schránky.
- 2026-09-09: verze 1.1.0. Podle Notion zadání "MS365 práva konektoru" doplněn Calendar
(calendarView, getSchedule, get/patch/delete události), Planner (plány, buckety, tasky,
create/patch/delete s ETag) a `GET /admin-consent/url`. Kód ověřen jen importem aplikace
a serializací schémat, proti reálnému tenantu netestováno (chybí DEV App Registration).
- 2026-09-09: přidána C# ukázka `examples/csharp/ListUsersTop10` (top 10 z `/users`).