Menü aufrufen
Toggle preferences menu
Persönliches Menü aufrufen
Nicht angemeldet
Ihre IP-Adresse wird öffentlich sichtbar sein, wenn Sie Änderungen vornehmen.

DriversHub: Unterschied zwischen den Versionen

Aus Kosmos MediaWiki
Die Seite wurde neu angelegt: „# Drivers Hub Backend – API-Dokumentation Repository: `CharlesWithC/HubBackend` ## 1. API-Grundlagen ### Base URL Die API besitzt **keine fest eingebaute öffentliche Base URL**. Host und API-Prefix kommen aus der Hub-Konfiguration. Beispielkonfiguration: ```json { "domain": "hub.example.com", "prefix": "/api" } ``` Damit lautet die Base URL: ```text https://hub.example.com/api ``` Ein Request auf: ```text GET /user/profile ``` wird also…“
 
Keine Bearbeitungszusammenfassung
 
Zeile 1: Zeile 1:
# Drivers Hub Backend – API-Dokumentation
= API-Dokumentation =
Repository: <code>CharlesWithC/HubBackend</code>


Repository: `CharlesWithC/HubBackend`
== 1. API-Grundlagen ==


## 1. API-Grundlagen
=== Base URL ===
 
Die API besitzt '''keine fest eingebaute öffentliche Base URL'''. Host und API-Prefix kommen aus der Hub-Konfiguration.
### Base URL
 
Die API besitzt **keine fest eingebaute öffentliche Base URL**. Host und API-Prefix kommen aus der Hub-Konfiguration.


Beispielkonfiguration:
Beispielkonfiguration:
 
