Change primary keys and remove id column

This commit is contained in:
Melon 2025-01-08 01:03:05 +00:00
parent 2193c44252
commit fbe0863d36
Signed by: melon
GPG Key ID: 6C9D970C50D26A25
7 changed files with 234 additions and 18 deletions

View File

@ -2,6 +2,8 @@ package api
import ( import (
"context" "context"
"crypto/rand"
"encoding/hex"
"encoding/json" "encoding/json"
"github.com/1f349/bluebell/database" "github.com/1f349/bluebell/database"
"github.com/1f349/bluebell/upload" "github.com/1f349/bluebell/upload"
@ -14,18 +16,95 @@ import (
) )
type apiDB interface { type apiDB interface {
SetDomainBranchEnabled(ctx context.Context, arg database.SetDomainBranchEnabledParams) error AddSite(ctx context.Context, arg database.AddSiteParams) error
UpdateSiteToken(ctx context.Context, arg database.UpdateSiteTokenParams) error
SetBranchEnabled(ctx context.Context, arg database.SetBranchEnabledParams) error
} }
func New(upload *upload.Handler, keyStore *mjwt.KeyStore, db apiDB) *httprouter.Router { func New(upload *upload.Handler, keyStore *mjwt.KeyStore, db apiDB) *httprouter.Router {
router := httprouter.New() router := httprouter.New()
// Site upload endpoint
router.POST("/u/:site/:branch", upload.Handle) router.POST("/u/:site/:branch", upload.Handle)
// Site creation endpoint
router.PUT("/sites/:host", checkAuth(keyStore, func(rw http.ResponseWriter, req *http.Request, params httprouter.Params, b AuthClaims) {
host := params.ByName("host")
if !validation.IsValidSite(host) {
http.Error(rw, "Invalid site", http.StatusBadRequest)
return
}
if !validateDomainOwnershipClaims(host, b.Claims.Perms) {
http.Error(rw, "Forbidden", http.StatusForbidden)
return
}
token, err := generateToken()
if err != nil {
http.Error(rw, "Failed to generate token", http.StatusInternalServerError)
return
}
err = db.AddSite(req.Context(), database.AddSiteParams{
Domain: host,
Token: token,
})
if err != nil {
http.Error(rw, "Failed to register site", http.StatusInternalServerError)
return
}
rw.WriteHeader(http.StatusOK)
_ = json.NewEncoder(rw).Encode(struct {
Token string `json:"token"`
}{Token: token})
}))
// Reset site token endpoint
router.POST("/sites/:host/reset-token", checkAuth(keyStore, func(rw http.ResponseWriter, req *http.Request, params httprouter.Params, b AuthClaims) {
host := params.ByName("host")
if !validation.IsValidSite(host) {
http.Error(rw, "Invalid site", http.StatusBadRequest)
return
}
if !validateDomainOwnershipClaims(host, b.Claims.Perms) {
http.Error(rw, "Forbidden", http.StatusForbidden)
return
}
token, err := generateToken()
if err != nil {
http.Error(rw, "Failed to generate token", http.StatusInternalServerError)
return
}
err = db.UpdateSiteToken(req.Context(), database.UpdateSiteTokenParams{
Domain: host,
Token: token,
})
if err != nil {
http.Error(rw, "Failed to register site", http.StatusInternalServerError)
return
}
rw.WriteHeader(http.StatusOK)
_ = json.NewEncoder(rw).Encode(struct {
Token string `json:"token"`
}{Token: token})
}))
// Enable/disable site branch
router.PUT("/sites/:host/:branch/enable", checkAuth(keyStore, func(rw http.ResponseWriter, req *http.Request, params httprouter.Params, b AuthClaims) { router.PUT("/sites/:host/:branch/enable", checkAuth(keyStore, func(rw http.ResponseWriter, req *http.Request, params httprouter.Params, b AuthClaims) {
setEnabled(rw, req, params, b, db, true) setEnabled(rw, req, params, b, db, true)
})) }))
router.DELETE("/sites/:host/:branch/enable", checkAuth(keyStore, func(rw http.ResponseWriter, req *http.Request, params httprouter.Params, b AuthClaims) { router.DELETE("/sites/:host/:branch/enable", checkAuth(keyStore, func(rw http.ResponseWriter, req *http.Request, params httprouter.Params, b AuthClaims) {
setEnabled(rw, req, params, b, db, false) setEnabled(rw, req, params, b, db, false)
})) }))
return router return router
} }
@ -48,7 +127,7 @@ func setEnabled(rw http.ResponseWriter, req *http.Request, params httprouter.Par
return return
} }
err := db.SetDomainBranchEnabled(req.Context(), database.SetDomainBranchEnabledParams{ err := db.SetBranchEnabled(req.Context(), database.SetBranchEnabledParams{
Domain: host, Domain: host,
Branch: branch, Branch: branch,
Enable: enable, Enable: enable,
@ -57,7 +136,17 @@ func setEnabled(rw http.ResponseWriter, req *http.Request, params httprouter.Par
http.Error(rw, "Failed to update branch state", http.StatusInternalServerError) http.Error(rw, "Failed to update branch state", http.StatusInternalServerError)
return return
} }
rw.WriteHeader(http.StatusAccepted)
rw.WriteHeader(http.StatusOK)
}
func generateToken() (string, error) {
b := make([]byte, 32)
_, err := rand.Read(b)
if err != nil {
return "", err
}
return hex.EncodeToString(b), nil
} }
// apiError outputs a generic JSON error message // apiError outputs a generic JSON error message

View File

@ -0,0 +1,30 @@
ALTER TABLE sites RENAME TO sites_new;
ALTER TABLE branches RENAME TO branches_new;
CREATE TABLE sites
(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
domain TEXT NOT NULL,
token TEXT NOT NULL
);
CREATE TABLE branches
(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
domain TEXT NOT NULL,
branch TEXT NOT NULL,
last_update DATETIME NOT NULL,
enable BOOLEAN NOT NULL
);
INSERT INTO sites (domain, token)
SELECT domain, token
FROM sites_new;
INSERT INTO branches (domain, branch, last_update, enable)
SELECT domain, branch, last_update, enable
FROM branches_new;
DROP TABLE sites_new;
DROP TABLE branches_new;

View File

@ -0,0 +1,29 @@
ALTER TABLE sites RENAME TO sites_old;
ALTER TABLE branches RENAME TO branches_old;
CREATE TABLE sites
(
domain TEXT NOT NULL PRIMARY KEY,
token TEXT NOT NULL
);
CREATE TABLE branches
(
domain TEXT NOT NULL,
branch TEXT NOT NULL,
last_update DATETIME NOT NULL,
enable BOOLEAN NOT NULL,
PRIMARY KEY (domain, branch)
);
INSERT INTO sites
SELECT domain, token
FROM sites_old;
INSERT INTO branches
SELECT domain, branch, last_update, enable
FROM branches_old;
DROP TABLE sites_old;
DROP TABLE branches_old;

View File

@ -9,7 +9,6 @@ import (
) )
type Branch struct { type Branch struct {
ID int64 `json:"id"`
Domain string `json:"domain"` Domain string `json:"domain"`
Branch string `json:"branch"` Branch string `json:"branch"`
LastUpdate time.Time `json:"last_update"` LastUpdate time.Time `json:"last_update"`
@ -17,7 +16,6 @@ type Branch struct {
} }
type Site struct { type Site struct {
ID int64 `json:"id"`
Domain string `json:"domain"` Domain string `json:"domain"`
Token string `json:"token"` Token string `json:"token"`
} }

View File

@ -12,11 +12,26 @@ WHERE domain = ?
AND enable = true AND enable = true
LIMIT 1; LIMIT 1;
-- name: AddSiteDomain :exec -- name: AddSite :exec
INSERT INTO sites (domain, token) INSERT INTO sites (domain, token)
VALUES (?, ?); VALUES (?, ?);
-- name: SetDomainBranchEnabled :exec -- name: UpdateSiteToken :exec
UPDATE sites
SET token = ?
WHERE domain = ?;
-- name: AddBranch :exec
INSERT INTO branches (domain, branch, last_update, enable)
VALUES (?, ?, ?, ?);
-- name: UpdateBranch :exec
UPDATE branches
SET last_update = ?
WHERE domain = ?
AND branch = ?;
-- name: SetBranchEnabled :exec
UPDATE branches UPDATE branches
SET enable = ? SET enable = ?
WHERE domain = ? WHERE domain = ?

View File

@ -10,18 +10,40 @@ import (
"time" "time"
) )
const addSiteDomain = `-- name: AddSiteDomain :exec const addBranch = `-- name: AddBranch :exec
INSERT INTO branches (domain, branch, last_update, enable)
VALUES (?, ?, ?, ?)
`
type AddBranchParams struct {
Domain string `json:"domain"`
Branch string `json:"branch"`
LastUpdate time.Time `json:"last_update"`
Enable bool `json:"enable"`
}
func (q *Queries) AddBranch(ctx context.Context, arg AddBranchParams) error {
_, err := q.db.ExecContext(ctx, addBranch,
arg.Domain,
arg.Branch,
arg.LastUpdate,
arg.Enable,
)
return err
}
const addSite = `-- name: AddSite :exec
INSERT INTO sites (domain, token) INSERT INTO sites (domain, token)
VALUES (?, ?) VALUES (?, ?)
` `
type AddSiteDomainParams struct { type AddSiteParams struct {
Domain string `json:"domain"` Domain string `json:"domain"`
Token string `json:"token"` Token string `json:"token"`
} }
func (q *Queries) AddSiteDomain(ctx context.Context, arg AddSiteDomainParams) error { func (q *Queries) AddSite(ctx context.Context, arg AddSiteParams) error {
_, err := q.db.ExecContext(ctx, addSiteDomain, arg.Domain, arg.Token) _, err := q.db.ExecContext(ctx, addSite, arg.Domain, arg.Token)
return err return err
} }
@ -47,7 +69,7 @@ func (q *Queries) GetLastUpdatedByDomainBranch(ctx context.Context, arg GetLastU
} }
const getSiteByDomain = `-- name: GetSiteByDomain :one const getSiteByDomain = `-- name: GetSiteByDomain :one
SELECT id, domain, token SELECT domain, token
FROM sites FROM sites
WHERE domain = ? WHERE domain = ?
LIMIT 1 LIMIT 1
@ -56,24 +78,58 @@ LIMIT 1
func (q *Queries) GetSiteByDomain(ctx context.Context, domain string) (Site, error) { func (q *Queries) GetSiteByDomain(ctx context.Context, domain string) (Site, error) {
row := q.db.QueryRowContext(ctx, getSiteByDomain, domain) row := q.db.QueryRowContext(ctx, getSiteByDomain, domain)
var i Site var i Site
err := row.Scan(&i.ID, &i.Domain, &i.Token) err := row.Scan(&i.Domain, &i.Token)
return i, err return i, err
} }
const setDomainBranchEnabled = `-- name: SetDomainBranchEnabled :exec const setBranchEnabled = `-- name: SetBranchEnabled :exec
UPDATE branches UPDATE branches
SET enable = ? SET enable = ?
WHERE domain = ? WHERE domain = ?
AND branch = ? AND branch = ?
` `
type SetDomainBranchEnabledParams struct { type SetBranchEnabledParams struct {
Enable bool `json:"enable"` Enable bool `json:"enable"`
Domain string `json:"domain"` Domain string `json:"domain"`
Branch string `json:"branch"` Branch string `json:"branch"`
} }
func (q *Queries) SetDomainBranchEnabled(ctx context.Context, arg SetDomainBranchEnabledParams) error { func (q *Queries) SetBranchEnabled(ctx context.Context, arg SetBranchEnabledParams) error {
_, err := q.db.ExecContext(ctx, setDomainBranchEnabled, arg.Enable, arg.Domain, arg.Branch) _, err := q.db.ExecContext(ctx, setBranchEnabled, arg.Enable, arg.Domain, arg.Branch)
return err
}
const updateBranch = `-- name: UpdateBranch :exec
UPDATE branches
SET last_update = ?
WHERE domain = ?
AND branch = ?
`
type UpdateBranchParams struct {
LastUpdate time.Time `json:"last_update"`
Domain string `json:"domain"`
Branch string `json:"branch"`
}
func (q *Queries) UpdateBranch(ctx context.Context, arg UpdateBranchParams) error {
_, err := q.db.ExecContext(ctx, updateBranch, arg.LastUpdate, arg.Domain, arg.Branch)
return err
}
const updateSiteToken = `-- name: UpdateSiteToken :exec
UPDATE sites
SET token = ?
WHERE domain = ?
`
type UpdateSiteTokenParams struct {
Token string `json:"token"`
Domain string `json:"domain"`
}
func (q *Queries) UpdateSiteToken(ctx context.Context, arg UpdateSiteTokenParams) error {
_, err := q.db.ExecContext(ctx, updateSiteToken, arg.Token, arg.Domain)
return err return err
} }

View File

@ -48,7 +48,6 @@ type fakeUploadDB struct {
func (f *fakeUploadDB) GetSiteByDomain(_ context.Context, domain string) (database.Site, error) { func (f *fakeUploadDB) GetSiteByDomain(_ context.Context, domain string) (database.Site, error) {
if domain == "example.com" { if domain == "example.com" {
return database.Site{ return database.Site{
ID: 1,
Domain: "example.com", Domain: "example.com",
Token: "abcd1234", Token: "abcd1234",
}, nil }, nil