mirror of
https://github.com/1f349/site-hosting.git
synced 2025-01-20 22:26:37 +00:00
Change primary keys and remove id column
This commit is contained in:
parent
2193c44252
commit
fbe0863d36
95
api/api.go
95
api/api.go
@ -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
|
||||||
|
@ -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;
|
@ -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;
|
@ -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"`
|
||||||
}
|
}
|
||||||
|
@ -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 = ?
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user