<code>{
```json
  "domain": "hub.example.com",
{
  "prefix": "/api"
  "domain": "hub.example.com",
}</code>
  "prefix": "/api"
}
```
 
Damit lautet die Base URL:
Damit lautet die Base URL:
 
<code><nowiki>https://hub.example.com/api</nowiki></code>
```text
https://hub.example.com/api
```
 
Ein Request auf:
Ein Request auf:
 
<code>GET /user/profile</code>
```text
GET /user/profile
```
 
wird also beispielsweise:
wird also beispielsweise:
<code>GET <nowiki>https://hub.example.com/api/user/profile</nowiki></code>
Der Prefix ist konfigurierbar und muss mit <code>/</code> beginnen.


```text
=== Swagger / OpenAPI ===
GET https://hub.example.com/api/user/profile
```
 
Der Prefix ist konfigurierbar und muss mit `/` beginnen.
 
### Swagger / OpenAPI
 
Wenn in der Konfiguration
Wenn in der Konfiguration
 
<code>{
```json
  "openapi": true
{
}</code>
  "openapi": true
}
```
 
gesetzt wird, stellt der Server die interaktive Swagger-Dokumentation unter
gesetzt wird, stellt der Server die interaktive Swagger-Dokumentation unter
 
<code>{prefix}/doc</code>
```text
{prefix}/doc
```
 
bereit.
bereit.


Bei `prefix: "/api"` also:
Bei <code>prefix: "/api"</code> also:
 
<code><nowiki>https://hub.example.com/api/doc</nowiki></code>
```text
https://hub.example.com/api/doc
```
 
Im Repository liegt außerdem:
Im Repository liegt außerdem:
<code>/openapi.json</code>
----


```text
= 2. Authentifizierung =
/openapi.json
```
 
---
 
# 2. Authentifizierung
 
Es gibt zwei Token-Typen:
Es gibt zwei Token-Typen:


1. **Bearer Token** – für Benutzer
# '''Bearer Token''' – für Benutzer
2. **Application Token** – für Anwendungen/Integrationen
# '''Application Token''' – für Anwendungen/Integrationen
 
## Bearer Token


== Bearer Token ==
Header:
Header:
 
<code>Authorization: Bearer <TOKEN></code>
```http
Authorization: Bearer <TOKEN>
```
 
Beispiel:
Beispiel:
 
<code>curl \
```bash
  -H "Authorization: Bearer e1234567-89ab-cdef-0123-456789abcdef" \
curl \
  <nowiki>https://hub.example.com/api/user/profile</nowiki></code>
  -H "Authorization: Bearer e1234567-89ab-cdef-0123-456789abcdef" \
  https://hub.example.com/api/user/profile
```
 
Tokens sind UUID-artige, serverseitig gespeicherte Session-Tokens. Es steckt kein JWT-Payload darin.
Tokens sind UUID-artige, serverseitig gespeicherte Session-Tokens. Es steckt kein JWT-Payload darin.


## Application Token
== Application Token ==
 
Header:
Header:
 
<code>Authorization: Application <TOKEN></code>
```http
Authorization: Application <TOKEN>
```
 
Beispiel:
Beispiel:
 
<code>curl \
```bash
  -H "Authorization: Application 12345678-1234-1234-1234-123456789abc" \
curl \
  <nowiki>https://hub.example.com/api/user/profile</nowiki></code>
  -H "Authorization: Application 12345678-1234-1234-1234-123456789abc" \
  https://hub.example.com/api/user/profile
```
 
Application Tokens haben gegenüber normalen User-Tokens Einschränkungen. Nicht jeder authentifizierte Endpoint muss Application Tokens akzeptieren.
Application Tokens haben gegenüber normalen User-Tokens Einschränkungen. Nicht jeder authentifizierte Endpoint muss Application Tokens akzeptieren.
----


---
= 3. Allgemeine Request-Regeln =
 
Für praktisch alle Requests außer <code>GET</code> erwartet das Backend:
# 3. Allgemeine Request-Regeln
<code>Content-Type: application/json</code>
 
Für praktisch alle Requests außer `GET` erwartet das Backend:
 
```http
Content-Type: application/json
```
 
Ausnahmen sind insbesondere Tracker-Webhooks:
Ausnahmen sind insbesondere Tracker-Webhooks:
 
<code>/tracksim/*
```text
/trucky/*
/tracksim/*
/custom-tracker/*
/trucky/*
/unitracker/*</code>
/custom-tracker/*
/unitracker/*
```
 
Diese dürfen tracker-spezifische Payloads verwenden.
Diese dürfen tracker-spezifische Payloads verwenden.


Standard-JSON-Request:
Standard-JSON-Request:
<code>curl -X PATCH \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"John Doe"}' \
  "$BASE/user/profile"</code>


```bash
== Fehlerformat ==
curl -X PATCH \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"John Doe"}' \
  "$BASE/user/profile"
```
 
## Fehlerformat
 
FastAPI-/HTTP-Fehler werden grundsätzlich in dieser Art zurückgegeben:
FastAPI-/HTTP-Fehler werden grundsätzlich in dieser Art zurückgegeben:
 
<code>{
```json
  "error": "Fehlermeldung"
{
}</code>
  "error": "Fehlermeldung"
}
```
 
Typische Statuscodes sind:
Typische Statuscodes sind:
 
<code>400  Bad Request
```text
401  Unauthorized
400  Bad Request
403  Forbidden
401  Unauthorized
404  Not Found
403  Forbidden
409  Conflict
404  Not Found
422  Unprocessable Entity
409  Conflict
423  Locked
422  Unprocessable Entity
428  Precondition Required
423  Locked
429  Too Many Requests
428  Precondition Required
500  Internal Server Error
429  Too Many Requests
503  Service Unavailable</code>
500  Internal Server Error
503  Service Unavailable
```
 
Bei Request-Validation wird die normale ausführliche FastAPI-422-Antwort durch:
Bei Request-Validation wird die normale ausführliche FastAPI-422-Antwort durch:
 
<code>{
```json
  "error": "Unprocessable Entity"
{
}</code>
  "error": "Unprocessable Entity"
}
```
 
ersetzt.
ersetzt.
----


---
= 4. Rate Limits =
 
# 4. Rate Limits
 
Es gibt globale und endpoint-spezifische Rate Limits.
Es gibt globale und endpoint-spezifische Rate Limits.


Global:
Global:
 
<code>300 Requests / 60 Sekunden</code>
```text
300 Requests / 60 Sekunden
```
 
Nach Überschreiten kann der Client für etwa fünf Minuten global blockiert werden.
Nach Überschreiten kann der Client für etwa fünf Minuten global blockiert werden.


Zusätzlich besitzen einzelne Endpoints eigene Limits.
Zusätzlich besitzen einzelne Endpoints eigene Limits.


Beispiel aus `/auth/password`:
Beispiel aus <code>/auth/password</code>:
 
<code>3 Requests / 60 Sekunden</code>
```text
----
3 Requests / 60 Sekunden
```
 
---
 
# 5. Benutzer-IDs: `uid` vs. `userid`


= 5. Benutzer-IDs: <code>uid</code> vs. <code>userid</code> =
Das ist für Clients besonders wichtig.
Das ist für Clients besonders wichtig.


### `uid`
=== <code>uid</code> ===
 
Interne, eindeutige User-ID.
Interne, eindeutige User-ID.


Jeder Account besitzt eine `uid`.
Jeder Account besitzt eine <code>uid</code>.
 
### `userid`


=== <code>userid</code> ===
Mitglieds-/Driver-Hub-ID.
Mitglieds-/Driver-Hub-ID.


Zeile 221: Zeile 128:


Daher können APIs je nach Einsatzzweck entweder:
Daher können APIs je nach Einsatzzweck entweder:
 
<code>uid</code>
```text
uid
```
 
oder
oder
 
<code>userid</code>
```text
userid
```
 
verlangen.
verlangen.
----


---
= 6. Login und Authentifizierungsflow =
 
# 6. Login und Authentifizierungsflow
 
## POST `/auth/password`


== POST <code>/auth/password</code> ==
Login mit E-Mail und Passwort.
Login mit E-Mail und Passwort.


### Body
=== Body ===
 
<code>{
```json
  "email": "user@example.com",
{
  "password": "Secret123!",
  "email": "user@example.com",
  "captcha-response": "<captcha-token>"
  "password": "Secret123!",
}</code>
  "captcha-response": "<captcha-token>"
<code>captcha-response</code> sollte als '''erforderlich''' betrachtet werden, auch wenn die OpenAPI-Datei es nicht sauber als required kennzeichnet.
}
```
 
`captcha-response` sollte als **erforderlich** betrachtet werden, auch wenn die OpenAPI-Datei es nicht sauber als required kennzeichnet.


Unterstützte Captcha-Systeme:
Unterstützte Captcha-Systeme:
<code>Cloudflare Turnstile
hCaptcha</code>


```text
=== Erfolgreicher Login ohne MFA ===
Cloudflare Turnstile
<code>{
hCaptcha
  "token": "e....",
```
  "mfa": false
 
}</code>
### Erfolgreicher Login ohne MFA
 
```json
{
  "token": "e....",
  "mfa": false
}
```
 
### Login mit aktiviertem MFA
 
```json
{
  "token": "f....",
  "mfa": true
}
```


=== Login mit aktiviertem MFA ===
<code>{
  "token": "f....",
  "mfa": true
}</code>
Der zurückgegebene Token ist in diesem Fall zunächst ein temporäres Auth-Ticket.
Der zurückgegebene Token ist in diesem Fall zunächst ein temporäres Auth-Ticket.


Danach:
Danach:
 
<code>POST /auth/mfa</code>
```http
POST /auth/mfa
```
 
Body:
Body:
 
<code>{
```json
  "token": "<temporary-auth-ticket>",
{
  "otp": "123456"
  "token": "<temporary-auth-ticket>",
}</code>
  "otp": "123456"
}
```
 
Danach erhält man den eigentlichen Session-Token.
Danach erhält man den eigentlichen Session-Token.
----


---
== POST <code>/auth/register</code> ==
 
## POST `/auth/register`
 
Registriert einen Account per E-Mail/Passwort.
Registriert einen Account per E-Mail/Passwort.


Body:
Body:
 
<code>{
```json
  "email": "user@example.com",
{
  "password": "Secret123!",
  "email": "user@example.com",
  "captcha-response": "<captcha-token>"
  "password": "Secret123!",
}</code>
  "captcha-response": "<captcha-token>"
}
```
 
Das Passwort muss mindestens acht Zeichen lang sein. Die konkrete Prüfung berücksichtigt außerdem Groß-/Kleinbuchstaben, Zahlen und Sonderzeichen.
Das Passwort muss mindestens acht Zeichen lang sein. Die konkrete Prüfung berücksichtigt außerdem Groß-/Kleinbuchstaben, Zahlen und Sonderzeichen.


Zeile 319: Zeile 188:


Bei Erfolg wird bereits ein Session-Token ausgegeben:
Bei Erfolg wird bereits ein Session-Token ausgegeben:
<code>{
  "token": "e....",
  "mfa": false
}</code>
----


```json
== POST <code>/auth/reset</code> ==
{
  "token": "e....",
  "mfa": false
}
```
 
---
 
## POST `/auth/reset`
 
Startet einen Password-Reset.
Startet einen Password-Reset.
<code>{
  "email": "user@example.com",
  "captcha-response": "<captcha-token>"
}</code>
----


```json
== POST <code>/auth/email</code> ==
{
  "email": "user@example.com",
  "captcha-response": "<captcha-token>"
}
```
 
---
 
## POST `/auth/email`
 
Verarbeitet E-Mail-Bestätigungs-/Reset-Links.
Verarbeitet E-Mail-Bestätigungs-/Reset-Links.


Query:
Query:
 
<code>?secret=<SECRET></code>
```text
?secret=<SECRET>
```
 
Bei Password-Reset ggf. Body:
Bei Password-Reset ggf. Body:
<code>{
  "password": "NewSecret123!"
}</code>
----


```json
== Discord / Steam Login ==
{
  "password": "NewSecret123!"
}
```
 
---
 
## Discord / Steam Login
 
### GET `/auth/discord/callback`


=== GET <code>/auth/discord/callback</code> ===
Queryparameter:
Queryparameter:
<code>code
error_description
callback_url</code>
<code>callback_url</code> ist erforderlich.


```text
=== GET <code>/auth/steam/callback</code> ===
code
error_description
callback_url
```
 
`callback_url` ist erforderlich.
 
### GET `/auth/steam/callback`
 
Steam-OpenID-Callback.
Steam-OpenID-Callback.


Die von Steam gelieferten Parameter müssen an diesen Endpoint weitergereicht werden.
Die von Steam gelieferten Parameter müssen an diesen Endpoint weitergereicht werden.
----


---
= 7. Token API =
 
{| class="wikitable"
# 7. Token API
!Method
 
!Endpoint
| Method | Endpoint                 | Funktion                               |
!Funktion
| ------ | ------------------------- | --------------------------------------- |
|-
| GET   | `/token`                  | aktuellen Token validieren             |
|GET
| PATCH | `/token`                  | aktuellen Token erneuern               |
|<code>/token</code>
| DELETE | `/token`                  | aktuellen Token widerrufen             |
|aktuellen Token validieren
| GET   | `/token/list`            | Sessions/Tokens auflisten               |
|-
| DELETE | `/token/hash`            | bestimmten Token anhand Hash widerrufen |
|PATCH
| DELETE | `/token/all`              | alle Benutzer-Tokens widerrufen         |
|<code>/token</code>
| GET   | `/token/application/list` | Application Tokens auflisten           |
|aktuellen Token erneuern
| POST   | `/token/application`      | Application Token erzeugen             |
|-
| DELETE | `/token/application`      | Application Token widerrufen           |
|DELETE
| DELETE | `/token/application/all| alle Application Tokens widerrufen     |
|<code>/token</code>
| POST   | `/auth/ticket`            | Auth-Ticket erzeugen/verwenden         |
|aktuellen Token widerrufen
| GET   | `/auth/ticket`            | Auth-Ticket abrufen                     |
|-
 
|GET
|<code>/token/list</code>
|Sessions/Tokens auflisten
|-
|DELETE
|<code>/token/hash</code>
|bestimmten Token anhand Hash widerrufen
|-
|DELETE
|<code>/token/all</code>
|alle Benutzer-Tokens widerrufen
|-
|GET
|<code>/token/application/list</code>
|Application Tokens auflisten
|-
|POST
|<code>/token/application</code>
|Application Token erzeugen
|-
|DELETE
|<code>/token/application</code>
|Application Token widerrufen
|-
|DELETE
|<code>/token/application/all</code>
|alle Application Tokens widerrufen
|-
|POST
|<code>/auth/ticket</code>
|Auth-Ticket erzeugen/verwenden
|-
|GET
|<code>/auth/ticket</code>
|Auth-Ticket abrufen
|}
Beispiel Token-Validierung:
Beispiel Token-Validierung:
 
<code>curl \
```bash
  -H "Authorization: Bearer $TOKEN" \
curl \
  "$BASE/token"</code>
  -H "Authorization: Bearer $TOKEN" \
  "$BASE/token"
```
 
Tokenliste unterstützt unter anderem:
Tokenliste unterstützt unter anderem:
<code>page
page_size
order_by
order</code>
Mögliche <code>order_by</code>-Werte laut OpenAPI:
<code>ip
timestamp
country_code
user_agent
last_used_timestamp</code>
----


```text
= 8. System-/Info-API =
page
{| class="wikitable"
page_size
!Method
order_by
!Endpoint
order
!Funktion
```
|-
 
|GET
Mögliche `order_by`-Werte laut OpenAPI:
|<code>/</code>
 
|Drivers-Hub-Informationen
```text
|-
ip
|GET
timestamp
|<code>/status</code>
country_code
|Serverstatus
user_agent
|-
last_used_timestamp
|POST
```
|<code>/status/database/restart</code>
 
|Datenbankverbindung neu starten
---
|-
 
|GET
# 8. System-/Info-API
|<code>/languages</code>
 
|Hub- und unterstützte Sprachen
| Method | Endpoint                           | Funktion                             |
|-
| ------ | ---------------------------------- | ------------------------------------ |
|POST
| GET   | `/`                                | Drivers-Hub-Informationen           |
|<code>/discord/role-connection/enable</code>
| GET   | `/status`                          | Serverstatus                         |
|Discord Role Connection aktivieren
| POST   | `/status/database/restart`        | Datenbankverbindung neu starten     |
|-
| GET   | `/languages`                      | Hub- und unterstützte Sprachen       |
|POST
| POST   | `/discord/role-connection/enable| Discord Role Connection aktivieren   |
|<code>/discord/role-connection/disable</code>
| POST   | `/discord/role-connection/disable` | Discord Role Connection deaktivieren |
|Discord Role Connection deaktivieren
| GET   | `/config`                          | Konfiguration lesen                 |
|-
| PATCH | `/config`                          | Konfiguration ändern                 |
|GET
| POST   | `/config/reload`                  | Konfiguration neu laden             |
|<code>/config</code>
| POST   | `/restart`                        | Backend neu starten                 |
|Konfiguration lesen
| GET   | `/audit/list`                      | Audit-Log abrufen                   |
|-
 
|PATCH
|<code>/config</code>
|Konfiguration ändern
|-
|POST
|<code>/config/reload</code>
|Konfiguration neu laden
|-
|POST
|<code>/restart</code>
|Backend neu starten
|-
|GET
|<code>/audit/list</code>
|Audit-Log abrufen
|}
Administrative Endpoints sind entsprechend permission-geschützt.
Administrative Endpoints sind entsprechend permission-geschützt.
----


---
= 9. User API =


# 9. User API
== Profile und Benutzer ==
 
{| class="wikitable"
## Profile und Benutzer
!Method
 
!Endpoint
| Method | Endpoint                 | Funktion                   |
!Funktion
| ------ | ------------------------- | --------------------------- |
|-
| GET   | `/user/list`              | Benutzerliste               |
|GET
| GET   | `/user/profile`          | Userprofil abrufen         |
|<code>/user/list</code>
| PATCH | `/user/profile`          | Name/Avatar ändern         |
|Benutzerliste
| PATCH | `/user/bio`              | Bio ändern                 |
|-
| PATCH | `/user/activity`          | Aktivitätsdaten ändern     |
|GET
| PATCH | `/user/{uid}/note`        | persönliche Notiz über User |
|<code>/user/profile</code>
| PATCH | `/user/{uid}/note/global` | globale Staff-Notiz         |
|Userprofil abrufen
| POST   | `/user/tracker/switch`    | aktiven Tracker wechseln   |
|-
 
|PATCH
### GET `/user/profile`
|<code>/user/profile</code>
|Name/Avatar ändern
|-
|PATCH
|<code>/user/bio</code>
|Bio ändern
|-
|PATCH
|<code>/user/activity</code>
|Aktivitätsdaten ändern
|-
|PATCH
|<code>/user/{uid}/note</code>
|persönliche Notiz über User
|-
|PATCH
|<code>/user/{uid}/note/global</code>
|globale Staff-Notiz
|-
|POST
|<code>/user/tracker/switch</code>
|aktiven Tracker wechseln
|}


=== GET <code>/user/profile</code> ===
Kann einen Benutzer anhand verschiedener IDs suchen:
Kann einen Benutzer anhand verschiedener IDs suchen:
 
<code>userid
```text
uid
userid
discordid
uid
steamid
discordid
truckersmpid
steamid
email</code>
truckersmpid
email
```
 
Zusätzliche Parameter:
Zusätzliche Parameter:
 
<code>role_history_limit
```text
ban_history_limit</code>
role_history_limit
ban_history_limit
```
 
Ohne Ziel-ID wird typischerweise das eigene Profil verwendet.
Ohne Ziel-ID wird typischerweise das eigene Profil verwendet.


Beispiel:
Beispiel:
 
<code>curl \
```bash
  -H "Authorization: Bearer $TOKEN" \
curl \
  "$BASE/user/profile?uid=123"</code>
  -H "Authorization: Bearer $TOKEN" \
  "$BASE/user/profile?uid=123"
```
 
Oder:
Oder:
<code>curl \
  -H "Authorization: Bearer $TOKEN" \
  "$BASE/user/profile?discordid=123456789012345678"</code>


```bash
=== PATCH <code>/user/profile</code> ===
curl \
  -H "Authorization: Bearer $TOKEN" \
  "$BASE/user/profile?discordid=123456789012345678"
```
 
### PATCH `/user/profile`
 
Body:
Body:
 
<code>{
```json
  "name": "New Name",
{
  "avatar": "<nowiki>https://example.com/avatar.png</nowiki>"
  "name": "New Name",
}</code>
  "avatar": "https://example.com/avatar.png"
}
```
 
Optionale Queryparameter:
Optionale Queryparameter:
 
<code>uid
```text
sync_from_discord
uid
sync_from_steam
sync_from_discord
sync_from_truckersmp</code>
sync_from_steam
sync_from_truckersmp
```
 
Damit können Profildaten auch von verbundenen Plattformen synchronisiert werden.
Damit können Profildaten auch von verbundenen Plattformen synchronisiert werden.
----


---
= 10. Sprache, Zeitzone und Privacy =
 
{| class="wikitable"
# 10. Sprache, Zeitzone und Privacy
!Method
 
!Endpoint
| Method | Endpoint         | Funktion                     |
!Funktion
| ------ | ---------------- | ---------------------------- |
|-
| GET   | `/user/language` | aktuelle Sprache             |
|GET
| PATCH | `/user/language` | Sprache ändern               |
|<code>/user/language</code>
| GET   | `/user/timezone` | Zeitzone lesen               |
|aktuelle Sprache
| PATCH | `/user/timezone` | Zeitzone ändern             |
|-
| GET   | `/user/privacy| Privacy-Einstellungen       |
|PATCH
| PATCH | `/user/privacy| Privacy-Einstellungen ändern |
|<code>/user/language</code>
 
|Sprache ändern
---
|-
 
|GET
# 11. Password und MFA
|<code>/user/timezone</code>
 
|Zeitzone lesen
| Method | Endpoint                | Funktion                    |
|-
| ------ | ------------------------ | --------------------------- |
|PATCH
| PATCH  | `/user/password`        | Passwort ändern            |
|<code>/user/timezone</code>
| POST  | `/user/password/disable` | Password-Login deaktivieren |
|Zeitzone ändern
| POST  | `/user/mfa/enable`      | TOTP-MFA aktivieren        |
|-
| POST  | `/user/mfa/disable`      | MFA deaktivieren            |
|GET
|<code>/user/privacy</code>
|Privacy-Einstellungen
|-
|PATCH
|<code>/user/privacy</code>
|Privacy-Einstellungen ändern
|}
----


= 11. Password und MFA =
{| class="wikitable"
!Method
!Endpoint
!Funktion
|-
|PATCH
|<code>/user/password</code>
|Passwort ändern
|-
|POST
|<code>/user/password/disable</code>
|Password-Login deaktivieren
|-
|POST
|<code>/user/mfa/enable</code>
|TOTP-MFA aktivieren
|-
|POST
|<code>/user/mfa/disable</code>
|MFA deaktivieren
|}
TOTP-MFA wird bei jedem Login verwendet.
TOTP-MFA wird bei jedem Login verwendet.


Für besonders kritische administrative Aktionen, insbesondere Config-Reload, kann MFA verpflichtend sein.
Für besonders kritische administrative Aktionen, insbesondere Config-Reload, kann MFA verpflichtend sein.
----


---
= 12. User Connections =
 
{| class="wikitable"
# 12. User Connections
!Method
 
!Endpoint
| Method | Endpoint                               | Funktion                         |
!Funktion
| ------ | -------------------------------------- | -------------------------------- |
|-
| POST   | `/user/resend-confirmation`            | Bestätigungsmail erneut senden   |
|POST
| PATCH | `/user/email`                          | E-Mail verbinden/ändern         |
|<code>/user/resend-confirmation</code>
| PATCH | `/user/discord`                        | Discord verbinden               |
|Bestätigungsmail erneut senden
| PATCH | `/user/steam`                          | Steam verbinden                 |
|-
| PATCH | `/user/truckersmp`                    | TruckersMP verbinden             |
|PATCH
| PATCH | `/user/{uid}/connections`              | Connections administrativ ändern |
|<code>/user/email</code>
| DELETE | `/user/{uid}/connections/{connection}` | Connection entfernen             |
|E-Mail verbinden/ändern
 
|-
|PATCH
|<code>/user/discord</code>
|Discord verbinden
|-
|PATCH
|<code>/user/steam</code>
|Steam verbinden
|-
|PATCH
|<code>/user/truckersmp</code>
|TruckersMP verbinden
|-
|PATCH
|<code>/user/{uid}/connections</code>
|Connections administrativ ändern
|-
|DELETE
|<code>/user/{uid}/connections/{connection}</code>
|Connection entfernen
|}
Für das Job-Tracking ist insbesondere eine verbundene Steam-ID relevant.
Für das Job-Tracking ist insbesondere eine verbundene Steam-ID relevant.
----


---
= 13. Notifications =
 
{| class="wikitable"
# 13. Notifications
!Method
 
!Endpoint
| Method | Endpoint                                                 | Funktion               |
!Funktion
| ------ | --------------------------------------------------------- | ----------------------- |
|-
| GET   | `/user/notification/list`                                | Notifications auflisten |
|GET
| GET   | `/user/notification/{notificationid}`                    | Notification lesen     |
|<code>/user/notification/list</code>
| DELETE | `/user/notification`                                      | Notification(s) löschen |
|Notifications auflisten
| PATCH | `/user/notification/{notificationid}/status/{status}`    | Status ändern           |
|-
| GET   | `/user/notification/settings`                            | Notification Settings   |
|GET
| POST   | `/user/notification/settings/{notification_type}/enable| Typ aktivieren         |
|<code>/user/notification/{notificationid}</code>
| POST   | `/user/notification/settings/{notification_type}/disable` | Typ deaktivieren       |
|Notification lesen
 
|-
---
|DELETE
 
|<code>/user/notification</code>
# 14. User Administration / Bans
|Notification(s) löschen
 
|-
| Method | Endpoint                        | Funktion                          |
|PATCH
| ------ | ------------------------------- | --------------------------------- |
|<code>/user/notification/{notificationid}/status/{status}</code>
| POST  | `/user/{uid}/accept`            | Benutzer als Mitglied akzeptieren |
|Status ändern
| DELETE | `/user/{uid}`                  | Benutzer löschen                  |
|-
| GET    | `/user/ban/list`                | Bannliste                        |
|GET
| GET    | `/user/ban`                    | Banninformationen                |
|<code>/user/notification/settings</code>
| PUT    | `/user/ban`                    | Bann erstellen                    |
|Notification Settings
| DELETE | `/user/ban`                    | Bann entfernen                    |
|-
| DELETE | `/user/ban/history/{historyid}` | Bann-History-Eintrag löschen      |
|POST
|<code>/user/notification/settings/{notification_type}/enable</code>
|Typ aktivieren
|-
|POST
|<code>/user/notification/settings/{notification_type}/disable</code>
|Typ deaktivieren
|}
----


= 14. User Administration / Bans =
{| class="wikitable"
!Method
!Endpoint
!Funktion
|-
|POST
|<code>/user/{uid}/accept</code>
|Benutzer als Mitglied akzeptieren
|-
|DELETE
|<code>/user/{uid}</code>
|Benutzer löschen
|-
|GET
|<code>/user/ban/list</code>
|Bannliste
|-
|GET
|<code>/user/ban</code>
|Banninformationen
|-
|PUT
|<code>/user/ban</code>
|Bann erstellen
|-
|DELETE
|<code>/user/ban</code>
|Bann entfernen
|-
|DELETE
|<code>/user/ban/history/{historyid}</code>
|Bann-History-Eintrag löschen
|}
Das „Akzeptieren“ eines Users ist unabhängig vom Application-Plugin.
Das „Akzeptieren“ eines Users ist unabhängig vom Application-Plugin.
----


---
= 15. Member API =
 
# 15. Member API
 
## Informationen
 
| Method | Endpoint        | Funktion        |
| ------ | ---------------- | ---------------- |
| GET    | `/member/roles`  | Rollen          |
| GET    | `/member/ranks`  | Ranks            |
| GET    | `/member/perms`  | Permissions      |
| GET    | `/member/list`  | Mitgliederliste  |
| GET    | `/member/banner` | Mitgliederbanner |
 
## Eigene Member-Aktionen
 
| Method | Endpoint                              | Funktion                          |
| ------ | ------------------------------------- | --------------------------------- |
| PATCH  | `/member/roles/rank`                  | Default Rank-Rolle ändern        |
| PATCH  | `/member/roles/rank/{rank_type_id}`  | Rank-Rolle bestimmten Typs ändern |
| GET    | `/member/bonus/history`              | Bonus-History                    |
| POST  | `/member/bonus/claim`                | Bonus beanspruchen                |
| GET    | `/member/bonus/notification/settings` | Bonus-Notification-Settings      |
| PATCH  | `/member/bonus/notification/settings` | Settings ändern                  |
| DELETE | `/member/roles/history/{historyid}`  | Rollen-History löschen            |
| POST  | `/member/resign`                      | Mitgliedschaft niederlegen        |
 
## Member Administration
 
| Method | Endpoint                  | Funktion          |
| ------ | -------------------------- | ------------------ |
| PATCH  | `/member/{userid}/roles`  | Rollen ändern      |
| PATCH  | `/member/{userid}/points`  | Punkte ändern      |
| POST  | `/member/{userid}/dismiss` | Mitglied entlassen |


---
== Informationen ==
{| class="wikitable"
!Method
!Endpoint
!Funktion
|-
|GET
|<code>/member/roles</code>
|Rollen
|-
|GET
|<code>/member/ranks</code>
|Ranks
|-
|GET
|<code>/member/perms</code>
|Permissions
|-
|GET
|<code>/member/list</code>
|Mitgliederliste
|-
|GET
|<code>/member/banner</code>
|Mitgliederbanner
|}


# 16. Driving Logs – `/dlog`
== Eigene Member-Aktionen ==
{| class="wikitable"
!Method
!Endpoint
!Funktion
|-
|PATCH
|<code>/member/roles/rank</code>
|Default Rank-Rolle ändern
|-
|PATCH
|<code>/member/roles/rank/{rank_type_id}</code>
|Rank-Rolle bestimmten Typs ändern
|-
|GET
|<code>/member/bonus/history</code>
|Bonus-History
|-
|POST
|<code>/member/bonus/claim</code>
|Bonus beanspruchen
|-
|GET
|<code>/member/bonus/notification/settings</code>
|Bonus-Notification-Settings
|-
|PATCH
|<code>/member/bonus/notification/settings</code>
|Settings ändern
|-
|DELETE
|<code>/member/roles/history/{historyid}</code>
|Rollen-History löschen
|-
|POST
|<code>/member/resign</code>
|Mitgliedschaft niederlegen
|}


| Method | Endpoint                   | Funktion             |
== Member Administration ==
| ------ | -------------------------- | --------------------- |
{| class="wikitable"
| GET    | `/dlog/list`              | Fahrten auflisten    |
!Method
| GET    | `/dlog/{logid}`            | einzelne Fahrt        |
!Endpoint
| DELETE | `/dlog/{logid}`            | Fahrt löschen        |
!Funktion
| GET    | `/dlog/leaderboard`        | Leaderboard          |
|-
| GET    | `/dlog/export`            | Fahrten exportieren  |
|PATCH
| GET    | `/dlog/statistics/summary` | aggregierte Statistik |
|<code>/member/{userid}/roles</code>
| GET    | `/dlog/statistics/chart`  | Chart-Daten          |
|Rollen ändern
| GET    | `/dlog/statistics/details` | Detailstatistik      |
|-
|PATCH
|<code>/member/{userid}/points</code>
|Punkte ändern
|-
|POST
|<code>/member/{userid}/dismiss</code>
|Mitglied entlassen
|}
----


= 16. Driving Logs – <code>/dlog</code> =
{| class="wikitable"
!Method
!Endpoint
!Funktion
|-
|GET
|<code>/dlog/list</code>
|Fahrten auflisten
|-
|GET
|<code>/dlog/{logid}</code>
|einzelne Fahrt
|-
|DELETE
|<code>/dlog/{logid}</code>
|Fahrt löschen
|-
|GET
|<code>/dlog/leaderboard</code>
|Leaderboard
|-
|GET
|<code>/dlog/export</code>
|Fahrten exportieren
|-
|GET
|<code>/dlog/statistics/summary</code>
|aggregierte Statistik
|-
|GET
|<code>/dlog/statistics/chart</code>
|Chart-Daten
|-
|GET
|<code>/dlog/statistics/details</code>
|Detailstatistik
|}
Diese APIs gehören zu den mächtigeren Teilen des Backends und besitzen zahlreiche Filter für beispielsweise:
Diese APIs gehören zu den mächtigeren Teilen des Backends und besitzen zahlreiche Filter für beispielsweise:
 
<code>Fahrer
```text
Zeiträume
Fahrer
Distanz
Zeiträume
Einnahmen
Distanz
Schaden
Einnahmen
Fahrzeug
Schaden
Fracht
Fahrzeug
Start-/Zielort
Fracht
Spiel
Start-/Zielort
Tracker</code>
Spiel
Tracker
```
 
Die Filter sollten anhand der jeweiligen OpenAPI-Definition verwendet werden, da die Statistik-Endpoints unterschiedlich große Parametersätze besitzen.
Die Filter sollten anhand der jeweiligen OpenAPI-Definition verwendet werden, da die Statistik-Endpoints unterschiedlich große Parametersätze besitzen.
----


---
= 17. Tracker APIs =
 
# 17. Tracker APIs
 
Tracker-Routen werden nur aktiviert, wenn der entsprechende Tracker konfiguriert ist.
Tracker-Routen werden nur aktiviert, wenn der entsprechende Tracker konfiguriert ist.


## TrackSim
== TrackSim ==
 
{| class="wikitable"
| Method | Endpoint                   |
!Method
| ------ | --------------------------- |
!Endpoint
| POST   | `/tracksim/update`          |
|-
| POST   | `/tracksim/update/route`    |
|POST
| PUT   | `/tracksim/driver/{userid}` |
|<code>/tracksim/update</code>
| DELETE | `/tracksim/driver/{userid}` |
|-
 
|POST
## Trucky
|<code>/tracksim/update/route</code>
 
|-
| Method | Endpoint                  |
|PUT
| ------ | ------------------------- |
|<code>/tracksim/driver/{userid}</code>
| POST  | `/trucky/update`          |
|-
| POST  | `/trucky/import/{jobid}`  |
|DELETE
| PUT    | `/trucky/driver/{userid}` |
|<code>/tracksim/driver/{userid}</code>
| DELETE | `/trucky/driver/{userid}` |
|}
 
## Custom Tracker
 
```text
POST /custom-tracker/update
```


## UniTracker
== Trucky ==
{| class="wikitable"
!Method
!Endpoint
|-
|POST
|<code>/trucky/update</code>
|-
|POST
|<code>/trucky/import/{jobid}</code>
|-
|PUT
|<code>/trucky/driver/{userid}</code>
|-
|DELETE
|<code>/trucky/driver/{userid}</code>
|}


```text
== Custom Tracker ==
POST /unitracker/update
<code>POST /custom-tracker/update</code>
```


== UniTracker ==
<code>POST /unitracker/update</code>
Diese Endpoints sind primär für Tracker-Server/Webhooks gedacht, nicht für den normalen Browser-Client.
Diese Endpoints sind primär für Tracker-Server/Webhooks gedacht, nicht für den normalen Browser-Client.
----


---
= 18. Announcements Plugin =
 
# 18. Announcements Plugin
 
Nur vorhanden, wenn das Plugin aktiviert ist.
Nur vorhanden, wenn das Plugin aktiviert ist.
{| class="wikitable"
!Method
!Endpoint
!Funktion
|-
|GET
|<code>/announcements/types</code>
|Announcement-Typen
|-
|GET
|<code>/announcements/list</code>
|Liste
|-
|GET
|<code>/announcements/{announcementid}</code>
|Eintrag
|-
|POST
|<code>/announcements</code>
|erstellen
|-
|PATCH
|<code>/announcements/{announcementid}</code>
|ändern
|-
|DELETE
|<code>/announcements/{announcementid}</code>
|löschen
|}
----


| Method | Endpoint                          | Funktion          |
= 19. Applications Plugin =
| ------ | --------------------------------- | ------------------ |
{| class="wikitable"
| GET    | `/announcements/types`            | Announcement-Typen |
!Method
| GET    | `/announcements/list`            | Liste              |
!Endpoint
| GET    | `/announcements/{announcementid}` | Eintrag            |
!Funktion
| POST  | `/announcements`                  | erstellen          |
|-
| PATCH  | `/announcements/{announcementid}` | ändern            |
|GET
| DELETE | `/announcements/{announcementid}` | löschen            |
|<code>/applications/types</code>
 
|Application-Typen
---
|-
 
|GET
# 19. Applications Plugin
|<code>/applications/list</code>
 
|Bewerbungen
| Method | Endpoint                               | Funktion             |
|-
| ------ | --------------------------------------- | -------------------- |
|GET
| GET   | `/applications/types`                  | Application-Typen   |
|<code>/applications/statistics</code>
| GET   | `/applications/list`                    | Bewerbungen         |
|Statistiken
| GET   | `/applications/statistics`              | Statistiken         |
|-
| GET   | `/applications/{applicationid}`        | Bewerbung           |
|GET
| POST   | `/applications`                        | Bewerbung erstellen |
|<code>/applications/{applicationid}</code>
| POST   | `/applications/{applicationid}/message` | Nachricht hinzufügen |
|Bewerbung
| PATCH | `/applications/{applicationid}/status| Status ändern       |
|-
| DELETE | `/applications/{applicationid}`        | löschen             |
|POST
 
|<code>/applications</code>
|Bewerbung erstellen
|-
|POST
|<code>/applications/{applicationid}/message</code>
|Nachricht hinzufügen
|-
|PATCH
|<code>/applications/{applicationid}/status</code>
|Status ändern
|-
|DELETE
|<code>/applications/{applicationid}</code>
|löschen
|}
Hinweis: Das Akzeptieren einer Application akzeptiert den User nicht automatisch als Hub-Mitglied.
Hinweis: Das Akzeptieren einer Application akzeptiert den User nicht automatisch als Hub-Mitglied.
----


---
= 20. Challenges Plugin =
 
{| class="wikitable"
# 20. Challenges Plugin
!Method
 
!Endpoint
| Method | Endpoint                                     |
|-
| ------ | -------------------------------------------- |
|GET
| GET   | `/challenges/list`                          |
|<code>/challenges/list</code>
| GET   | `/challenges/{challengeid}`                  |
|-
| POST   | `/challenges`                                |
|GET
| PATCH | `/challenges/{challengeid}`                  |
|<code>/challenges/{challengeid}</code>
| DELETE | `/challenges/{challengeid}`                  |
|-
| PUT   | `/challenges/{challengeid}/delivery/{logid}` |
|POST
| DELETE | `/challenges/{challengeid}/delivery/{logid}` |
|<code>/challenges</code>
 
|-
|PATCH
|<code>/challenges/{challengeid}</code>
|-
|DELETE
|<code>/challenges/{challengeid}</code>
|-
|PUT
|<code>/challenges/{challengeid}/delivery/{logid}</code>
|-
|DELETE
|<code>/challenges/{challengeid}/delivery/{logid}</code>
|}
Die letzten beiden Calls ordnen Driving Logs einer Challenge zu bzw. entfernen sie.
Die letzten beiden Calls ordnen Driving Logs einer Challenge zu bzw. entfernen sie.
----


---
= 21. Divisions Plugin =
 
{| class="wikitable"
# 21. Divisions Plugin
!Method
 
!Endpoint
| Method | Endpoint                             |
|-
| ------ | ------------------------------------- |
|GET
| GET   | `/divisions/list`                    |
|<code>/divisions/list</code>
| GET   | `/divisions/statistics`              |
|-
| GET   | `/divisions/{divisionid}/activity`    |
|GET
| GET   | `/divisions/list/pending`            |
|<code>/divisions/statistics</code>
| GET   | `/dlog/{logid}/division`              |
|-
| POST   | `/dlog/{logid}/division/{divisionid}` |
|GET
| PATCH | `/dlog/{logid}/division/{divisionid}` |
|<code>/divisions/{divisionid}/activity</code>
 
|-
---
|GET
 
|<code>/divisions/list/pending</code>
# 22. Downloads Plugin
|-
 
|GET
| Method | Endpoint                      |
|<code>/dlog/{logid}/division</code>
| ------ | ------------------------------ |
|-
| GET    | `/downloads/list`              |
|POST
| GET    | `/downloads/redirect/{secret}` |
|<code>/dlog/{logid}/division/{divisionid}</code>
| GET    | `/downloads/{downloadsid}`    |
|-
| POST  | `/downloads`                  |
|PATCH
| PATCH  | `/downloads/{downloadsid}`    |
|<code>/dlog/{logid}/division/{divisionid}</code>
| DELETE | `/downloads/{downloadsid}`    |
|}
----


`/downloads/redirect/{secret}` dient dem kontrollierten Download/Redirect anhand eines Secrets.
= 22. Downloads Plugin =
 
{| class="wikitable"
---
!Method
 
!Endpoint
# 23. Economy Plugin
|-
|GET
|<code>/downloads/list</code>
|-
|GET
|<code>/downloads/redirect/{secret}</code>
|-
|GET
|<code>/downloads/{downloadsid}</code>
|-
|POST
|<code>/downloads</code>
|-
|PATCH
|<code>/downloads/{downloadsid}</code>
|-
|DELETE
|<code>/downloads/{downloadsid}</code>
|}
<code>/downloads/redirect/{secret}</code> dient dem kontrollierten Download/Redirect anhand eines Secrets.
----


= 23. Economy Plugin =
Das Economy-Plugin besitzt eine umfangreiche eigene API.
Das Economy-Plugin besitzt eine umfangreiche eigene API.


## Economy Overview
== Economy Overview ==
 
  <code>GET /economy</code>
```text
----
GET /economy
```
 
---
 
## Balance
 
| Method | Endpoint                                            |
| ------ | --------------------------------------------------- |
| GET    | `/economy/balance`                                  |
| GET    | `/economy/balance/{userid}`                        |
| PATCH | `/economy/balance/{userid}`                        |
| GET    | `/economy/balance/leaderboard`                      |
| POST  | `/economy/balance/transfer`                        |
| GET   | `/economy/balance/{userid}/transactions/list`      |
| GET    | `/economy/balance/{userid}/transactions/export`    |
| POST  | `/economy/balance/{userid}/visibility/{visibility}` |
 
---


## Garages
== Balance ==
{| class="wikitable"
!Method
!Endpoint
|-
|GET
|<code>/economy/balance</code>
|-
|GET
|<code>/economy/balance/{userid}</code>
|-
|PATCH
|<code>/economy/balance/{userid}</code>
|-
|GET
|<code>/economy/balance/leaderboard</code>
|-
|POST
|<code>/economy/balance/transfer</code>
|-
|GET
|<code>/economy/balance/{userid}/transactions/list</code>
|-
|GET
|<code>/economy/balance/{userid}/transactions/export</code>
|-
|POST
|<code>/economy/balance/{userid}/visibility/{visibility}</code>
|}
----


| Method | Endpoint                               |
== Garages ==
| ------ | -------------------------------------- |
{| class="wikitable"
| GET   | `/economy/garages`                    |
!Method
| GET   | `/economy/garages/list`                |
!Endpoint
| GET   | `/economy/garages/{garageid}`          |
|-
| POST   | `/economy/garages/{garageid}/purchase` |
|GET
| POST   | `/economy/garages/{garageid}/transfer` |
|<code>/economy/garages</code>
| POST   | `/economy/garages/{garageid}/sell`    |
|-
|GET
|<code>/economy/garages/list</code>
|-
|GET
|<code>/economy/garages/{garageid}</code>
|-
|POST
|<code>/economy/garages/{garageid}/purchase</code>
|-
|POST
|<code>/economy/garages/{garageid}/transfer</code>
|-
|POST
|<code>/economy/garages/{garageid}/sell</code>
|}


### Garage Slots
=== Garage Slots ===
{| class="wikitable"
!Method
!Endpoint
|-
|GET
|<code>/economy/garages/{garageid}/slots/list</code>
|-
|GET
|<code>/economy/garages/{garageid}/slots/{slotid}</code>
|-
|POST
|<code>/economy/garages/{garageid}/slots/purchase</code>
|-
|POST
|<code>/economy/garages/{garageid}/slots/{slotid}/transfer</code>
|-
|POST
|<code>/economy/garages/{garageid}/slots/{slotid}/sell</code>
|}
----


| Method | Endpoint                                              |
== Trucks ==
| ------ | ----------------------------------------------------- |
{| class="wikitable"
| GET   | `/economy/garages/{garageid}/slots/list`              |
!Method
| GET    | `/economy/garages/{garageid}/slots/{slotid}`          |
!Endpoint
| POST   | `/economy/garages/{garageid}/slots/purchase`          |
|-
| POST   | `/economy/garages/{garageid}/slots/{slotid}/transfer` |
|GET
| POST   | `/economy/garages/{garageid}/slots/{slotid}/sell`    |
|<code>/economy/trucks</code>
|-
|GET
|<code>/economy/trucks/list</code>
|-
|GET
|<code>/economy/trucks/{vehicleid}</code>
|-
|GET
|<code>/economy/trucks/{vehicleid}/{operation}/history</code>
|-
|POST
|<code>/economy/trucks/{truckid}/purchase</code>
|-
|POST
|<code>/economy/trucks/{vehicleid}/transfer</code>
|-
|POST
|<code>/economy/trucks/{vehicleid}/relocate</code>
|-
|POST
|<code>/economy/trucks/{vehicleid}/activate</code>
|-
|POST
|<code>/economy/trucks/{vehicleid}/deactivate</code>
|-
|POST
|<code>/economy/trucks/{vehicleid}/repair</code>
|-
|POST
|<code>/economy/trucks/{vehicleid}/sell</code>
|-
|POST
|<code>/economy/trucks/{vehicleid}/scrap</code>
|}
----


---
== Merchandise ==
 
{| class="wikitable"
## Trucks
!Method
 
!Endpoint
| Method | Endpoint                                         |
|-
| ------ | ------------------------------------------------- |
|GET
| GET   | `/economy/trucks`                                |
|<code>/economy/merch</code>
| GET    | `/economy/trucks/list`                            |
|-
| GET    | `/economy/trucks/{vehicleid}`                    |
|GET
| GET   | `/economy/trucks/{vehicleid}/{operation}/history` |
|<code>/economy/merch/list</code>
| POST  | `/economy/trucks/{truckid}/purchase`              |
|-
| POST  | `/economy/trucks/{vehicleid}/transfer`            |
|POST
| POST   | `/economy/trucks/{vehicleid}/relocate`            |
|<code>/economy/merch/{merchid}/purchase</code>
| POST  | `/economy/trucks/{vehicleid}/activate`            |
|-
| POST  | `/economy/trucks/{vehicleid}/deactivate`          |
|POST
| POST  | `/economy/trucks/{vehicleid}/repair`              |
|<code>/economy/merch/{itemid}/transfer</code>
| POST  | `/economy/trucks/{vehicleid}/sell`                |
|-
| POST  | `/economy/trucks/{vehicleid}/scrap`              |
|POST
 
|<code>/economy/merch/{itemid}/sell</code>
---
|}
 
----
## Merchandise
 
| Method | Endpoint                            |
| ------ | ----------------------------------- |
| GET    | `/economy/merch`                    |
| GET    | `/economy/merch/list`              |
| POST   | `/economy/merch/{merchid}/purchase` |
| POST  | `/economy/merch/{itemid}/transfer|
| POST   | `/economy/merch/{itemid}/sell`      |
 
---
 
# 24. Events Plugin
 
| Method | Endpoint                      |
| ------ | ----------------------------- |
| GET    | `/events/list`                |
| GET    | `/events/{eventid}`          |
| PUT    | `/events/{eventid}/vote`      |
| DELETE | `/events/{eventid}/vote`      |
| POST  | `/events`                    |
| PATCH  | `/events/{eventid}`          |
| DELETE | `/events/{eventid}`          |
| PATCH  | `/events/{eventid}/attendees` |


= 24. Events Plugin =
{| class="wikitable"
!Method
!Endpoint
|-
|GET
|<code>/events/list</code>
|-
|GET
|<code>/events/{eventid}</code>
|-
|PUT
|<code>/events/{eventid}/vote</code>
|-
|DELETE
|<code>/events/{eventid}/vote</code>
|-
|POST
|<code>/events</code>
|-
|PATCH
|<code>/events/{eventid}</code>
|-
|DELETE
|<code>/events/{eventid}</code>
|-
|PATCH
|<code>/events/{eventid}/attendees</code>
|}
Beim Bearbeiten von Attendees werden User-IDs verwendet.
Beim Bearbeiten von Attendees werden User-IDs verwendet.
----


---
= 25. Poll Plugin =
 
{| class="wikitable"
# 25. Poll Plugin
!Method
 
!Endpoint
| Method | Endpoint               |
|-
| ------ | ---------------------- |
|GET
| GET   | `/polls/list`          |
|<code>/polls/list</code>
| GET   | `/polls/{pollid}`      |
|-
| PUT   | `/polls/{pollid}/vote` |
|GET
| PATCH | `/polls/{pollid}/vote` |
|<code>/polls/{pollid}</code>
| DELETE | `/polls/{pollid}/vote` |
|-
| POST   | `/polls`              |
|PUT
| PATCH | `/polls/{pollid}`      |
|<code>/polls/{pollid}/vote</code>
| DELETE | `/polls/{pollid}`      |
|-
 
|PATCH
`GET /polls/list` unterstützt u. a.:
|<code>/polls/{pollid}/vote</code>
 
|-
```text
|DELETE
page
|<code>/polls/{pollid}/vote</code>
page_size
|-
order_by
|POST
order
|<code>/polls</code>
```
|-
 
|PATCH
`order_by` kann beispielsweise:
|<code>/polls/{pollid}</code>
 
|-
```text
|DELETE
orderid
|<code>/polls/{pollid}</code>
pollid
|}
title
<code>GET /polls/list</code> unterstützt u. a.:
timestamp
<code>page
end_time
page_size
```
order_by
 
order</code>
<code>order_by</code> kann beispielsweise:
<code>orderid
pollid
title
timestamp
end_time</code>
sein.
sein.
----


---
= 26. Tasks Plugin =
 
{| class="wikitable"
# 26. Tasks Plugin
!Method
 
!Endpoint
| Method | Endpoint                         |
|-
| ------ | --------------------------------- |
|GET
| GET   | `/tasks/list`                    |
|<code>/tasks/list</code>
| GET   | `/tasks/{taskid}`                |
|-
| POST   | `/tasks`                          |
|GET
| PATCH | `/tasks/{taskid}`                |
|<code>/tasks/{taskid}</code>
| DELETE | `/tasks/{taskid}`                |
|-
| PUT   | `/tasks/{taskid}/complete/mark|
|POST
| DELETE | `/tasks/{taskid}/complete/mark|
|<code>/tasks</code>
| POST   | `/tasks/{taskid}/complete/accept` |
|-
| POST   | `/tasks/{taskid}/complete/reject` |
|PATCH
 
|<code>/tasks/{taskid}</code>
|-
|DELETE
|<code>/tasks/{taskid}</code>
|-
|PUT
|<code>/tasks/{taskid}/complete/mark</code>
|-
|DELETE
|<code>/tasks/{taskid}/complete/mark</code>
|-
|POST
|<code>/tasks/{taskid}/complete/accept</code>
|-
|POST
|<code>/tasks/{taskid}/complete/reject</code>
|}
Der typische Workflow ist:
Der typische Workflow ist:
<code>Task erstellen
      ↓
User markiert Task als erledigt
      ↓
Staff akzeptiert oder verwirft die Completion</code>
----


```text
= 27. Beispiel eines kompletten Clients =
Task erstellen
      ↓
User markiert Task als erledigt
      ↓
Staff akzeptiert oder verwirft die Completion
```
 
---
 
# 27. Beispiel eines kompletten Clients
 
Shell-Setup:
Shell-Setup:
<code>BASE="<nowiki>https://hub.example.com/api</nowiki>"
TOKEN="..."</code>


```bash
== Status ==
BASE="https://hub.example.com/api"
<code>curl -sS "$BASE/status"</code>
TOKEN="..."
```
 
## Status
 
```bash
curl -sS "$BASE/status"
```
 
## Login
 
```bash
curl -sS \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "password": "Secret123!",
    "captcha-response": "CAPTCHA_TOKEN"
  }' \
  "$BASE/auth/password"
```


== Login ==
<code>curl -sS \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "password": "Secret123!",
    "captcha-response": "CAPTCHA_TOKEN"
  }' \
  "$BASE/auth/password"</code>
Response:
Response:
<code>{
  "token": "e1234567-89ab-cdef-0123-456789abcdef",
  "mfa": false
}</code>


```json
== Eigenes Profil ==
{
<code>curl -sS \
  "token": "e1234567-89ab-cdef-0123-456789abcdef",
  -H "Authorization: Bearer $TOKEN" \
  "mfa": false
  "$BASE/user/profile"</code>
}
```
 
## Eigenes Profil
 
```bash
curl -sS \
  -H "Authorization: Bearer $TOKEN" \
  "$BASE/user/profile"
```
 
## Fremdes Profil anhand UID


```bash
== Fremdes Profil anhand UID ==
curl -sS \
<code>curl -sS \
  -H "Authorization: Bearer $TOKEN" \
  -H "Authorization: Bearer $TOKEN" \
  "$BASE/user/profile?uid=42"
  "$BASE/user/profile?uid=42"</code>
```


## Profil ändern
== Profil ändern ==
<code>curl -sS \
  -X PATCH \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Kosmos",
    "avatar": "<nowiki>https://example.com/avatar.png</nowiki>"
  }' \
  "$BASE/user/profile"</code>


```bash
== Driving Logs ==
curl -sS \
<code>curl -sS \
  -X PATCH \
  -H "Authorization: Bearer $TOKEN" \
  -H "Authorization: Bearer $TOKEN" \
  "$BASE/dlog/list?page=1&page_size=50"</code>
  -H "Content-Type: application/json" \
  -d '{
    "name": "Kosmos",
    "avatar": "https://example.com/avatar.png"
  }' \
  "$BASE/user/profile"
```


## Driving Logs
== Token prüfen ==
<code>curl -sS \
  -H "Authorization: Bearer $TOKEN" \
  "$BASE/token"</code>


```bash
== Logout / Token widerrufen ==
curl -sS \
<code>curl -sS \
  -H "Authorization: Bearer $TOKEN" \
  -X DELETE \
  "$BASE/dlog/list?page=1&page_size=50"
  -H "Authorization: Bearer $TOKEN" \
```
  -H "Content-Type: application/json" \
  "$BASE/token"</code>
----


## Token prüfen
= 28. Wichtige Besonderheiten für Client-Entwickler =
 
```bash
curl -sS \
  -H "Authorization: Bearer $TOKEN" \
  "$BASE/token"
```
 
## Logout / Token widerrufen
 
```bash
curl -sS \
  -X DELETE \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  "$BASE/token"
```
 
---
 
# 28. Wichtige Besonderheiten für Client-Entwickler
 
### 1. Nicht alle Endpoints sind immer vorhanden


=== 1. Nicht alle Endpoints sind immer vorhanden ===
Tracker-Endpunkte hängen von den konfigurierten Trackern ab.
Tracker-Endpunkte hängen von den konfigurierten Trackern ab.


Plugin-Endpunkte hängen von den aktivierten Plugins ab.
Plugin-Endpunkte hängen von den aktivierten Plugins ab.


Ein `404 Not Found` kann daher bedeuten, dass die entsprechende Funktion im aktuellen Hub deaktiviert ist.
Ein <code>404 Not Found</code> kann daher bedeuten, dass die entsprechende Funktion im aktuellen Hub deaktiviert ist.
 
### 2. Permissions sind dynamisch


Viele Endpoints verlangen keine fest im Endpointnamen sichtbare Rolle wie `admin`.
=== 2. Permissions sind dynamisch ===
Viele Endpoints verlangen keine fest im Endpointnamen sichtbare Rolle wie <code>admin</code>.


Die Autorisierung basiert auf:
Die Autorisierung basiert auf:
 
<code>User accepted?
```text
+
User accepted?
Roles
+
+
Roles
Permissions der Rollen</code>
+
Permissions der Rollen
```
 
Ein Benutzer muss mindestens eine passende Permission besitzen.
Ein Benutzer muss mindestens eine passende Permission besitzen.


### 3. Application Token != User Token
=== 3. Application Token != User Token ===
 
Ein Application Token wird vom System ausdrücklich anders behandelt.
Ein Application Token wird vom System ausdrücklich anders behandelt.


Ein Client sollte daher nicht davon ausgehen, dass jeder Bearer-Endpunkt automatisch mit Application Token funktioniert.
Ein Client sollte daher nicht davon ausgehen, dass jeder Bearer-Endpunkt automatisch mit Application Token funktioniert.


### 4. OpenAPI beschreibt Responses kaum
=== 4. OpenAPI beschreibt Responses kaum ===
 
Viele Definitionen enthalten:
Viele Definitionen enthalten:
 
<code>"responses": {}</code>
```json
"responses": {}
```
 
Für einen streng typisierten Client sollte man Response-Schemas daher aus der Implementierung bzw. aus echten Testantworten ableiten.
Für einen streng typisierten Client sollte man Response-Schemas daher aus der Implementierung bzw. aus echten Testantworten ableiten.


### 5. Captcha-Abweichung
=== 5. Captcha-Abweichung ===
 
Bei <code>/auth/password</code>, <code>/auth/register</code> und <code>/auth/reset</code> sollte der Client immer:
Bei `/auth/password`, `/auth/register` und `/auth/reset` sollte der Client immer:
<code>"captcha-response": "..."</code>
 
```json
"captcha-response": "..."
```
 
mitsenden.
mitsenden.


Zumindest beim Password-Login greift die Implementierung direkt auf dieses Feld zu.
Zumindest beim Password-Login greift die Implementierung direkt auf dieses Feld zu.


### 6. API-Versionierung
=== 6. API-Versionierung ===
 
Die API verwendet keine Versionsnummer im URL-Pfad wie:
Die API verwendet keine Versionsnummer im URL-Pfad wie:
 
<code>/api/v1/...</code>
```text
/api/v1/...
```
 
Die Kompatibilität hängt daher von der eingesetzten HubBackend-Version ab.
Die Kompatibilität hängt daher von der eingesetzten HubBackend-Version ab.
----


---
= 29. Empfehlung für eine eigene Integration =
 
# 29. Empfehlung für eine eigene Integration
 
Für einen normalen Web-/Desktop-Client würde ich folgende Reihenfolge verwenden:
Für einen normalen Web-/Desktop-Client würde ich folgende Reihenfolge verwenden:
 
<code>GET /
```text
   
GET /
GET /languages
 
   
GET /languages
POST /auth/password
 
   
POST /auth/password
optional POST /auth/mfa
 
   
optional POST /auth/mfa
GET /token
 
   
GET /token
GET /user/profile
 
   
GET /user/profile
GET /member/perms
 
   
GET /member/perms
Features abhängig von Permissions anzeigen</code>
 
Features abhängig von Permissions anzeigen
```
 
Danach können beispielsweise:
Danach können beispielsweise:
 
<code>/dlog/*
```text
/member/*
/dlog/*
/announcements/*
/member/*
/applications/*
/announcements/*
/events/*
/applications/*
/economy/*</code>
/events/*
/economy/*
```
 
verwendet werden.
verwendet werden.


Für einen generischen Client ist es sinnvoll, **nicht** hart anzunehmen, welche Plugins vorhanden sind, sondern die Hub-Konfiguration bzw. verfügbaren Funktionen beim Start festzustellen.
Für einen generischen Client ist es sinnvoll, '''nicht''' hart anzunehmen, welche Plugins vorhanden sind, sondern die Hub-Konfiguration bzw. verfügbaren Funktionen beim Start festzustellen.
 
----
---
 
# 30. Kurzreferenz der API-Bereiche
 
```text
/                        Server/Hub Info
/status                  Status
/config                  Administration
/audit                    Audit Log
 
/auth/*                  Login / Registration
/token/*                  Sessions / Application Tokens
 
/user/*                  Accounts
/member/*                Mitglieder / Rollen / Punkte
/dlog/*                  Driving Logs & Statistiken
 
/tracksim/*              TrackSim
/trucky/*                Trucky
/custom-tracker/*        Custom Tracker
/unitracker/*            UniTracker


/announcements/*          Announcements Plugin
= 30. Kurzreferenz der API-Bereiche =
/applications/*          Applications Plugin
<code>/                        Server/Hub Info
/challenges/*            Challenge Plugin
/status                  Status
/divisions/*              Division Plugin
/config                  Administration
/downloads/*              Downloads Plugin
/audit                    Audit Log
/economy/*                Economy Plugin
/events/*                Event Plugin
/auth/*                  Login / Registration
/polls/*                  Poll Plugin
/token/*                  Sessions / Application Tokens
/tasks/*                  Task Plugin
```
/user/*                  Accounts
/member/*                Mitglieder / Rollen / Punkte
/dlog/*                  Driving Logs & Statistiken
/tracksim/*              TrackSim
/trucky/*                Trucky
/custom-tracker/*        Custom Tracker
/unitracker/*            UniTracker
/announcements/*          Announcements Plugin
/applications/*          Applications Plugin
/challenges/*            Challenge Plugin
/divisions/*              Division Plugin
/downloads/*              Downloads Plugin
/economy/*                Economy Plugin
/events/*                Event Plugin
/polls/*                  Poll Plugin
/tasks/*                  Task Plugin</code>