+24
-1
appview/pages/pages.go
+24
-1
appview/pages/pages.go
···
22
t map[string]*template.Template
23
}
24
25
func NewPages() *Pages {
26
templates := make(map[string]*template.Template)
27
···
37
38
if !strings.HasPrefix(path, "templates/layouts/") {
39
// Add the page template on top of the base
40
-
tmpl, err := template.New(name).ParseFS(files, "templates/layouts/*.html", path)
41
if err != nil {
42
return fmt.Errorf("setting up template: %w", err)
43
}
···
215
func (p *Pages) RepoTags(w io.Writer, params RepoTagsParams) error {
216
return p.executeRepo("repo/tags", w, params)
217
}
···
22
t map[string]*template.Template
23
}
24
25
+
func funcMap() template.FuncMap {
26
+
return template.FuncMap{
27
+
"split": func(s string) []string {
28
+
return strings.Split(s, "\n")
29
+
},
30
+
"add": func(a, b int) int {
31
+
return a + b
32
+
},
33
+
}
34
+
}
35
+
36
func NewPages() *Pages {
37
templates := make(map[string]*template.Template)
38
···
48
49
if !strings.HasPrefix(path, "templates/layouts/") {
50
// Add the page template on top of the base
51
+
tmpl, err := template.New(name).
52
+
Funcs(funcMap()).
53
+
ParseFS(files, "templates/layouts/*.html", path)
54
if err != nil {
55
return fmt.Errorf("setting up template: %w", err)
56
}
···
228
func (p *Pages) RepoTags(w io.Writer, params RepoTagsParams) error {
229
return p.executeRepo("repo/tags", w, params)
230
}
231
+
232
+
type RepoBlobParams struct {
233
+
LoggedInUser *auth.User
234
+
RepoInfo RepoInfo
235
+
types.RepoBlobResponse
236
+
}
237
+
238
+
func (p *Pages) RepoBlob(w io.Writer, params RepoBlobParams) error {
239
+
return p.executeRepo("repo/blob", w, params)
240
+
}
+12
appview/pages/templates/repo/blob.html
+12
appview/pages/templates/repo/blob.html
-34
appview/pages/templates/repo/file.html
-34
appview/pages/templates/repo/file.html
···
1
-
<html>
2
-
{{ template "layouts/head" . }}
3
-
{{ template "layouts/repo-header" . }}
4
-
<body>
5
-
{{ template "layouts/nav" . }}
6
-
<main>
7
-
<p>{{ .path }} (<a style="color: gray" href="?raw=true">view raw</a>)</p>
8
-
{{if .chroma }}
9
-
<div class="chroma-file-wrapper">
10
-
{{ .content }}
11
-
</div>
12
-
{{else}}
13
-
<div class="file-wrapper">
14
-
<table>
15
-
<tbody><tr>
16
-
<td class="line-numbers">
17
-
<pre>
18
-
{{- range .linecount }}
19
-
<a id="L{{ . }}" href="#L{{ . }}">{{ . }}</a>
20
-
{{- end -}}
21
-
</pre>
22
-
</td>
23
-
<td class="file-content">
24
-
<pre>
25
-
{{- .content -}}
26
-
</pre>
27
-
</td>
28
-
</tbody></tr>
29
-
</table>
30
-
</div>
31
-
{{end}}
32
-
</main>
33
-
</body>
34
-
</html>
···
+40
-3
appview/state/repo.go
+40
-3
appview/state/repo.go
···
48
OwnerDid: id.DID.String(),
49
OwnerHandle: id.Handle.String(),
50
Name: repoName,
51
-
Description: result.Description,
52
},
53
RepoIndexResponse: result,
54
})
···
89
OwnerDid: id.DID.String(),
90
OwnerHandle: id.Handle.String(),
91
Name: repoName,
92
-
Description: result.Description,
93
},
94
RepoLogResponse: result,
95
})
···
171
OwnerDid: id.DID.String(),
172
OwnerHandle: id.Handle.String(),
173
Name: repoName,
174
-
Description: result.Description,
175
},
176
RepoTreeResponse: result,
177
})
···
250
Name: repoName,
251
},
252
RepoBranchesResponse: result,
253
})
254
return
255
}
···
48
OwnerDid: id.DID.String(),
49
OwnerHandle: id.Handle.String(),
50
Name: repoName,
51
},
52
RepoIndexResponse: result,
53
})
···
88
OwnerDid: id.DID.String(),
89
OwnerHandle: id.Handle.String(),
90
Name: repoName,
91
},
92
RepoLogResponse: result,
93
})
···
169
OwnerDid: id.DID.String(),
170
OwnerHandle: id.Handle.String(),
171
Name: repoName,
172
},
173
RepoTreeResponse: result,
174
})
···
247
Name: repoName,
248
},
249
RepoBranchesResponse: result,
250
+
})
251
+
return
252
+
}
253
+
254
+
func (s *State) RepoBlob(w http.ResponseWriter, r *http.Request) {
255
+
repoName, knot, id, err := repoKnotAndId(r)
256
+
if err != nil {
257
+
log.Println("failed to get repo and knot", err)
258
+
return
259
+
}
260
+
261
+
ref := chi.URLParam(r, "ref")
262
+
filePath := chi.URLParam(r, "*")
263
+
resp, err := http.Get(fmt.Sprintf("http://%s/%s/%s/blob/%s/%s", knot, id.DID.String(), repoName, ref, filePath))
264
+
if err != nil {
265
+
log.Println("failed to reach knotserver", err)
266
+
return
267
+
}
268
+
269
+
body, err := io.ReadAll(resp.Body)
270
+
if err != nil {
271
+
log.Fatalf("Error reading response body: %v", err)
272
+
return
273
+
}
274
+
275
+
var result types.RepoBlobResponse
276
+
err = json.Unmarshal(body, &result)
277
+
if err != nil {
278
+
log.Println("failed to parse response:", err)
279
+
return
280
+
}
281
+
282
+
s.pages.RepoBlob(w, pages.RepoBlobParams{
283
+
LoggedInUser: s.auth.GetUser(r),
284
+
RepoInfo: pages.RepoInfo{
285
+
OwnerDid: id.DID.String(),
286
+
OwnerHandle: id.Handle.String(),
287
+
Name: repoName,
288
+
},
289
+
RepoBlobResponse: result,
290
})
291
return
292
}
+1
appview/state/state.go
+1
appview/state/state.go
+4
-20
knotserver/file.go
+4
-20
knotserver/file.go
···
43
}
44
}
45
46
-
func (h *Handle) showFile(content string, data map[string]any, w http.ResponseWriter, l *slog.Logger) {
47
-
lc, err := countLines(strings.NewReader(content))
48
if err != nil {
49
// Non-fatal, we'll just skip showing line numbers in the template.
50
l.Warn("counting lines", "error", err)
51
}
52
53
-
lines := make([]int, lc)
54
-
if lc > 0 {
55
-
for i := range lines {
56
-
lines[i] = i + 1
57
-
}
58
-
}
59
-
60
-
data["linecount"] = lines
61
-
data["content"] = content
62
-
63
-
writeJSON(w, data)
64
-
return
65
-
}
66
-
67
-
func (h *Handle) showRaw(content string, w http.ResponseWriter) {
68
-
w.WriteHeader(http.StatusOK)
69
-
w.Header().Set("Content-Type", "text/plain")
70
-
w.Write([]byte(content))
71
return
72
}
···
43
}
44
}
45
46
+
func (h *Handle) showFile(resp types.RepoBlobResponse, w http.ResponseWriter, l *slog.Logger) {
47
+
lc, err := countLines(strings.NewReader(resp.Contents))
48
if err != nil {
49
// Non-fatal, we'll just skip showing line numbers in the template.
50
l.Warn("counting lines", "error", err)
51
}
52
53
+
resp.Lines = lc
54
+
writeJSON(w, resp)
55
return
56
}
+1
-1
knotserver/handler.go
+1
-1
knotserver/handler.go
+13
-21
knotserver/routes.go
+13
-21
knotserver/routes.go
···
129
DotDot: filepath.Dir(treePath),
130
Files: files,
131
}
132
-
// data := make(map[string]any)
133
-
// data["ref"] = ref
134
-
// data["parent"] = treePath
135
-
// data["desc"] = getDescription(path)
136
-
// data["dotdot"] = filepath.Dir(treePath)
137
138
writeJSON(w, resp)
139
-
// h.listFiles(files, data, w)
140
return
141
}
142
143
-
func (h *Handle) FileContent(w http.ResponseWriter, r *http.Request) {
144
-
var raw bool
145
-
if rawParam, err := strconv.ParseBool(r.URL.Query().Get("raw")); err == nil {
146
-
raw = rawParam
147
-
}
148
-
149
treePath := chi.URLParam(r, "*")
150
ref := chi.URLParam(r, "ref")
151
···
163
writeError(w, err.Error(), http.StatusInternalServerError)
164
return
165
}
166
-
data := make(map[string]any)
167
-
data["ref"] = ref
168
-
data["desc"] = getDescription(path)
169
-
data["path"] = treePath
170
171
-
safe := sanitize([]byte(contents))
172
173
-
if raw {
174
-
h.showRaw(string(safe), w)
175
-
} else {
176
-
h.showFile(string(safe), data, w, l)
177
}
178
}
179
180
func (h *Handle) Archive(w http.ResponseWriter, r *http.Request) {
···
341
},
342
Tag: tag.TagObject(),
343
}
344
rtags = append(rtags, &tr)
345
}
346
···
129
DotDot: filepath.Dir(treePath),
130
Files: files,
131
}
132
133
writeJSON(w, resp)
134
return
135
}
136
137
+
func (h *Handle) Blob(w http.ResponseWriter, r *http.Request) {
138
treePath := chi.URLParam(r, "*")
139
ref := chi.URLParam(r, "ref")
140
···
152
writeError(w, err.Error(), http.StatusInternalServerError)
153
return
154
}
155
156
+
safe := string(sanitize([]byte(contents)))
157
158
+
resp := types.RepoBlobResponse{
159
+
Ref: ref,
160
+
Contents: string(safe),
161
+
Path: treePath,
162
}
163
+
164
+
h.showFile(resp, w, l)
165
}
166
167
func (h *Handle) Archive(w http.ResponseWriter, r *http.Request) {
···
328
},
329
Tag: tag.TagObject(),
330
}
331
+
332
+
if tag.Message() != "" {
333
+
tr.Message = tag.Message()
334
+
}
335
+
336
rtags = append(rtags, &tr)
337
}
338
+8
types/repo.go
+8
types/repo.go
···
59
type RepoBranchesResponse struct {
60
Branches []Branch `json:"branches,omitempty"`
61
}
62
+
63
+
type RepoBlobResponse struct {
64
+
Contents string `json:"contents,omitempty"`
65
+
Ref string `json:"ref,omitempty"`
66
+
Path string `json:"path,omitempty"`
67
+
68
+
Lines int `json:"lines,omitempty"`
69
+
}
+5
-5
types/tree.go
+5
-5
types/tree.go