- 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>
168 lines
7.5 KiB
Markdown
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`).
|