repos / git-pr

a self-hosted git collaboration server
git clone https://github.com/picosh/git-pr.git

commit
7f9ad09
parent
c687eee
author
Eric Bower
date
2024-06-25 09:56:40 -0400 EDT
refactor: user model
5 files changed,  +72, -40
M cli.go
M db.go
M pr.go
M web.go
M backend.go
+11, -0
 1@@ -1,6 +1,8 @@
 2 package git
 3 
 4 import (
 5+	"encoding/base64"
 6+	"fmt"
 7 	"log/slog"
 8 	"path/filepath"
 9 
10@@ -28,9 +30,18 @@ func (be *Backend) RepoID(name string) string {
11 }
12 
13 func (be *Backend) Pubkey(pk ssh.PublicKey) string {
14+	return be.KeyForKeyText(pk)
15+}
16+
17+func (be *Backend) KeyForFingerprint(pk ssh.PublicKey) string {
18 	return gossh.FingerprintSHA256(pk)
19 }
20 
21+func (be *Backend) KeyForKeyText(pk ssh.PublicKey) string {
22+	kb := base64.StdEncoding.EncodeToString(pk.Marshal())
23+	return fmt.Sprintf("%s %s", pk.Type(), kb)
24+}
25+
26 func (be *Backend) KeysEqual(pka, pkb string) bool {
27 	return pka == pkb
28 }
M cli.go
+6, -24
 1@@ -216,10 +216,7 @@ Here's how it works:
 2 						Args:      true,
 3 						ArgsUsage: "[repoID]",
 4 						Action: func(cCtx *cli.Context) error {
 5-							user, err := pr.UpsertUser(&User{
 6-								Pubkey: pubkey,
 7-								Name:   userName,
 8-							})
 9+							user, err := pr.UpsertUser(pubkey, userName)
10 							if err != nil {
11 								return err
12 							}
13@@ -452,10 +449,7 @@ Here's how it works:
14 								return fmt.Errorf("PR has already been accepted")
15 							}
16 
17-							user, err := pr.UpsertUser(&User{
18-								Pubkey: pubkey,
19-								Name:   userName,
20-							})
21+							user, err := pr.UpsertUser(pubkey, userName)
22 							if err != nil {
23 								return err
24 							}
25@@ -478,10 +472,7 @@ Here's how it works:
26 								return err
27 							}
28 
29-							user, err := pr.UpsertUser(&User{
30-								Pubkey: pubkey,
31-								Name:   userName,
32-							})
33+							user, err := pr.UpsertUser(pubkey, userName)
34 							if err != nil {
35 								return err
36 							}
37@@ -524,10 +515,7 @@ Here's how it works:
38 								return err
39 							}
40 
41-							user, err := pr.UpsertUser(&User{
42-								Pubkey: pubkey,
43-								Name:   userName,
44-							})
45+							user, err := pr.UpsertUser(pubkey, userName)
46 							if err != nil {
47 								return err
48 							}
49@@ -565,10 +553,7 @@ Here's how it works:
50 								return err
51 							}
52 
53-							user, err := pr.UpsertUser(&User{
54-								Pubkey: pubkey,
55-								Name:   userName,
56-							})
57+							user, err := pr.UpsertUser(pubkey, userName)
58 							if err != nil {
59 								return err
60 							}
61@@ -622,10 +607,7 @@ Here's how it works:
62 								return err
63 							}
64 
65-							user, err := pr.UpsertUser(&User{
66-								Pubkey: pubkey,
67-								Name:   userName,
68-							})
69+							user, err := pr.UpsertUser(pubkey, userName)
70 							if err != nil {
71 								return err
72 							}
M db.go
+5, -5
 1@@ -68,13 +68,13 @@ type DB struct {
 2 var schema = `
 3 CREATE TABLE IF NOT EXISTS app_users (
 4   id INTEGER PRIMARY KEY AUTOINCREMENT,
 5-  pubkey UNIQUE TEXT NOT NULL,
 6-  name UNIQUE TEXT NOT NULL,
 7+  pubkey TEXT NOT NULL UNIQUE,
 8+  name TEXT NOT NULL UNIQUE,
 9   created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
10-  updated_at DATETIME NOT NULL,
11+  updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
12 );
13 
14-CREATE TABLE IF NOT EXISTS acl {
15+CREATE TABLE IF NOT EXISTS acl (
16   id INTEGER PRIMARY KEY AUTOINCREMENT,
17   user_id INTEGER,
18   ip_address string,
19@@ -84,7 +84,7 @@ CREATE TABLE IF NOT EXISTS acl {
20     FOREIGN KEY(user_id) REFERENCES app_users(id)
21     ON DELETE CASCADE
22     ON UPDATE CASCADE
23-}
24+);
25 
26 CREATE TABLE IF NOT EXISTS patch_requests (
27   id INTEGER PRIMARY KEY AUTOINCREMENT,
M pr.go
+45, -6
 1@@ -27,7 +27,7 @@ type GitPatchRequest interface {
 2 	GetUsers() ([]*User, error)
 3 	GetUserByID(userID int64) (*User, error)
 4 	GetUserByPubkey(pubkey string) (*User, error)
 5-	UpsertUser(user *User) (*User, error)
 6+	UpsertUser(pubkey, name string) (*User, error)
 7 	GetRepos() ([]*Repo, error)
 8 	GetReposWithLatestPr() ([]RepoWithLatestPr, error)
 9 	GetRepoByID(repoID string) (*Repo, error)
10@@ -55,19 +55,58 @@ var _ GitPatchRequest = PrCmd{}
11 var _ GitPatchRequest = (*PrCmd)(nil)
12 
13 func (pr PrCmd) GetUsers() ([]*User, error) {
14-	return []*User{}, nil
15+	users := []*User{}
16+	err := pr.Backend.DB.Select(&users, "SELECT * FROM app_users")
17+	return users, err
18 }
19 
20 func (pr PrCmd) GetUserByID(id int64) (*User, error) {
21-	return nil, nil
22+	var user User
23+	err := pr.Backend.DB.Get(&user, "SELECT * FROM app_users WHERE id=?", id)
24+	return &user, err
25 }
26 
27 func (pr PrCmd) GetUserByPubkey(pubkey string) (*User, error) {
28-	return nil, nil
29+	var user User
30+	err := pr.Backend.DB.Get(&user, "SELECT * FROM app_users WHERE pubkey=?", pubkey)
31+	return &user, err
32 }
33 
34-func (pr PrCmd) UpsertUser(user *User) (*User, error) {
35-	return nil, nil
36+func (pr PrCmd) createUser(pubkey, name string) (*User, error) {
37+	if pubkey == "" {
38+		return nil, fmt.Errorf("must provide pubkey when creating user")
39+	}
40+	if name == "" {
41+		return nil, fmt.Errorf("must provide user name when creating user")
42+	}
43+
44+	var userID int64
45+	row := pr.Backend.DB.QueryRow(
46+		"INSERT INTO app_users (pubkey, name) VALUES (?, ?) RETURNING id",
47+		pubkey,
48+		name,
49+	)
50+	err := row.Scan(&userID)
51+	if err != nil {
52+		return nil, err
53+	}
54+	if userID == 0 {
55+		return nil, fmt.Errorf("could not create user")
56+	}
57+
58+	user, err := pr.GetUserByID(userID)
59+	return user, err
60+}
61+
62+func (pr PrCmd) UpsertUser(pubkey, name string) (*User, error) {
63+	if pubkey == "" {
64+		return nil, fmt.Errorf("must provide pubkey during upsert")
65+	}
66+	user, err := pr.GetUserByPubkey(pubkey)
67+	if err != nil {
68+		user, err = pr.createUser(pubkey, name)
69+	}
70+	return user, err
71 }
72 
73 type PrWithRepo struct {
M web.go
+5, -5
 1@@ -141,7 +141,7 @@ func repoListHandler(w http.ResponseWriter, r *http.Request) {
 2 		Repos: repoData,
 3 	})
 4 	if err != nil {
 5-		fmt.Println(err)
 6+		web.Backend.Logger.Error("cannot execute template", "err", err)
 7 	}
 8 }
 9 
10@@ -169,7 +169,7 @@ func repoDetailHandler(w http.ResponseWriter, r *http.Request) {
11 
12 	web, err := getWebCtx(r)
13 	if err != nil {
14-		fmt.Println(err)
15+		web.Logger.Error("fetch web", "err", err)
16 		w.WriteHeader(http.StatusInternalServerError)
17 		return
18 	}
19@@ -231,7 +231,7 @@ func repoDetailHandler(w http.ResponseWriter, r *http.Request) {
20 		ReviewedPrs: reviewedList,
21 	})
22 	if err != nil {
23-		fmt.Println(err)
24+		web.Backend.Logger.Error("cannot execute template", "err", err)
25 	}
26 }
27 
28@@ -334,7 +334,7 @@ func prDetailHandler(w http.ResponseWriter, r *http.Request) {
29 		},
30 	})
31 	if err != nil {
32-		fmt.Println(err)
33+		web.Backend.Logger.Error("cannot execute template", "err", err)
34 	}
35 }
36 
37@@ -452,7 +452,7 @@ func chromaStyleHandler(w http.ResponseWriter, r *http.Request) {
38 	w.Header().Add("content-type", "text/css")
39 	err = web.Formatter.WriteCSS(w, web.Theme)
40 	if err != nil {
41-		fmt.Println(err)
42+		web.Backend.Logger.Error("cannot write css file", "err", err)
43 	}
44 }
45