forked from tangled.org/core
this repo has no description

implement transactions

+14 -2
appview/db/db.go
··· 1 package db 2 3 import ( 4 "database/sql" 5 6 _ "github.com/mattn/go-sqlite3" 7 ) 8 9 type DB struct { 10 - db *sql.DB 11 } 12 13 func Make(dbPath string) (*DB, error) { ··· 104 if err != nil { 105 return nil, err 106 } 107 - return &DB{db: db}, nil 108 }
··· 1 package db 2 3 import ( 4 + "context" 5 "database/sql" 6 7 _ "github.com/mattn/go-sqlite3" 8 ) 9 10 type DB struct { 11 + *sql.DB 12 + } 13 + 14 + type Execer interface { 15 + Query(query string, args ...any) (*sql.Rows, error) 16 + QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error) 17 + QueryRow(query string, args ...any) *sql.Row 18 + QueryRowContext(ctx context.Context, query string, args ...any) *sql.Row 19 + Exec(query string, args ...any) (sql.Result, error) 20 + ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error) 21 + Prepare(query string) (*sql.Stmt, error) 22 + PrepareContext(ctx context.Context, query string) (*sql.Stmt, error) 23 } 24 25 func Make(dbPath string) (*DB, error) { ··· 116 if err != nil { 117 return nil, err 118 } 119 + return &DB{db}, nil 120 }
+12 -12
appview/db/follow.go
··· 12 RKey string 13 } 14 15 - func (d *DB) AddFollow(userDid, subjectDid, rkey string) error { 16 query := `insert or ignore into follows (user_did, subject_did, rkey) values (?, ?, ?)` 17 - _, err := d.db.Exec(query, userDid, subjectDid, rkey) 18 return err 19 } 20 21 // Get a follow record 22 - func (d *DB) GetFollow(userDid, subjectDid string) (*Follow, error) { 23 query := `select user_did, subject_did, followed_at, rkey from follows where user_did = ? and subject_did = ?` 24 - row := d.db.QueryRow(query, userDid, subjectDid) 25 26 var follow Follow 27 var followedAt string ··· 42 } 43 44 // Get a follow record 45 - func (d *DB) DeleteFollow(userDid, subjectDid string) error { 46 - _, err := d.db.Exec(`delete from follows where user_did = ? and subject_did = ?`, userDid, subjectDid) 47 return err 48 } 49 50 - func (d *DB) GetFollowerFollowing(did string) (int, int, error) { 51 followers, following := 0, 0 52 - err := d.db.QueryRow( 53 `SELECT 54 COUNT(CASE WHEN subject_did = ? THEN 1 END) AS followers, 55 COUNT(CASE WHEN user_did = ? THEN 1 END) AS following ··· 81 } 82 } 83 84 - func (d *DB) GetFollowStatus(userDid, subjectDid string) FollowStatus { 85 if userDid == subjectDid { 86 return IsSelf 87 - } else if _, err := d.GetFollow(userDid, subjectDid); err != nil { 88 return IsNotFollowing 89 } else { 90 return IsFollowing 91 } 92 } 93 94 - func (d *DB) GetAllFollows() ([]Follow, error) { 95 var follows []Follow 96 97 - rows, err := d.db.Query(`select user_did, subject_did, followed_at, rkey from follows`) 98 if err != nil { 99 return nil, err 100 }
··· 12 RKey string 13 } 14 15 + func AddFollow(e Execer, userDid, subjectDid, rkey string) error { 16 query := `insert or ignore into follows (user_did, subject_did, rkey) values (?, ?, ?)` 17 + _, err := e.Exec(query, userDid, subjectDid, rkey) 18 return err 19 } 20 21 // Get a follow record 22 + func GetFollow(e Execer, userDid, subjectDid string) (*Follow, error) { 23 query := `select user_did, subject_did, followed_at, rkey from follows where user_did = ? and subject_did = ?` 24 + row := e.QueryRow(query, userDid, subjectDid) 25 26 var follow Follow 27 var followedAt string ··· 42 } 43 44 // Get a follow record 45 + func DeleteFollow(e Execer, userDid, subjectDid string) error { 46 + _, err := e.Exec(`delete from follows where user_did = ? and subject_did = ?`, userDid, subjectDid) 47 return err 48 } 49 50 + func GetFollowerFollowing(e Execer, did string) (int, int, error) { 51 followers, following := 0, 0 52 + err := e.QueryRow( 53 `SELECT 54 COUNT(CASE WHEN subject_did = ? THEN 1 END) AS followers, 55 COUNT(CASE WHEN user_did = ? THEN 1 END) AS following ··· 81 } 82 } 83 84 + func GetFollowStatus(e Execer, userDid, subjectDid string) FollowStatus { 85 if userDid == subjectDid { 86 return IsSelf 87 + } else if _, err := GetFollow(e, userDid, subjectDid); err != nil { 88 return IsNotFollowing 89 } else { 90 return IsFollowing 91 } 92 } 93 94 + func GetAllFollows(e Execer) ([]Follow, error) { 95 var follows []Follow 96 97 + rows, err := e.Query(`select user_did, subject_did, followed_at, rkey from follows`) 98 if err != nil { 99 return nil, err 100 }
+25 -29
appview/db/issues.go
··· 26 Created *time.Time 27 } 28 29 - func (d *DB) NewIssue(issue *Issue) error { 30 - tx, err := d.db.Begin() 31 - if err != nil { 32 - return err 33 - } 34 defer tx.Rollback() 35 36 - _, err = tx.Exec(` 37 insert or ignore into repo_issue_seqs (repo_at, next_issue_id) 38 values (?, 1) 39 `, issue.RepoAt) ··· 69 return nil 70 } 71 72 - func (d *DB) SetIssueAt(repoAt string, issueId int, issueAt string) error { 73 - _, err := d.db.Exec(`update issues set issue_at = ? where repo_at = ? and issue_id = ?`, issueAt, repoAt, issueId) 74 return err 75 } 76 77 - func (d *DB) GetIssueAt(repoAt string, issueId int) (string, error) { 78 var issueAt string 79 - err := d.db.QueryRow(`select issue_at from issues where repo_at = ? and issue_id = ?`, repoAt, issueId).Scan(&issueAt) 80 return issueAt, err 81 } 82 83 - func (d *DB) GetIssueId(repoAt string) (int, error) { 84 var issueId int 85 - err := d.db.QueryRow(`select next_issue_id from repo_issue_seqs where repo_at = ?`, repoAt).Scan(&issueId) 86 return issueId - 1, err 87 } 88 89 - func (d *DB) GetIssueOwnerDid(repoAt string, issueId int) (string, error) { 90 var ownerDid string 91 - err := d.db.QueryRow(`select owner_did from issues where repo_at = ? and issue_id = ?`, repoAt, issueId).Scan(&ownerDid) 92 return ownerDid, err 93 } 94 95 - func (d *DB) GetIssues(repoAt string) ([]Issue, error) { 96 var issues []Issue 97 98 - rows, err := d.db.Query(`select owner_did, issue_id, created, title, body, open from issues where repo_at = ? order by created desc`, repoAt) 99 if err != nil { 100 return nil, err 101 } ··· 125 return issues, nil 126 } 127 128 - func (d *DB) GetIssue(repoAt string, issueId int) (*Issue, error) { 129 query := `select owner_did, created, title, body, open from issues where repo_at = ? and issue_id = ?` 130 - row := d.db.QueryRow(query, repoAt, issueId) 131 132 var issue Issue 133 var createdAt string ··· 145 return &issue, nil 146 } 147 148 - func (d *DB) GetIssueWithComments(repoAt string, issueId int) (*Issue, []Comment, error) { 149 query := `select owner_did, issue_id, created, title, body, open from issues where repo_at = ? and issue_id = ?` 150 - row := d.db.QueryRow(query, repoAt, issueId) 151 152 var issue Issue 153 var createdAt string ··· 162 } 163 issue.Created = &createdTime 164 165 - comments, err := d.GetComments(repoAt, issueId) 166 if err != nil { 167 return nil, nil, err 168 } ··· 170 return &issue, comments, nil 171 } 172 173 - func (d *DB) NewComment(comment *Comment) error { 174 query := `insert into comments (owner_did, repo_at, comment_at, issue_id, comment_id, body) values (?, ?, ?, ?, ?, ?)` 175 - _, err := d.db.Exec( 176 query, 177 comment.OwnerDid, 178 comment.RepoAt, ··· 184 return err 185 } 186 187 - func (d *DB) GetComments(repoAt string, issueId int) ([]Comment, error) { 188 var comments []Comment 189 190 - rows, err := d.db.Query(`select owner_did, issue_id, comment_id, comment_at, body, created from comments where repo_at = ? and issue_id = ? order by created asc`, repoAt, issueId) 191 if err == sql.ErrNoRows { 192 return []Comment{}, nil 193 } ··· 220 return comments, nil 221 } 222 223 - func (d *DB) CloseIssue(repoAt string, issueId int) error { 224 - _, err := d.db.Exec(`update issues set open = 0 where repo_at = ? and issue_id = ?`, repoAt, issueId) 225 return err 226 } 227 228 - func (d *DB) ReopenIssue(repoAt string, issueId int) error { 229 - _, err := d.db.Exec(`update issues set open = 1 where repo_at = ? and issue_id = ?`, repoAt, issueId) 230 return err 231 }
··· 26 Created *time.Time 27 } 28 29 + func NewIssue(tx *sql.Tx, issue *Issue) error { 30 defer tx.Rollback() 31 32 + _, err := tx.Exec(` 33 insert or ignore into repo_issue_seqs (repo_at, next_issue_id) 34 values (?, 1) 35 `, issue.RepoAt) ··· 65 return nil 66 } 67 68 + func SetIssueAt(e Execer, repoAt string, issueId int, issueAt string) error { 69 + _, err := e.Exec(`update issues set issue_at = ? where repo_at = ? and issue_id = ?`, issueAt, repoAt, issueId) 70 return err 71 } 72 73 + func GetIssueAt(e Execer, repoAt string, issueId int) (string, error) { 74 var issueAt string 75 + err := e.QueryRow(`select issue_at from issues where repo_at = ? and issue_id = ?`, repoAt, issueId).Scan(&issueAt) 76 return issueAt, err 77 } 78 79 + func GetIssueId(e Execer, repoAt string) (int, error) { 80 var issueId int 81 + err := e.QueryRow(`select next_issue_id from repo_issue_seqs where repo_at = ?`, repoAt).Scan(&issueId) 82 return issueId - 1, err 83 } 84 85 + func GetIssueOwnerDid(e Execer, repoAt string, issueId int) (string, error) { 86 var ownerDid string 87 + err := e.QueryRow(`select owner_did from issues where repo_at = ? and issue_id = ?`, repoAt, issueId).Scan(&ownerDid) 88 return ownerDid, err 89 } 90 91 + func GetIssues(e Execer, repoAt string) ([]Issue, error) { 92 var issues []Issue 93 94 + rows, err := e.Query(`select owner_did, issue_id, created, title, body, open from issues where repo_at = ? order by created desc`, repoAt) 95 if err != nil { 96 return nil, err 97 } ··· 121 return issues, nil 122 } 123 124 + func GetIssue(e Execer, repoAt string, issueId int) (*Issue, error) { 125 query := `select owner_did, created, title, body, open from issues where repo_at = ? and issue_id = ?` 126 + row := e.QueryRow(query, repoAt, issueId) 127 128 var issue Issue 129 var createdAt string ··· 141 return &issue, nil 142 } 143 144 + func GetIssueWithComments(e Execer, repoAt string, issueId int) (*Issue, []Comment, error) { 145 query := `select owner_did, issue_id, created, title, body, open from issues where repo_at = ? and issue_id = ?` 146 + row := e.QueryRow(query, repoAt, issueId) 147 148 var issue Issue 149 var createdAt string ··· 158 } 159 issue.Created = &createdTime 160 161 + comments, err := GetComments(e, repoAt, issueId) 162 if err != nil { 163 return nil, nil, err 164 } ··· 166 return &issue, comments, nil 167 } 168 169 + func NewComment(e Execer, comment *Comment) error { 170 query := `insert into comments (owner_did, repo_at, comment_at, issue_id, comment_id, body) values (?, ?, ?, ?, ?, ?)` 171 + _, err := e.Exec( 172 query, 173 comment.OwnerDid, 174 comment.RepoAt, ··· 180 return err 181 } 182 183 + func GetComments(e Execer, repoAt string, issueId int) ([]Comment, error) { 184 var comments []Comment 185 186 + rows, err := e.Query(`select owner_did, issue_id, comment_id, comment_at, body, created from comments where repo_at = ? and issue_id = ? order by created asc`, repoAt, issueId) 187 if err == sql.ErrNoRows { 188 return []Comment{}, nil 189 } ··· 216 return comments, nil 217 } 218 219 + func CloseIssue(e Execer, repoAt string, issueId int) error { 220 + _, err := e.Exec(`update issues set open = 0 where repo_at = ? and issue_id = ?`, repoAt, issueId) 221 return err 222 } 223 224 + func ReopenIssue(e Execer, repoAt string, issueId int) error { 225 + _, err := e.Exec(`update issues set open = 1 where repo_at = ? and issue_id = ?`, repoAt, issueId) 226 return err 227 }
+10 -6
appview/db/jetstream.go
··· 1 package db 2 3 - func (d *DB) SaveLastTimeUs(lastTimeUs int64) error { 4 - _, err := d.db.Exec(`insert into _jetstream (last_time_us) values (?)`, lastTimeUs) 5 return err 6 } 7 8 - func (d *DB) UpdateLastTimeUs(lastTimeUs int64) error { 9 - _, err := d.db.Exec(`update _jetstream set last_time_us = ? where rowid = 1`, lastTimeUs) 10 if err != nil { 11 return err 12 } 13 return nil 14 } 15 16 - func (d *DB) GetLastTimeUs() (int64, error) { 17 var lastTimeUs int64 18 - row := d.db.QueryRow(`select last_time_us from _jetstream`) 19 err := row.Scan(&lastTimeUs) 20 return lastTimeUs, err 21 }
··· 1 package db 2 3 + type DbWrapper struct { 4 + Execer 5 + } 6 + 7 + func (db DbWrapper) SaveLastTimeUs(lastTimeUs int64) error { 8 + _, err := db.Exec(`insert into _jetstream (last_time_us) values (?)`, lastTimeUs) 9 return err 10 } 11 12 + func (db DbWrapper) UpdateLastTimeUs(lastTimeUs int64) error { 13 + _, err := db.Exec(`update _jetstream set last_time_us = ? where rowid = 1`, lastTimeUs) 14 if err != nil { 15 return err 16 } 17 return nil 18 } 19 20 + func (db DbWrapper) GetLastTimeUs() (int64, error) { 21 var lastTimeUs int64 22 + row := db.QueryRow(`select last_time_us from _jetstream`) 23 err := row.Scan(&lastTimeUs) 24 return lastTimeUs, err 25 }
+8 -8
appview/db/pubkeys.go
··· 5 "time" 6 ) 7 8 - func (d *DB) AddPublicKey(did, name, key string) error { 9 query := `insert or ignore into public_keys (did, name, key) values (?, ?, ?)` 10 - _, err := d.db.Exec(query, did, name, key) 11 return err 12 } 13 14 - func (d *DB) RemovePublicKey(did string) error { 15 query := `delete from public_keys where did = ?` 16 - _, err := d.db.Exec(query, did) 17 return err 18 } 19 ··· 35 }) 36 } 37 38 - func (d *DB) GetAllPublicKeys() ([]PublicKey, error) { 39 var keys []PublicKey 40 41 - rows, err := d.db.Query(`select key, name, did, created from public_keys`) 42 if err != nil { 43 return nil, err 44 } ··· 62 return keys, nil 63 } 64 65 - func (d *DB) GetPublicKeys(did string) ([]PublicKey, error) { 66 var keys []PublicKey 67 68 - rows, err := d.db.Query(`select did, key, name, created from public_keys where did = ?`, did) 69 if err != nil { 70 return nil, err 71 }
··· 5 "time" 6 ) 7 8 + func AddPublicKey(e Execer, did, name, key string) error { 9 query := `insert or ignore into public_keys (did, name, key) values (?, ?, ?)` 10 + _, err := e.Exec(query, did, name, key) 11 return err 12 } 13 14 + func RemovePublicKey(e Execer, did string) error { 15 query := `delete from public_keys where did = ?` 16 + _, err := e.Exec(query, did) 17 return err 18 } 19 ··· 35 }) 36 } 37 38 + func GetAllPublicKeys(e Execer) ([]PublicKey, error) { 39 var keys []PublicKey 40 41 + rows, err := e.Query(`select key, name, did, created from public_keys`) 42 if err != nil { 43 return nil, err 44 } ··· 62 return keys, nil 63 } 64 65 + func GetPublicKeys(e Execer, did string) ([]PublicKey, error) { 66 var keys []PublicKey 67 68 + rows, err := e.Query(`select did, key, name, created from public_keys where did = ?`, did) 69 if err != nil { 70 return nil, err 71 }
+11 -11
appview/db/registration.go
··· 32 ) 33 34 // returns registered status, did of owner, error 35 - func (d *DB) RegistrationsByDid(did string) ([]Registration, error) { 36 var registrations []Registration 37 38 - rows, err := d.db.Query(` 39 select domain, did, created, registered from registrations 40 where did = ? 41 `, did) ··· 69 } 70 71 // returns registered status, did of owner, error 72 - func (d *DB) RegistrationByDomain(domain string) (*Registration, error) { 73 var createdAt *string 74 var registeredAt *string 75 var registration Registration 76 77 - err := d.db.QueryRow(` 78 select domain, did, created, registered from registrations 79 where domain = ? 80 `, domain).Scan(&registration.Domain, &registration.ByDid, &createdAt, &registeredAt) ··· 106 return hex.EncodeToString(key) 107 } 108 109 - func (d *DB) GenerateRegistrationKey(domain, did string) (string, error) { 110 // sanity check: does this domain already have a registration? 111 - reg, err := d.RegistrationByDomain(domain) 112 if err != nil { 113 return "", err 114 } ··· 127 128 secret := genSecret() 129 130 - _, err = d.db.Exec(` 131 insert into registrations (domain, did, secret) 132 values (?, ?, ?) 133 on conflict(domain) do update set did = excluded.did, secret = excluded.secret ··· 140 return secret, nil 141 } 142 143 - func (d *DB) GetRegistrationKey(domain string) (string, error) { 144 - res := d.db.QueryRow(`select secret from registrations where domain = ?`, domain) 145 146 var secret string 147 err := res.Scan(&secret) ··· 152 return secret, nil 153 } 154 155 - func (d *DB) Register(domain string) error { 156 - _, err := d.db.Exec(` 157 update registrations 158 set registered = strftime('%Y-%m-%dT%H:%M:%SZ', 'now') 159 where domain = ?;
··· 32 ) 33 34 // returns registered status, did of owner, error 35 + func RegistrationsByDid(e Execer, did string) ([]Registration, error) { 36 var registrations []Registration 37 38 + rows, err := e.Query(` 39 select domain, did, created, registered from registrations 40 where did = ? 41 `, did) ··· 69 } 70 71 // returns registered status, did of owner, error 72 + func RegistrationByDomain(e Execer, domain string) (*Registration, error) { 73 var createdAt *string 74 var registeredAt *string 75 var registration Registration 76 77 + err := e.QueryRow(` 78 select domain, did, created, registered from registrations 79 where domain = ? 80 `, domain).Scan(&registration.Domain, &registration.ByDid, &createdAt, &registeredAt) ··· 106 return hex.EncodeToString(key) 107 } 108 109 + func GenerateRegistrationKey(e Execer, domain, did string) (string, error) { 110 // sanity check: does this domain already have a registration? 111 + reg, err := RegistrationByDomain(e, domain) 112 if err != nil { 113 return "", err 114 } ··· 127 128 secret := genSecret() 129 130 + _, err = e.Exec(` 131 insert into registrations (domain, did, secret) 132 values (?, ?, ?) 133 on conflict(domain) do update set did = excluded.did, secret = excluded.secret ··· 140 return secret, nil 141 } 142 143 + func GetRegistrationKey(e Execer, domain string) (string, error) { 144 + res := e.QueryRow(`select secret from registrations where domain = ?`, domain) 145 146 var secret string 147 err := res.Scan(&secret) ··· 152 return secret, nil 153 } 154 155 + func Register(e Execer, domain string) error { 156 + _, err := e.Exec(` 157 update registrations 158 set registered = strftime('%Y-%m-%dT%H:%M:%SZ', 'now') 159 where domain = ?;
+14 -14
appview/db/repos.go
··· 14 AtUri string 15 } 16 17 - func (d *DB) GetAllRepos() ([]Repo, error) { 18 var repos []Repo 19 20 - rows, err := d.db.Query(`select did, name, knot, rkey, created from repos`) 21 if err != nil { 22 return nil, err 23 } ··· 39 return repos, nil 40 } 41 42 - func (d *DB) GetAllReposByDid(did string) ([]Repo, error) { 43 var repos []Repo 44 45 - rows, err := d.db.Query(`select did, name, knot, rkey, created from repos where did = ?`, did) 46 if err != nil { 47 return nil, err 48 } ··· 64 return repos, nil 65 } 66 67 - func (d *DB) GetRepo(did, name string) (*Repo, error) { 68 var repo Repo 69 70 - row := d.db.QueryRow(`select did, name, knot, created, at_uri from repos where did = ? and name = ?`, did, name) 71 72 var createdAt string 73 if err := row.Scan(&repo.Did, &repo.Name, &repo.Knot, &createdAt, &repo.AtUri); err != nil { ··· 79 return &repo, nil 80 } 81 82 - func (d *DB) AddRepo(repo *Repo) error { 83 - _, err := d.db.Exec(`insert into repos (did, name, knot, rkey, at_uri) values (?, ?, ?, ?, ?)`, repo.Did, repo.Name, repo.Knot, repo.Rkey, repo.AtUri) 84 return err 85 } 86 87 - func (d *DB) RemoveRepo(did, name, rkey string) error { 88 - _, err := d.db.Exec(`delete from repos where did = ? and name = ? and rkey = ?`, did, name, rkey) 89 return err 90 } 91 92 - func (d *DB) AddCollaborator(collaborator, repoOwnerDid, repoName, repoKnot string) error { 93 - _, err := d.db.Exec( 94 `insert into collaborators (did, repo) 95 values (?, (select id from repos where did = ? and name = ? and knot = ?));`, 96 collaborator, repoOwnerDid, repoName, repoKnot) 97 return err 98 } 99 100 - func (d *DB) CollaboratingIn(collaborator string) ([]Repo, error) { 101 var repos []Repo 102 103 - rows, err := d.db.Query(`select r.did, r.name, r.knot, r.rkey, r.created from repos r join collaborators c on r.id = c.repo where c.did = ?;`, collaborator) 104 if err != nil { 105 return nil, err 106 }
··· 14 AtUri string 15 } 16 17 + func GetAllRepos(e Execer) ([]Repo, error) { 18 var repos []Repo 19 20 + rows, err := e.Query(`select did, name, knot, rkey, created from repos`) 21 if err != nil { 22 return nil, err 23 } ··· 39 return repos, nil 40 } 41 42 + func GetAllReposByDid(e Execer, did string) ([]Repo, error) { 43 var repos []Repo 44 45 + rows, err := e.Query(`select did, name, knot, rkey, created from repos where did = ?`, did) 46 if err != nil { 47 return nil, err 48 } ··· 64 return repos, nil 65 } 66 67 + func GetRepo(e Execer, did, name string) (*Repo, error) { 68 var repo Repo 69 70 + row := e.QueryRow(`select did, name, knot, created, at_uri from repos where did = ? and name = ?`, did, name) 71 72 var createdAt string 73 if err := row.Scan(&repo.Did, &repo.Name, &repo.Knot, &createdAt, &repo.AtUri); err != nil { ··· 79 return &repo, nil 80 } 81 82 + func AddRepo(e Execer, repo *Repo) error { 83 + _, err := e.Exec(`insert into repos (did, name, knot, rkey, at_uri) values (?, ?, ?, ?, ?)`, repo.Did, repo.Name, repo.Knot, repo.Rkey, repo.AtUri) 84 return err 85 } 86 87 + func RemoveRepo(e Execer, did, name, rkey string) error { 88 + _, err := e.Exec(`delete from repos where did = ? and name = ? and rkey = ?`, did, name, rkey) 89 return err 90 } 91 92 + func AddCollaborator(e Execer, collaborator, repoOwnerDid, repoName, repoKnot string) error { 93 + _, err := e.Exec( 94 `insert into collaborators (did, repo) 95 values (?, (select id from repos where did = ? and name = ? and knot = ?));`, 96 collaborator, repoOwnerDid, repoName, repoKnot) 97 return err 98 } 99 100 + func CollaboratingIn(e Execer, collaborator string) ([]Repo, error) { 101 var repos []Repo 102 103 + rows, err := e.Query(`select r.did, r.name, r.knot, r.rkey, r.created from repos r join collaborators c on r.id = c.repo where c.did = ?;`, collaborator) 104 if err != nil { 105 return nil, err 106 }
+3 -3
appview/db/timeline.go
··· 11 EventAt time.Time 12 } 13 14 - func (d *DB) MakeTimeline() ([]TimelineEvent, error) { 15 var events []TimelineEvent 16 17 - repos, err := d.GetAllRepos() 18 if err != nil { 19 return nil, err 20 } 21 22 - follows, err := d.GetAllFollows() 23 if err != nil { 24 return nil, err 25 }
··· 11 EventAt time.Time 12 } 13 14 + func MakeTimeline(e Execer) ([]TimelineEvent, error) { 15 var events []TimelineEvent 16 17 + repos, err := GetAllRepos(e) 18 if err != nil { 19 return nil, err 20 } 21 22 + follows, err := GetAllFollows(e) 23 if err != nil { 24 return nil, err 25 }
+1 -1
appview/pages/templates/repo/new.html
··· 22 type="text" 23 id="branch" 24 name="branch" 25 required 26 class="w-full max-w-md" 27 /> 28 - <p class="text-sm text-gray-500">The default branch is <span class="font-bold">main</span></p> 29 </div> 30 31 <fieldset class="space-y-3">
··· 22 type="text" 23 id="branch" 24 name="branch" 25 + value="main" 26 required 27 class="w-full max-w-md" 28 /> 29 </div> 30 31 <fieldset class="space-y-3">
+4 -3
appview/state/follow.go
··· 9 comatproto "github.com/bluesky-social/indigo/api/atproto" 10 lexutil "github.com/bluesky-social/indigo/lex/util" 11 tangled "github.com/sotangled/tangled/api/tangled" 12 ) 13 14 func (s *State) Follow(w http.ResponseWriter, r *http.Request) { ··· 51 return 52 } 53 54 - err = s.db.AddFollow(currentUser.Did, subjectIdent.DID.String(), rkey) 55 if err != nil { 56 log.Println("failed to follow", err) 57 return ··· 73 return 74 case http.MethodDelete: 75 // find the record in the db 76 - follow, err := s.db.GetFollow(currentUser.Did, subjectIdent.DID.String()) 77 if err != nil { 78 log.Println("failed to get follow relationship") 79 return ··· 90 return 91 } 92 93 - err = s.db.DeleteFollow(currentUser.Did, subjectIdent.DID.String()) 94 if err != nil { 95 log.Println("failed to delete follow from DB") 96 // this is not an issue, the firehose event might have already done this
··· 9 comatproto "github.com/bluesky-social/indigo/api/atproto" 10 lexutil "github.com/bluesky-social/indigo/lex/util" 11 tangled "github.com/sotangled/tangled/api/tangled" 12 + "github.com/sotangled/tangled/appview/db" 13 ) 14 15 func (s *State) Follow(w http.ResponseWriter, r *http.Request) { ··· 52 return 53 } 54 55 + err = db.AddFollow(s.db, currentUser.Did, subjectIdent.DID.String(), rkey) 56 if err != nil { 57 log.Println("failed to follow", err) 58 return ··· 74 return 75 case http.MethodDelete: 76 // find the record in the db 77 + follow, err := db.GetFollow(s.db, currentUser.Did, subjectIdent.DID.String()) 78 if err != nil { 79 log.Println("failed to get follow relationship") 80 return ··· 91 return 92 } 93 94 + err = db.DeleteFollow(s.db, currentUser.Did, subjectIdent.DID.String()) 95 if err != nil { 96 log.Println("failed to delete follow from DB") 97 // this is not an issue, the firehose event might have already done this
+3 -3
appview/state/jetstream.go
··· 13 14 type Ingester func(ctx context.Context, e *models.Event) error 15 16 - func jetstreamIngester(db *db.DB) Ingester { 17 return func(ctx context.Context, e *models.Event) error { 18 var err error 19 defer func() { 20 eventTime := e.TimeUS 21 lastTimeUs := eventTime + 1 22 - if err := db.UpdateLastTimeUs(lastTimeUs); err != nil { 23 err = fmt.Errorf("(deferred) failed to save last time us: %w", err) 24 } 25 }() ··· 39 log.Println("invalid record") 40 return err 41 } 42 - err = db.AddFollow(did, record.Subject, e.Commit.RKey) 43 if err != nil { 44 return fmt.Errorf("failed to add follow to db: %w", err) 45 }
··· 13 14 type Ingester func(ctx context.Context, e *models.Event) error 15 16 + func jetstreamIngester(d db.DbWrapper) Ingester { 17 return func(ctx context.Context, e *models.Event) error { 18 var err error 19 defer func() { 20 eventTime := e.TimeUS 21 lastTimeUs := eventTime + 1 22 + if err := d.UpdateLastTimeUs(lastTimeUs); err != nil { 23 err = fmt.Errorf("(deferred) failed to save last time us: %w", err) 24 } 25 }() ··· 39 log.Println("invalid record") 40 return err 41 } 42 + err = db.AddFollow(d, did, record.Subject, e.Commit.RKey) 43 if err != nil { 44 return fmt.Errorf("failed to add follow to db: %w", err) 45 }
+2 -1
appview/state/middleware.go
··· 13 "github.com/go-chi/chi/v5" 14 "github.com/sotangled/tangled/appview" 15 "github.com/sotangled/tangled/appview/auth" 16 ) 17 18 type Middleware func(http.Handler) http.Handler ··· 176 return 177 } 178 179 - repo, err := s.db.GetRepo(id.DID.String(), repoName) 180 if err != nil { 181 // invalid did or handle 182 log.Println("failed to resolve repo")
··· 13 "github.com/go-chi/chi/v5" 14 "github.com/sotangled/tangled/appview" 15 "github.com/sotangled/tangled/appview/auth" 16 + "github.com/sotangled/tangled/appview/db" 17 ) 18 19 type Middleware func(http.Handler) http.Handler ··· 177 return 178 } 179 180 + repo, err := db.GetRepo(s.db, id.DID.String(), repoName) 181 if err != nil { 182 // invalid did or handle 183 log.Println("failed to resolve repo")
+46 -12
appview/state/repo.go
··· 389 390 // TODO: create an atproto record for this 391 392 - secret, err := s.db.GetRegistrationKey(f.Knot) 393 if err != nil { 394 log.Printf("no key found for domain %s: %s\n", f.Knot, err) 395 return ··· 412 return 413 } 414 415 err = s.enforcer.AddCollaborator(collaboratorIdent.DID.String(), f.Knot, f.OwnerSlashRepo()) 416 if err != nil { 417 w.Write([]byte(fmt.Sprint("failed to add collaborator: ", err))) 418 return 419 } 420 421 - err = s.db.AddCollaborator(collaboratorIdent.DID.String(), f.OwnerDid(), f.RepoName, f.Knot) 422 if err != nil { 423 w.Write([]byte(fmt.Sprint("failed to add collaborator: ", err))) 424 return 425 } 426 427 w.Write([]byte(fmt.Sprint("added collaborator: ", collaboratorIdent.Handle.String()))) 428 429 } ··· 546 return 547 } 548 549 - issue, comments, err := s.db.GetIssueWithComments(f.RepoAt, issueIdInt) 550 if err != nil { 551 log.Println("failed to get issue and comments", err) 552 s.pages.Notice(w, "issues", "Failed to load issue. Try again later.") ··· 605 return 606 } 607 608 - issue, err := s.db.GetIssue(f.RepoAt, issueIdInt) 609 if err != nil { 610 log.Println("failed to get issue", err) 611 s.pages.Notice(w, "issue-action", "Failed to close issue. Try again later.") ··· 645 return 646 } 647 648 - err := s.db.CloseIssue(f.RepoAt, issueIdInt) 649 if err != nil { 650 log.Println("failed to close issue", err) 651 s.pages.Notice(w, "issue-action", "Failed to close issue. Try again later.") ··· 678 } 679 680 if user.Did == f.OwnerDid() { 681 - err := s.db.ReopenIssue(f.RepoAt, issueIdInt) 682 if err != nil { 683 log.Println("failed to reopen issue", err) 684 s.pages.Notice(w, "issue-action", "Failed to reopen issue. Try again later.") ··· 719 720 commentId := rand.IntN(1000000) 721 722 - err := s.db.NewComment(&db.Comment{ 723 OwnerDid: user.Did, 724 RepoAt: f.RepoAt, 725 Issue: issueIdInt, ··· 735 createdAt := time.Now().Format(time.RFC3339) 736 commentIdInt64 := int64(commentId) 737 ownerDid := user.Did 738 - issueAt, err := s.db.GetIssueAt(f.RepoAt, issueIdInt) 739 if err != nil { 740 log.Println("failed to get issue at", err) 741 s.pages.Notice(w, "issue-comment", "Failed to create comment.") ··· 777 return 778 } 779 780 - issues, err := s.db.GetIssues(f.RepoAt) 781 if err != nil { 782 log.Println("failed to get issues", err) 783 s.pages.Notice(w, "issues", "Failed to load issues. Try again later.") ··· 841 return 842 } 843 844 - err = s.db.NewIssue(&db.Issue{ 845 RepoAt: f.RepoAt, 846 Title: title, 847 Body: body, ··· 853 return 854 } 855 856 - issueId, err := s.db.GetIssueId(f.RepoAt) 857 if err != nil { 858 log.Println("failed to get issue id", err) 859 s.pages.Notice(w, "issues", "Failed to create issue.") ··· 881 return 882 } 883 884 - err = s.db.SetIssueAt(f.RepoAt, issueId, resp.Uri) 885 if err != nil { 886 log.Println("failed to set issue at", err) 887 s.pages.Notice(w, "issues", "Failed to create issue.")
··· 389 390 // TODO: create an atproto record for this 391 392 + secret, err := db.GetRegistrationKey(s.db, f.Knot) 393 if err != nil { 394 log.Printf("no key found for domain %s: %s\n", f.Knot, err) 395 return ··· 412 return 413 } 414 415 + tx, err := s.db.BeginTx(r.Context(), nil) 416 + if err != nil { 417 + log.Println("failed to start tx") 418 + w.Write([]byte(fmt.Sprint("failed to add collaborator: ", err))) 419 + return 420 + } 421 + defer func() { 422 + tx.Rollback() 423 + err = s.enforcer.E.LoadPolicy() 424 + if err != nil { 425 + log.Println("failed to rollback policies") 426 + } 427 + }() 428 + 429 err = s.enforcer.AddCollaborator(collaboratorIdent.DID.String(), f.Knot, f.OwnerSlashRepo()) 430 if err != nil { 431 w.Write([]byte(fmt.Sprint("failed to add collaborator: ", err))) 432 return 433 } 434 435 + err = db.AddCollaborator(s.db, collaboratorIdent.DID.String(), f.OwnerDid(), f.RepoName, f.Knot) 436 if err != nil { 437 w.Write([]byte(fmt.Sprint("failed to add collaborator: ", err))) 438 return 439 } 440 441 + err = tx.Commit() 442 + if err != nil { 443 + log.Println("failed to commit changes", err) 444 + http.Error(w, err.Error(), http.StatusInternalServerError) 445 + return 446 + } 447 + 448 + err = s.enforcer.E.SavePolicy() 449 + if err != nil { 450 + log.Println("failed to update ACLs", err) 451 + http.Error(w, err.Error(), http.StatusInternalServerError) 452 + return 453 + } 454 + 455 w.Write([]byte(fmt.Sprint("added collaborator: ", collaboratorIdent.Handle.String()))) 456 457 } ··· 574 return 575 } 576 577 + issue, comments, err := db.GetIssueWithComments(s.db, f.RepoAt, issueIdInt) 578 if err != nil { 579 log.Println("failed to get issue and comments", err) 580 s.pages.Notice(w, "issues", "Failed to load issue. Try again later.") ··· 633 return 634 } 635 636 + issue, err := db.GetIssue(s.db, f.RepoAt, issueIdInt) 637 if err != nil { 638 log.Println("failed to get issue", err) 639 s.pages.Notice(w, "issue-action", "Failed to close issue. Try again later.") ··· 673 return 674 } 675 676 + err := db.CloseIssue(s.db, f.RepoAt, issueIdInt) 677 if err != nil { 678 log.Println("failed to close issue", err) 679 s.pages.Notice(w, "issue-action", "Failed to close issue. Try again later.") ··· 706 } 707 708 if user.Did == f.OwnerDid() { 709 + err := db.ReopenIssue(s.db, f.RepoAt, issueIdInt) 710 if err != nil { 711 log.Println("failed to reopen issue", err) 712 s.pages.Notice(w, "issue-action", "Failed to reopen issue. Try again later.") ··· 747 748 commentId := rand.IntN(1000000) 749 750 + err := db.NewComment(s.db, &db.Comment{ 751 OwnerDid: user.Did, 752 RepoAt: f.RepoAt, 753 Issue: issueIdInt, ··· 763 createdAt := time.Now().Format(time.RFC3339) 764 commentIdInt64 := int64(commentId) 765 ownerDid := user.Did 766 + issueAt, err := db.GetIssueAt(s.db, f.RepoAt, issueIdInt) 767 if err != nil { 768 log.Println("failed to get issue at", err) 769 s.pages.Notice(w, "issue-comment", "Failed to create comment.") ··· 805 return 806 } 807 808 + issues, err := db.GetIssues(s.db, f.RepoAt) 809 if err != nil { 810 log.Println("failed to get issues", err) 811 s.pages.Notice(w, "issues", "Failed to load issues. Try again later.") ··· 869 return 870 } 871 872 + tx, err := s.db.BeginTx(r.Context(), nil) 873 + if err != nil { 874 + s.pages.Notice(w, "issues", "Failed to create issue, try again later") 875 + return 876 + } 877 + 878 + err = db.NewIssue(tx, &db.Issue{ 879 RepoAt: f.RepoAt, 880 Title: title, 881 Body: body, ··· 887 return 888 } 889 890 + issueId, err := db.GetIssueId(s.db, f.RepoAt) 891 if err != nil { 892 log.Println("failed to get issue id", err) 893 s.pages.Notice(w, "issues", "Failed to create issue.") ··· 915 return 916 } 917 918 + err = db.SetIssueAt(s.db, f.RepoAt, issueId, resp.Uri) 919 if err != nil { 920 log.Println("failed to set issue at", err) 921 s.pages.Notice(w, "issues", "Failed to create issue.")
+3 -2
appview/state/settings.go
··· 10 lexutil "github.com/bluesky-social/indigo/lex/util" 11 "github.com/gliderlabs/ssh" 12 "github.com/sotangled/tangled/api/tangled" 13 "github.com/sotangled/tangled/appview/pages" 14 ) 15 16 func (s *State) Settings(w http.ResponseWriter, r *http.Request) { 17 // for now, this is just pubkeys 18 user := s.auth.GetUser(r) 19 - pubKeys, err := s.db.GetPublicKeys(user.Did) 20 if err != nil { 21 log.Println(err) 22 } ··· 47 return 48 } 49 50 - if err := s.db.AddPublicKey(did, name, key); err != nil { 51 log.Printf("adding public key: %s", err) 52 s.pages.Notice(w, "settings-keys", "Failed to add public key.") 53 return
··· 10 lexutil "github.com/bluesky-social/indigo/lex/util" 11 "github.com/gliderlabs/ssh" 12 "github.com/sotangled/tangled/api/tangled" 13 + "github.com/sotangled/tangled/appview/db" 14 "github.com/sotangled/tangled/appview/pages" 15 ) 16 17 func (s *State) Settings(w http.ResponseWriter, r *http.Request) { 18 // for now, this is just pubkeys 19 user := s.auth.GetUser(r) 20 + pubKeys, err := db.GetPublicKeys(s.db, user.Did) 21 if err != nil { 22 log.Println(err) 23 } ··· 48 return 49 } 50 51 + if err := db.AddPublicKey(s.db, did, name, key); err != nil { 52 log.Printf("adding public key: %s", err) 53 s.pages.Notice(w, "settings-keys", "Failed to add public key.") 54 return
+99 -36
appview/state/state.go
··· 39 } 40 41 func Make(config *appview.Config) (*State, error) { 42 - db, err := db.Make(config.DbPath) 43 if err != nil { 44 return nil, err 45 } ··· 60 61 resolver := appview.NewResolver() 62 63 - jc, err := jetstream.NewJetstreamClient("appview", []string{tangled.GraphFollowNSID}, nil, slog.Default(), db, false) 64 if err != nil { 65 return nil, fmt.Errorf("failed to create jetstream client: %w", err) 66 } 67 - err = jc.StartJetstream(context.Background(), jetstreamIngester(db)) 68 if err != nil { 69 return nil, fmt.Errorf("failed to start jetstream watcher: %w", err) 70 } 71 72 state := &State{ 73 - db, 74 auth, 75 enforcer, 76 clock, ··· 135 func (s *State) Timeline(w http.ResponseWriter, r *http.Request) { 136 user := s.auth.GetUser(r) 137 138 - timeline, err := s.db.MakeTimeline() 139 if err != nil { 140 log.Println(err) 141 s.pages.Notice(w, "timeline", "Uh oh! Failed to load timeline.") ··· 195 return 196 } 197 198 - key, err := s.db.GenerateRegistrationKey(domain, did) 199 200 if err != nil { 201 log.Println(err) ··· 222 return 223 } 224 225 - pubKeys, err := s.db.GetPublicKeys(id.DID.String()) 226 if err != nil { 227 w.WriteHeader(http.StatusNotFound) 228 return ··· 250 } 251 log.Println("checking ", domain) 252 253 - secret, err := s.db.GetRegistrationKey(domain) 254 if err != nil { 255 log.Printf("no key found for domain %s: %s\n", domain, err) 256 return ··· 295 return 296 } 297 298 // mark as registered 299 - err = s.db.Register(domain) 300 if err != nil { 301 log.Println("failed to register domain", err) 302 http.Error(w, err.Error(), http.StatusInternalServerError) ··· 304 } 305 306 // set permissions for this did as owner 307 - reg, err := s.db.RegistrationByDomain(domain) 308 if err != nil { 309 log.Println("failed to register domain", err) 310 http.Error(w, err.Error(), http.StatusInternalServerError) ··· 327 return 328 } 329 330 w.Write([]byte("check success")) 331 } 332 ··· 338 } 339 340 user := s.auth.GetUser(r) 341 - reg, err := s.db.RegistrationByDomain(domain) 342 if err != nil { 343 w.Write([]byte("failed to pull up registration info")) 344 return ··· 370 func (s *State) Knots(w http.ResponseWriter, r *http.Request) { 371 // for now, this is just pubkeys 372 user := s.auth.GetUser(r) 373 - registrations, err := s.db.RegistrationsByDid(user.Did) 374 if err != nil { 375 log.Println(err) 376 } ··· 444 } 445 log.Println("created atproto record: ", resp.Uri) 446 447 - secret, err := s.db.GetRegistrationKey(domain) 448 if err != nil { 449 log.Printf("no key found for domain %s: %s\n", domain, err) 450 return ··· 520 return 521 } 522 523 - secret, err := s.db.GetRegistrationKey(domain) 524 if err != nil { 525 s.pages.Notice(w, "repo", fmt.Sprintf("No registration key found for knot %s.", domain)) 526 return ··· 532 return 533 } 534 535 - resp, err := client.NewRepo(user.Did, repoName, defaultBranch) 536 - if err != nil { 537 - s.pages.Notice(w, "repo", "Failed to create repository on knot server.") 538 - return 539 - } 540 - 541 - switch resp.StatusCode { 542 - case http.StatusConflict: 543 - s.pages.Notice(w, "repo", "A repository with that name already exists.") 544 - return 545 - case http.StatusInternalServerError: 546 - s.pages.Notice(w, "repo", "Failed to create repository on knot. Try again later.") 547 - case http.StatusNoContent: 548 - // continue 549 - } 550 - 551 rkey := s.TID() 552 repo := &db.Repo{ 553 Did: user.Did, ··· 578 } 579 log.Println("created repo record: ", atresp.Uri) 580 581 - repo.AtUri = atresp.Uri 582 583 - err = s.db.AddRepo(repo) 584 if err != nil { 585 log.Println(err) 586 s.pages.Notice(w, "repo", "Failed to save repository information.") ··· 596 return 597 } 598 599 s.pages.HxLocation(w, fmt.Sprintf("/@%s/%s", user.Handle, repoName)) 600 return 601 } ··· 615 return 616 } 617 618 - repos, err := s.db.GetAllReposByDid(ident.DID.String()) 619 if err != nil { 620 log.Printf("getting repos for %s: %s", ident.DID.String(), err) 621 } 622 623 - collaboratingRepos, err := s.db.CollaboratingIn(ident.DID.String()) 624 if err != nil { 625 log.Printf("getting collaborating repos for %s: %s", ident.DID.String(), err) 626 } ··· 638 } 639 } 640 641 - followers, following, err := s.db.GetFollowerFollowing(ident.DID.String()) 642 if err != nil { 643 log.Printf("getting follow stats repos for %s: %s", ident.DID.String(), err) 644 } ··· 646 loggedInUser := s.auth.GetUser(r) 647 followStatus := db.IsNotFollowing 648 if loggedInUser != nil { 649 - followStatus = s.db.GetFollowStatus(loggedInUser.Did, ident.DID.String()) 650 } 651 652 profileAvatarUri, err := GetAvatarUri(ident.DID.String()) ··· 818 819 r.Route("/repo", func(r chi.Router) { 820 r.Route("/new", func(r chi.Router) { 821 r.Get("/", s.AddRepo) 822 r.Post("/", s.AddRepo) 823 })
··· 39 } 40 41 func Make(config *appview.Config) (*State, error) { 42 + d, err := db.Make(config.DbPath) 43 if err != nil { 44 return nil, err 45 } ··· 60 61 resolver := appview.NewResolver() 62 63 + wrapper := db.DbWrapper{d} 64 + jc, err := jetstream.NewJetstreamClient("appview", []string{tangled.GraphFollowNSID}, nil, slog.Default(), wrapper, false) 65 if err != nil { 66 return nil, fmt.Errorf("failed to create jetstream client: %w", err) 67 } 68 + err = jc.StartJetstream(context.Background(), jetstreamIngester(wrapper)) 69 if err != nil { 70 return nil, fmt.Errorf("failed to start jetstream watcher: %w", err) 71 } 72 73 state := &State{ 74 + d, 75 auth, 76 enforcer, 77 clock, ··· 136 func (s *State) Timeline(w http.ResponseWriter, r *http.Request) { 137 user := s.auth.GetUser(r) 138 139 + timeline, err := db.MakeTimeline(s.db) 140 if err != nil { 141 log.Println(err) 142 s.pages.Notice(w, "timeline", "Uh oh! Failed to load timeline.") ··· 196 return 197 } 198 199 + key, err := db.GenerateRegistrationKey(s.db, domain, did) 200 201 if err != nil { 202 log.Println(err) ··· 223 return 224 } 225 226 + pubKeys, err := db.GetPublicKeys(s.db, id.DID.String()) 227 if err != nil { 228 w.WriteHeader(http.StatusNotFound) 229 return ··· 251 } 252 log.Println("checking ", domain) 253 254 + secret, err := db.GetRegistrationKey(s.db, domain) 255 if err != nil { 256 log.Printf("no key found for domain %s: %s\n", domain, err) 257 return ··· 296 return 297 } 298 299 + tx, err := s.db.BeginTx(r.Context(), nil) 300 + if err != nil { 301 + log.Println("failed to start tx", err) 302 + http.Error(w, err.Error(), http.StatusInternalServerError) 303 + return 304 + } 305 + defer func() { 306 + tx.Rollback() 307 + err = s.enforcer.E.LoadPolicy() 308 + if err != nil { 309 + log.Println("failed to rollback policies") 310 + } 311 + }() 312 + 313 // mark as registered 314 + err = db.Register(tx, domain) 315 if err != nil { 316 log.Println("failed to register domain", err) 317 http.Error(w, err.Error(), http.StatusInternalServerError) ··· 319 } 320 321 // set permissions for this did as owner 322 + reg, err := db.RegistrationByDomain(tx, domain) 323 if err != nil { 324 log.Println("failed to register domain", err) 325 http.Error(w, err.Error(), http.StatusInternalServerError) ··· 342 return 343 } 344 345 + err = tx.Commit() 346 + if err != nil { 347 + log.Println("failed to commit changes", err) 348 + http.Error(w, err.Error(), http.StatusInternalServerError) 349 + return 350 + } 351 + 352 + err = s.enforcer.E.SavePolicy() 353 + if err != nil { 354 + log.Println("failed to update ACLs", err) 355 + http.Error(w, err.Error(), http.StatusInternalServerError) 356 + return 357 + } 358 + 359 w.Write([]byte("check success")) 360 } 361 ··· 367 } 368 369 user := s.auth.GetUser(r) 370 + reg, err := db.RegistrationByDomain(s.db, domain) 371 if err != nil { 372 w.Write([]byte("failed to pull up registration info")) 373 return ··· 399 func (s *State) Knots(w http.ResponseWriter, r *http.Request) { 400 // for now, this is just pubkeys 401 user := s.auth.GetUser(r) 402 + registrations, err := db.RegistrationsByDid(s.db, user.Did) 403 if err != nil { 404 log.Println(err) 405 } ··· 473 } 474 log.Println("created atproto record: ", resp.Uri) 475 476 + secret, err := db.GetRegistrationKey(s.db, domain) 477 if err != nil { 478 log.Printf("no key found for domain %s: %s\n", domain, err) 479 return ··· 549 return 550 } 551 552 + existingRepo, err := db.GetRepo(s.db, user.Did, repoName) 553 + if err == nil && existingRepo != nil { 554 + s.pages.Notice(w, "repo", fmt.Sprintf("A repo by this name already exists on %s", existingRepo.Knot)) 555 + return 556 + } 557 + 558 + secret, err := db.GetRegistrationKey(s.db, domain) 559 if err != nil { 560 s.pages.Notice(w, "repo", fmt.Sprintf("No registration key found for knot %s.", domain)) 561 return ··· 567 return 568 } 569 570 rkey := s.TID() 571 repo := &db.Repo{ 572 Did: user.Did, ··· 597 } 598 log.Println("created repo record: ", atresp.Uri) 599 600 + tx, err := s.db.BeginTx(r.Context(), nil) 601 + if err != nil { 602 + log.Println(err) 603 + s.pages.Notice(w, "repo", "Failed to save repository information.") 604 + return 605 + } 606 + defer func() { 607 + tx.Rollback() 608 + err = s.enforcer.E.LoadPolicy() 609 + if err != nil { 610 + log.Println("failed to rollback policies") 611 + } 612 + }() 613 614 + resp, err := client.NewRepo(user.Did, repoName, defaultBranch) 615 + if err != nil { 616 + s.pages.Notice(w, "repo", "Failed to create repository on knot server.") 617 + return 618 + } 619 + 620 + switch resp.StatusCode { 621 + case http.StatusConflict: 622 + s.pages.Notice(w, "repo", "A repository with that name already exists.") 623 + return 624 + case http.StatusInternalServerError: 625 + s.pages.Notice(w, "repo", "Failed to create repository on knot. Try again later.") 626 + case http.StatusNoContent: 627 + // continue 628 + } 629 + 630 + repo.AtUri = atresp.Uri 631 + err = db.AddRepo(tx, repo) 632 if err != nil { 633 log.Println(err) 634 s.pages.Notice(w, "repo", "Failed to save repository information.") ··· 644 return 645 } 646 647 + err = tx.Commit() 648 + if err != nil { 649 + log.Println("failed to commit changes", err) 650 + http.Error(w, err.Error(), http.StatusInternalServerError) 651 + return 652 + } 653 + 654 + err = s.enforcer.E.SavePolicy() 655 + if err != nil { 656 + log.Println("failed to update ACLs", err) 657 + http.Error(w, err.Error(), http.StatusInternalServerError) 658 + return 659 + } 660 + 661 s.pages.HxLocation(w, fmt.Sprintf("/@%s/%s", user.Handle, repoName)) 662 return 663 } ··· 677 return 678 } 679 680 + repos, err := db.GetAllReposByDid(s.db, ident.DID.String()) 681 if err != nil { 682 log.Printf("getting repos for %s: %s", ident.DID.String(), err) 683 } 684 685 + collaboratingRepos, err := db.CollaboratingIn(s.db, ident.DID.String()) 686 if err != nil { 687 log.Printf("getting collaborating repos for %s: %s", ident.DID.String(), err) 688 } ··· 700 } 701 } 702 703 + followers, following, err := db.GetFollowerFollowing(s.db, ident.DID.String()) 704 if err != nil { 705 log.Printf("getting follow stats repos for %s: %s", ident.DID.String(), err) 706 } ··· 708 loggedInUser := s.auth.GetUser(r) 709 followStatus := db.IsNotFollowing 710 if loggedInUser != nil { 711 + followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, ident.DID.String()) 712 } 713 714 profileAvatarUri, err := GetAvatarUri(ident.DID.String()) ··· 880 881 r.Route("/repo", func(r chi.Router) { 882 r.Route("/new", func(r chi.Router) { 883 + r.Use(AuthMiddleware(s)) 884 r.Get("/", s.AddRepo) 885 r.Post("/", s.AddRepo) 886 })
+8 -7
rbac/rbac.go
··· 6 "path" 7 "strings" 8 9 - sqladapter "github.com/Blank-Xu/sql-adapter" 10 "github.com/casbin/casbin/v2" 11 "github.com/casbin/casbin/v2/model" 12 ) ··· 31 ) 32 33 type Enforcer struct { 34 - E *casbin.SyncedEnforcer 35 } 36 37 func keyMatch2(key1 string, key2 string) bool { ··· 50 return nil, err 51 } 52 53 - a, err := sqladapter.NewAdapter(db, "sqlite3", "acl") 54 if err != nil { 55 return nil, err 56 } 57 58 - e, err := casbin.NewSyncedEnforcer(m, a) 59 if err != nil { 60 return nil, err 61 } 62 63 - e.EnableAutoSave(true) 64 e.AddFunction("keyMatch2", keyMatch2Func) 65 66 return &Enforcer{e}, nil ··· 82 } 83 84 func (e *Enforcer) GetDomainsForUser(did string) ([]string, error) { 85 - return e.E.Enforcer.GetDomainsForUser(did) 86 } 87 88 func (e *Enforcer) AddOwner(domain, owner string) error { ··· 131 132 // this includes roles too, casbin does not differentiate. 133 // the filtering criteria is to remove strings not starting with `did:` 134 - members, err := e.E.Enforcer.GetImplicitUsersForRole(role, domain) 135 for _, m := range members { 136 if strings.HasPrefix(m, "did:") { 137 membersWithoutRoles = append(membersWithoutRoles, m)
··· 6 "path" 7 "strings" 8 9 + adapter "github.com/Blank-Xu/sql-adapter" 10 "github.com/casbin/casbin/v2" 11 "github.com/casbin/casbin/v2/model" 12 ) ··· 31 ) 32 33 type Enforcer struct { 34 + E *casbin.Enforcer 35 } 36 37 func keyMatch2(key1 string, key2 string) bool { ··· 50 return nil, err 51 } 52 53 + a, err := adapter.NewAdapter(db, "sqlite3", "acl") 54 if err != nil { 55 return nil, err 56 } 57 58 + e, err := casbin.NewEnforcer(m, a) 59 if err != nil { 60 return nil, err 61 } 62 63 + e.EnableAutoSave(false) 64 + 65 e.AddFunction("keyMatch2", keyMatch2Func) 66 67 return &Enforcer{e}, nil ··· 83 } 84 85 func (e *Enforcer) GetDomainsForUser(did string) ([]string, error) { 86 + return e.E.GetDomainsForUser(did) 87 } 88 89 func (e *Enforcer) AddOwner(domain, owner string) error { ··· 132 133 // this includes roles too, casbin does not differentiate. 134 // the filtering criteria is to remove strings not starting with `did:` 135 + members, err := e.E.GetImplicitUsersForRole(role, domain) 136 for _, m := range members { 137 if strings.HasPrefix(m, "did:") { 138 membersWithoutRoles = append(membersWithoutRoles, m)