+7
-2
appview/db/spindle.go
+7
-2
appview/db/spindle.go
···
51
51
for rows.Next() {
52
52
var spindle Spindle
53
53
var createdAt string
54
-
var verified sql.NullTime
54
+
var verified sql.NullString
55
55
56
56
if err := rows.Scan(
57
57
&spindle.Id,
···
69
69
}
70
70
71
71
if verified.Valid {
72
-
spindle.Verified = &verified.Time
72
+
t, err := time.Parse(time.RFC3339, verified.String)
73
+
if err != nil {
74
+
now := time.Now()
75
+
spindle.Verified = &now
76
+
}
77
+
spindle.Verified = &t
73
78
}
74
79
75
80
spindles = append(spindles, spindle)
+2
-2
appview/pages/templates/repo/new.html
+2
-2
appview/pages/templates/repo/new.html
···
60
60
</fieldset>
61
61
62
62
<div class="space-y-2">
63
-
<button type="submit" class="btn flex gap-2 items-center">
63
+
<button type="submit" class="btn flex items-center">
64
64
create repo
65
65
<span id="spinner" class="group">
66
-
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
66
+
{{ i "loader-circle" "ml-2 w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
67
67
</span>
68
68
</button>
69
69
<div id="repo" class="error"></div>
+3
-3
appview/pages/templates/repo/settings.html
+3
-3
appview/pages/templates/repo/settings.html
···
83
83
84
84
{{ if .RepoInfo.Roles.IsOwner }}
85
85
<form
86
-
hx-put="/{{ $.RepoInfo.FullName }}/settings/spindle"
86
+
hx-post="/{{ $.RepoInfo.FullName }}/settings/spindle"
87
87
class="mt-6 group"
88
88
>
89
89
<label for="spindle">spindle</label>
···
100
100
<option
101
101
value="{{ . }}"
102
102
class="py-1"
103
-
{{ if .eq . $.Repo.Spindle }}
103
+
{{ if eq . $.CurrentSpindle }}
104
104
selected
105
105
{{ end }}
106
106
>
···
127
127
<button class="btn my-2 flex items-center" type="text">
128
128
<span>delete</span>
129
129
<span id="delete-repo-spinner" class="group">
130
-
{{ i "loader-circle" "pl-2 w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
130
+
{{ i "loader-circle" "ml-2 w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
131
131
</span>
132
132
</button>
133
133
<span>
+2
-2
appview/pages/templates/spindles/fragments/spindleListing.html
+2
-2
appview/pages/templates/spindles/fragments/spindleListing.html
···
24
24
<button
25
25
class="btn text-red-500 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300 gap-2 group"
26
26
title="Delete spindle"
27
-
hx-delete="/spindles/{{ urlquery .Instance }}"
27
+
hx-delete="/spindles/{{ .Instance }}"
28
28
hx-swap="outerHTML"
29
29
hx-target="#spindle-{{.Id}}"
30
30
hx-confirm="Are you sure you want to delete the spindle '{{ .Instance }}'?"
···
40
40
<button
41
41
class="btn gap-2 group"
42
42
title="Retry spindle verification"
43
-
hx-post="/spindles/{{ urlquery .Instance }}/retry"
43
+
hx-post="/spindles/{{ .Instance }}/retry"
44
44
hx-swap="none"
45
45
hx-target="#spindle-{{.Id}}"
46
46
>
+1
appview/repo/repo.go
+1
appview/repo/repo.go
+46
appview/spindles/spindles.go
+46
appview/spindles/spindles.go
···
54
54
)
55
55
if err != nil {
56
56
s.Logger.Error("failed to fetch spindles", "err", err)
57
+
w.WriteHeader(http.StatusInternalServerError)
58
+
return
57
59
}
58
60
59
61
s.Pages.Spindles(w, pages.SpindlesParams{
···
150
152
return
151
153
}
152
154
155
+
tx, err = s.Db.Begin()
156
+
if err != nil {
157
+
l.Error("failed to commit verification info", "err", err)
158
+
s.Pages.HxRefresh(w)
159
+
return
160
+
}
161
+
defer func() {
162
+
tx.Rollback()
163
+
s.Enforcer.E.LoadPolicy()
164
+
}()
165
+
166
+
// mark this spindle as verified in the db
167
+
_, err = db.VerifySpindle(
168
+
tx,
169
+
db.FilterEq("owner", user.Did),
170
+
db.FilterEq("instance", instance),
171
+
)
172
+
173
+
err = s.Enforcer.AddSpindleOwner(instance, user.Did)
174
+
if err != nil {
175
+
l.Error("failed to update ACL", "err", err)
176
+
s.Pages.HxRefresh(w)
177
+
return
178
+
}
179
+
180
+
err = tx.Commit()
181
+
if err != nil {
182
+
l.Error("failed to commit verification info", "err", err)
183
+
s.Pages.HxRefresh(w)
184
+
return
185
+
}
186
+
187
+
err = s.Enforcer.E.SavePolicy()
188
+
if err != nil {
189
+
l.Error("failed to update ACL", "err", err)
190
+
s.Pages.HxRefresh(w)
191
+
return
192
+
}
193
+
153
194
// ok
154
195
s.Pages.HxRefresh(w)
155
196
return
···
255
296
db.FilterEq("owner", user.Did),
256
297
db.FilterEq("instance", instance),
257
298
)
299
+
if err != nil {
300
+
l.Error("verification failed", "err", err)
301
+
fail()
302
+
return
303
+
}
258
304
259
305
verifiedSpindle := db.Spindle{
260
306
Id: int(rowId),
+6
-5
spindle/ingester.go
+6
-5
spindle/ingester.go
···
59
59
if s.cfg.Server.Dev {
60
60
domain = s.cfg.Server.ListenAddr
61
61
}
62
-
recordInstance := *record.Instance
62
+
recordInstance := record.Instance
63
63
64
64
if recordInstance != domain {
65
65
l.Error("domain mismatch", "domain", recordInstance, "expected", domain)
66
-
return fmt.Errorf("domain mismatch: %s != %s", *record.Instance, domain)
66
+
return fmt.Errorf("domain mismatch: %s != %s", record.Instance, domain)
67
67
}
68
68
69
69
ok, err := s.e.E.Enforce(did, rbacDomain, rbacDomain, "server:invite")
···
95
95
96
96
l := s.l.With("component", "ingester", "record", tangled.RepoNSID)
97
97
98
+
l.Info("ingesting repo record")
99
+
98
100
switch e.Commit.Operation {
99
101
case models.CommitOperationCreate, models.CommitOperationUpdate:
100
102
raw := e.Commit.Record
···
106
108
}
107
109
108
110
domain := s.cfg.Server.Hostname
109
-
if s.cfg.Server.Dev {
110
-
domain = s.cfg.Server.ListenAddr
111
-
}
112
111
113
112
// no spindle configured for this repo
114
113
if record.Spindle == nil {
114
+
l.Info("no spindle configured", "did", record.Owner, "name", record.Name)
115
115
return nil
116
116
}
117
117
118
118
// this repo did not want this spindle
119
119
if *record.Spindle != domain {
120
+
l.Info("different spindle configured", "did", record.Owner, "name", record.Name, "spindle", *record.Spindle, "domain", domain)
120
121
return nil
121
122
}
122
123
+7
-1
spindle/server.go
+7
-1
spindle/server.go
···
66
66
67
67
jq := queue.NewQueue(100, 2)
68
68
69
-
collections := []string{tangled.SpindleMemberNSID}
69
+
collections := []string{
70
+
tangled.SpindleMemberNSID,
71
+
tangled.RepoNSID,
72
+
}
70
73
jc, err := jetstream.NewJetstreamClient(cfg.Server.JetstreamEndpoint, "spindle", collections, nil, logger, d, false, false)
71
74
if err != nil {
72
75
return fmt.Errorf("failed to setup jetstream client: %w", err)
···
140
143
mux := chi.NewRouter()
141
144
142
145
mux.HandleFunc("/events", s.Events)
146
+
mux.HandleFunc("/owner", func(w http.ResponseWriter, r *http.Request) {
147
+
w.Write([]byte(s.cfg.Server.Owner))
148
+
})
143
149
mux.HandleFunc("/logs/{knot}/{rkey}/{name}", s.Logs)
144
150
return mux
145
151
}