c904e3e2db
POST /user/delete (auth required) verifies the password via pass1 and transactionally removes the user's sessions, votes, entries and the user row, then clears the session cookie. Associated media files are removed best effort after commit. This was only a stub in the Flask original. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
241 lines
4.6 KiB
Markdown
241 lines
4.6 KiB
Markdown
# kver API Definition
|
||
|
||
Abgeleitet aus dem bestehenden Flask-Code. Basis für die Go-Reimplementierung.
|
||
|
||
---
|
||
|
||
## Authentifizierung
|
||
|
||
Sessions werden als Cookie (`session`) übertragen. Alle geschützten Endpunkte erwarten diesen Cookie.
|
||
|
||
---
|
||
|
||
## Auth
|
||
|
||
### `POST /auth/login`
|
||
|
||
Einloggen.
|
||
|
||
**Request (form-encoded):**
|
||
| Feld | Typ | Beschreibung |
|
||
|------|-----|--------------|
|
||
| `user` | string | Nutzername |
|
||
| `pass` | string | Passwort |
|
||
| `timeout` | int | Session-Dauer in Sekunden |
|
||
|
||
**Response:**
|
||
- `200` + setzt `session`-Cookie → Redirect auf `/`
|
||
- `200` + Fehlertext bei falschen Credentials
|
||
|
||
---
|
||
|
||
### `GET /auth/login`
|
||
|
||
Login-Seite anzeigen (wird in der Go-API nicht benötigt, Frontend übernimmt das).
|
||
|
||
---
|
||
|
||
### `POST /auth/newuser`
|
||
|
||
Neuen Account registrieren.
|
||
|
||
**Request (form-encoded):**
|
||
| Feld | Typ | Beschreibung |
|
||
|------|-----|--------------|
|
||
| `user` | string | Nutzername (3–32 Zeichen, `[a-zA-Z0-9._\s-]`) |
|
||
| `pass1` | string | Passwort (min. 10 Zeichen) |
|
||
| `pass2` | string | Passwort-Bestätigung |
|
||
|
||
**Response:**
|
||
- `200` bei Erfolg
|
||
- `200` + Fehlerliste bei Validierungsfehler
|
||
|
||
---
|
||
|
||
### `GET /auth/logout`
|
||
|
||
Session beenden und Cookie löschen.
|
||
|
||
**Response:** Redirect auf `/`
|
||
|
||
---
|
||
|
||
### `GET /auth/headerbar`
|
||
|
||
Gibt zurück ob der Nutzer eingeloggt ist (für die UI-Headerleiste).
|
||
|
||
**Response:** HTML-Partial (in Go-API: JSON)
|
||
|
||
---
|
||
|
||
### `GET /auth/sessioninfo`
|
||
|
||
Infos zur aktuellen Session.
|
||
|
||
**Auth:** erforderlich
|
||
|
||
**Response:**
|
||
```json
|
||
{
|
||
"uid": 123456,
|
||
"created_at": 1700000000,
|
||
"expires": 1700086400,
|
||
"description": ""
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Entries (Beiträge)
|
||
|
||
### `GET /entry/feed/:page`
|
||
|
||
Paginierter Feed aller Beiträge, neueste zuerst.
|
||
|
||
**Parameter:**
|
||
| Name | Typ | Beschreibung |
|
||
|------|-----|--------------|
|
||
| `page` | int | Seite (0–100), 20 Einträge pro Seite |
|
||
|
||
**Response:**
|
||
```json
|
||
[
|
||
{
|
||
"pid": 123456789,
|
||
"created_at": 1700000000,
|
||
"uid": 42,
|
||
"content": "...",
|
||
"filepath": "static/media/...",
|
||
"username": "max"
|
||
}
|
||
]
|
||
```
|
||
Leeres Array `[]` wenn keine weiteren Einträge vorhanden.
|
||
|
||
---
|
||
|
||
### `POST /entry/create`
|
||
|
||
Neuen Beitrag erstellen.
|
||
|
||
**Auth:** erforderlich
|
||
|
||
**Request (multipart/form-data):**
|
||
| Feld | Typ | Beschreibung |
|
||
|------|-----|--------------|
|
||
| `content` | string | Text (max. 1000 Zeichen) |
|
||
| `file` | file (optional) | Bild (JPG oder GIF, wird auf max. 1024px skaliert) |
|
||
|
||
Mindestens `content` oder `file` muss vorhanden sein.
|
||
|
||
**Response:**
|
||
- `201` bei Erfolg
|
||
- `400` bei leerem Beitrag
|
||
- `401` wenn nicht eingeloggt
|
||
|
||
---
|
||
|
||
### `GET /entry/:pid/interactions/:mode`
|
||
|
||
Abstimmung auf einen Beitrag. (*Aktuell nicht implementiert.*)
|
||
|
||
**Parameter:**
|
||
| Name | Typ | Beschreibung |
|
||
|------|-----|--------------|
|
||
| `pid` | int | Post-ID |
|
||
| `mode` | string | `left` oder `right` |
|
||
|
||
---
|
||
|
||
## User
|
||
|
||
### `GET /u/:username`
|
||
|
||
Öffentliche Profilseite eines Nutzers.
|
||
|
||
**Response:** Nutzerprofil + Beiträge (Details noch offen)
|
||
|
||
---
|
||
|
||
### `GET /user/info`
|
||
|
||
Eigene Account-Informationen.
|
||
|
||
**Auth:** erforderlich
|
||
|
||
**Response:**
|
||
```json
|
||
{
|
||
"uid": 42,
|
||
"username": "max",
|
||
"created_at": 1700000000
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### `POST /user/delete`
|
||
|
||
Eigenen Account dauerhaft löschen. Beiträge, Votes und Sessions werden
|
||
mitgelöscht, zugehörige Mediendateien best effort entfernt.
|
||
|
||
**Auth:** erforderlich
|
||
|
||
**Request (form-encoded):**
|
||
| Feld | Typ | Beschreibung |
|
||
|------|-----|--------------|
|
||
| `pass1` | string | Passwort zur Bestätigung |
|
||
|
||
**Response:**
|
||
- `200` `{"status": "deleted"}` + löscht den `session`-Cookie
|
||
- `403` bei falschem Passwort
|
||
|
||
---
|
||
|
||
## Datenbankschema (SQLite)
|
||
|
||
```sql
|
||
CREATE TABLE user (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
uid INTEGER UNIQUE,
|
||
username TEXT UNIQUE,
|
||
password BLOB,
|
||
created_at INTEGER,
|
||
last_login INTEGER
|
||
);
|
||
|
||
CREATE TABLE session (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
uid INTEGER,
|
||
value TEXT UNIQUE,
|
||
created_at INTEGER,
|
||
expires INTEGER,
|
||
description TEXT
|
||
);
|
||
|
||
CREATE TABLE entry (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
pid INTEGER UNIQUE,
|
||
uid INTEGER,
|
||
created_at INTEGER,
|
||
content TEXT,
|
||
filepath TEXT
|
||
);
|
||
|
||
CREATE TABLE vote (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
uid INTEGER,
|
||
pid INTEGER,
|
||
mode TEXT -- 'left' | 'right'
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
## Offene Punkte
|
||
|
||
- `/entry/:pid/interactions/:mode` ist auskommentiert — Voting-Logik muss neu designed werden
|
||
- Kein Rate-Limiting außer dem zufälligen `sleep` beim Login
|
||
- `session`-Token ist nur `randbelow(999999999) + timestamp` — sollte auf `crypto/rand` umgestellt werden
|
||
- Fehler-Responses sind aktuell Plaintext/HTML — in der Go-API einheitlich JSON
|