Datenbank von SQLite auf Postgres umgestellt
Verbindung über KVER_DSN; Tabelle user heißt jetzt account (reserviertes Wort in Postgres). kver import-sqlite übernimmt die alte Datei einmalig in einer Transaktion. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TiXsPUqw7oeomZ8wZrQW5q
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
c6ab082f8c
commit
2714fdb1a5
@@ -5,7 +5,6 @@ import (
|
||||
"math/rand/v2"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
@@ -37,7 +36,7 @@ func createUser(username, password string) (int64, error) {
|
||||
for i := 0; i < 5; i++ {
|
||||
uid := int64(rand.IntN(99999999)) + 1
|
||||
_, lastErr = db.Exec(
|
||||
`INSERT INTO user (uid, created_at, username, password) VALUES (?, ?, ?, ?)`,
|
||||
`INSERT INTO account (uid, created_at, username, password) VALUES ($1, $2, $3, $4)`,
|
||||
uid, now, username, hash,
|
||||
)
|
||||
if lastErr == nil {
|
||||
@@ -45,9 +44,12 @@ func createUser(username, password string) (int64, error) {
|
||||
}
|
||||
// username ist ebenfalls UNIQUE: hat DER kollidiert (Rennen mit der
|
||||
// Vorab-Prüfung des Aufrufers), hilft kein Retry -> gezielt melden.
|
||||
if strings.Contains(lastErr.Error(), "user.username") {
|
||||
if isUniqueViolation(lastErr, "account_username_key") {
|
||||
return 0, errUsernameTaken
|
||||
}
|
||||
if !isUniqueViolation(lastErr, "account_uid_key") {
|
||||
return 0, lastErr
|
||||
}
|
||||
}
|
||||
return 0, lastErr
|
||||
}
|
||||
@@ -55,7 +57,7 @@ func createUser(username, password string) (int64, error) {
|
||||
// idFromUsername liefert die interne id oder 0, wenn der Nutzer nicht existiert.
|
||||
func idFromUsername(username string) int64 {
|
||||
var id int64
|
||||
if err := db.QueryRow(`SELECT id FROM user WHERE username = ?`, username).Scan(&id); err != nil {
|
||||
if err := db.QueryRow(`SELECT id FROM account WHERE username = $1`, username).Scan(&id); err != nil {
|
||||
return 0
|
||||
}
|
||||
return id
|
||||
@@ -72,7 +74,7 @@ func handleUserPage(w http.ResponseWriter, r *http.Request) error {
|
||||
|
||||
var uid, createdAt int64
|
||||
var avatar string
|
||||
err := db.QueryRow(`SELECT uid, created_at, avatar FROM user WHERE username = ?`, username).Scan(&uid, &createdAt, &avatar)
|
||||
err := db.QueryRow(`SELECT uid, created_at, avatar FROM account WHERE username = $1`, username).Scan(&uid, &createdAt, &avatar)
|
||||
if err != nil {
|
||||
return errUserNotFound
|
||||
}
|
||||
@@ -89,7 +91,7 @@ func handleUserPage(w http.ResponseWriter, r *http.Request) error {
|
||||
// registrierte Nutzer und nicht-gelöschte Beiträge.
|
||||
func handleStats(w http.ResponseWriter, r *http.Request) {
|
||||
var users, entries int64
|
||||
db.QueryRow(`SELECT COUNT(*) FROM user`).Scan(&users)
|
||||
db.QueryRow(`SELECT COUNT(*) FROM account`).Scan(&users)
|
||||
db.QueryRow(`SELECT COUNT(*) FROM entry WHERE deleted = 0`).Scan(&entries)
|
||||
writeJSON(w, http.StatusOK, map[string]any{
|
||||
"users": users,
|
||||
@@ -103,7 +105,7 @@ func handleUserInfo(w http.ResponseWriter, r *http.Request) error {
|
||||
var createdAt, lastLogin sql.NullInt64
|
||||
var username, avatar string
|
||||
err := db.QueryRow(
|
||||
`SELECT created_at, last_login, username, avatar FROM user WHERE uid = ?`, uid,
|
||||
`SELECT created_at, last_login, username, avatar FROM account WHERE uid = $1`, uid,
|
||||
).Scan(&createdAt, &lastLogin, &username, &avatar)
|
||||
if err != nil {
|
||||
return errUserNotFound
|
||||
@@ -129,7 +131,7 @@ func handleUserRename(w http.ResponseWriter, r *http.Request) error {
|
||||
}
|
||||
|
||||
var current string
|
||||
if err := db.QueryRow(`SELECT username FROM user WHERE uid = ?`, uid).Scan(¤t); err != nil {
|
||||
if err := db.QueryRow(`SELECT username FROM account WHERE uid = $1`, uid).Scan(¤t); err != nil {
|
||||
return errUserNotFound
|
||||
}
|
||||
if name == current {
|
||||
@@ -139,9 +141,9 @@ func handleUserRename(w http.ResponseWriter, r *http.Request) error {
|
||||
return errUsernameTaken
|
||||
}
|
||||
|
||||
if _, err := db.Exec(`UPDATE user SET username = ? WHERE uid = ?`, name, uid); err != nil {
|
||||
if _, err := db.Exec(`UPDATE account SET username = $1 WHERE uid = $2`, name, uid); err != nil {
|
||||
// Rennen zwischen Vorab-Prüfung und UPDATE: UNIQUE-Constraint -> 409.
|
||||
if strings.Contains(err.Error(), "user.username") {
|
||||
if isUniqueViolation(err, "account_username_key") {
|
||||
return errUsernameTaken
|
||||
}
|
||||
return Internal(err)
|
||||
@@ -171,9 +173,9 @@ func handleSetAvatar(w http.ResponseWriter, r *http.Request) error {
|
||||
}
|
||||
|
||||
var old string
|
||||
db.QueryRow(`SELECT avatar FROM user WHERE uid = ?`, uid).Scan(&old)
|
||||
db.QueryRow(`SELECT avatar FROM account WHERE uid = $1`, uid).Scan(&old)
|
||||
|
||||
if _, err := db.Exec(`UPDATE user SET avatar = ? WHERE uid = ?`, stored, uid); err != nil {
|
||||
if _, err := db.Exec(`UPDATE account SET avatar = $1 WHERE uid = $2`, stored, uid); err != nil {
|
||||
os.Remove(stored)
|
||||
return Internal(err)
|
||||
}
|
||||
@@ -193,7 +195,7 @@ func handleUserDelete(w http.ResponseWriter, r *http.Request) error {
|
||||
uid := uidFromContext(r.Context())
|
||||
|
||||
var hash []byte
|
||||
if err := db.QueryRow(`SELECT password FROM user WHERE uid = ?`, uid).Scan(&hash); err != nil {
|
||||
if err := db.QueryRow(`SELECT password FROM account WHERE uid = $1`, uid).Scan(&hash); err != nil {
|
||||
return errUserNotFound
|
||||
}
|
||||
|
||||
@@ -204,7 +206,7 @@ func handleUserDelete(w http.ResponseWriter, r *http.Request) error {
|
||||
// Mediendateien der Beiträge (und das Profilbild) einsammeln, bevor die
|
||||
// Pfade geleert bzw. die user-Zeile gelöscht wird.
|
||||
var media []string
|
||||
if rows, err := db.Query(`SELECT filepath FROM entry WHERE uid = ?`, uid); err == nil {
|
||||
if rows, err := db.Query(`SELECT filepath FROM entry WHERE uid = $1`, uid); err == nil {
|
||||
for rows.Next() {
|
||||
var fp string
|
||||
if rows.Scan(&fp) == nil && fp != "" {
|
||||
@@ -214,7 +216,7 @@ func handleUserDelete(w http.ResponseWriter, r *http.Request) error {
|
||||
rows.Close()
|
||||
}
|
||||
var avatar string
|
||||
if db.QueryRow(`SELECT avatar FROM user WHERE uid = ?`, uid).Scan(&avatar) == nil && avatar != "" {
|
||||
if db.QueryRow(`SELECT avatar FROM account WHERE uid = $1`, uid).Scan(&avatar) == nil && avatar != "" {
|
||||
media = append(media, avatar)
|
||||
}
|
||||
|
||||
@@ -223,10 +225,10 @@ func handleUserDelete(w http.ResponseWriter, r *http.Request) error {
|
||||
return Internal(err)
|
||||
}
|
||||
for _, q := range []string{
|
||||
`DELETE FROM session WHERE uid = ?`,
|
||||
`DELETE FROM vote WHERE uid = ?`,
|
||||
`UPDATE entry SET deleted = 1, content = '', filepath = '', uid = 0 WHERE uid = ?`,
|
||||
`DELETE FROM user WHERE uid = ?`,
|
||||
`DELETE FROM session WHERE uid = $1`,
|
||||
`DELETE FROM vote WHERE uid = $1`,
|
||||
`UPDATE entry SET deleted = 1, content = '', filepath = '', uid = 0 WHERE uid = $1`,
|
||||
`DELETE FROM account WHERE uid = $1`,
|
||||
} {
|
||||
if _, err := tx.Exec(q, uid); err != nil {
|
||||
tx.Rollback()
|
||||
|
||||
Reference in New Issue
Block a user