~bigbes/sr-ht-dolt

ref: cd0b0c0fb427bff6060c3f785d67784b999610f3 sr-ht-dolt/web/adapters.go -rw-r--r-- 5.5 KiB
cd0b0c0f — Eugene Blikh web: rename a database from its settings page 3 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package web

import (
	"context"
	"time"

	"sourcecraft.dev/bigbes/sr-ht-core/auth"
	"sourcecraft.dev/bigbes/sr-ht-core/client"

	"sourcecraft.dev/bigbes/sr-ht-dolt/authn"
	"sourcecraft.dev/bigbes/sr-ht-dolt/browse"
	"sourcecraft.dev/bigbes/sr-ht-dolt/core"
	"sourcecraft.dev/bigbes/sr-ht-dolt/db"
)

// This file holds the production adapters that satisfy the small interfaces in
// deps.go over the real db, browse and core-go layers. Tests do not use these;
// they inject their own fakes. Each adapter is a zero-value struct with a
// compile-time interface assertion so a signature drift in a committed package
// breaks the build here rather than at Phase-3 wiring time.

// DBAdapter satisfies RepoStore over the request-scoped db.Store. It holds no
// connection: every method builds a Store from the *sql.DB the core-go database
// middleware installed in ctx (db.FromContext), so one value serves all
// requests and leaks nothing.
type DBAdapter struct{}

var _ RepoStore = DBAdapter{}

func (DBAdapter) CreateRepo(ctx context.Context, r *core.Repo) (*core.Repo, error) {
	return db.FromContext(ctx).CreateRepo(ctx, r)
}

func (DBAdapter) GetRepoByOwnerAndName(ctx context.Context, owner, name string) (*core.Repo, error) {
	return db.FromContext(ctx).GetRepoByOwnerAndName(ctx, owner, name)
}

func (DBAdapter) ListReposByOwner(ctx context.Context, owner string, viewer *core.Caller) ([]*core.Repo, error) {
	return db.FromContext(ctx).ListReposByOwner(ctx, owner, viewer)
}

func (DBAdapter) ListReposForViewer(ctx context.Context, viewer *core.Caller) ([]*core.Repo, error) {
	return db.FromContext(ctx).ListReposForViewer(ctx, viewer)
}

func (DBAdapter) ListReposForDashboard(ctx context.Context, userID int) ([]*core.Repo, error) {
	return db.FromContext(ctx).ListReposForDashboard(ctx, userID)
}

func (DBAdapter) UpdateRepo(ctx context.Context, id int, description string, visibility core.Visibility) error {
	return db.FromContext(ctx).UpdateRepo(ctx, id, description, visibility)
}

func (DBAdapter) RenameRepo(ctx context.Context, id int, name, path string) error {
	return db.FromContext(ctx).RenameRepo(ctx, id, name, path)
}

func (DBAdapter) DeleteRepo(ctx context.Context, id int) error {
	return db.FromContext(ctx).DeleteRepo(ctx, id)
}

func (DBAdapter) EffectiveAccess(ctx context.Context, userID, repoID int) (*core.AccessMode, error) {
	return db.FromContext(ctx).EffectiveAccess(ctx, userID, repoID)
}

func (DBAdapter) ListACL(ctx context.Context, repoID int) ([]*db.ACLEntry, error) {
	return db.FromContext(ctx).ListACL(ctx, repoID)
}

func (DBAdapter) UpsertACL(ctx context.Context, repoID, userID int, mode core.AccessMode) error {
	return db.FromContext(ctx).UpsertACL(ctx, repoID, userID, mode)
}

func (DBAdapter) DeleteACL(ctx context.Context, repoID, userID int) error {
	return db.FromContext(ctx).DeleteACL(ctx, repoID, userID)
}

func (DBAdapter) InsertKey(ctx context.Context, userID int, kid string, pubkey []byte, comment string) (*db.DoltKey, error) {
	return db.FromContext(ctx).InsertKey(ctx, userID, kid, pubkey, comment)
}

func (DBAdapter) ListKeysByUser(ctx context.Context, userID int) ([]*db.DoltKey, error) {
	return db.FromContext(ctx).ListKeysByUser(ctx, userID)
}

func (DBAdapter) DeleteKey(ctx context.Context, id, userID int) error {
	return db.FromContext(ctx).DeleteKey(ctx, id, userID)
}

// BrowseAdapter satisfies BrowseOpener over browse.Open. The returned *browse.DB
// already implements every BrowseSession method plus Close.
type BrowseAdapter struct{}

var _ BrowseOpener = BrowseAdapter{}

func (BrowseAdapter) Open(ctx context.Context, diskPath string) (BrowseSession, error) {
	dbh, err := browse.Open(ctx, diskPath)
	if err != nil {
		return nil, err
	}
	return dbh, nil
}

// gitDescribeTimeout bounds the git.sr.ht GraphQL lookup. It must stay well
// under dolt-git-hook's 5s client timeout: the lookup runs inside the hook's
// POST to /internal/repos, so a slow git.sr.ht API must not push the whole
// request past what the hook will wait for.
const gitDescribeTimeout = 3 * time.Second

// GitDescriptionResolver satisfies GitDescriber over git.sr.ht's GraphQL API,
// queried with internal auth in the owner's name — the same service-to-service
// network-key trust dolt-git-hook uses to reach us, pointed the other way.
type GitDescriptionResolver struct{}

var _ GitDescriber = GitDescriptionResolver{}

func (GitDescriptionResolver) Description(ctx context.Context, owner, name string) (string, bool) {
	ctx, cancel := context.WithTimeout(ctx, gitDescribeTimeout)
	defer cancel()

	var resp struct {
		Me struct {
			Repository *struct {
				Description *string `json:"description"`
			} `json:"repository"`
		} `json:"me"`
	}
	err := client.Do(ctx, owner, "git.sr.ht", client.GraphQLQuery{
		Query:     `query($name: String!) { me { repository(name: $name) { description } } }`,
		Variables: map[string]any{"name": name},
	}, &resp)
	if err != nil || resp.Me.Repository == nil {
		return "", false
	}
	if resp.Me.Repository.Description == nil {
		return "", true
	}
	return *resp.Me.Repository.Description, true
}

// MetaUserResolver satisfies UserResolver via core-go's auth.LookupUser, which
// mirrors the meta.sr.ht profile into the local user table and yields the
// account's UserID. Used to resolve an ACL grantee by username.
type MetaUserResolver struct{}

var _ UserResolver = MetaUserResolver{}

func (MetaUserResolver) LookupUser(ctx context.Context, username string) (*core.Caller, error) {
	var ac auth.AuthContext
	if err := auth.LookupUser(ctx, username, &ac); err != nil {
		return nil, err
	}
	return authn.AsCoreCaller(&ac), nil
}