Gitfed
bastien-mrq/gitfed / cmd / gitfed-web / handlers_admin_repos.go
package main

import (
	"bytes"
	"html/template"
	"net/http"
	"sort"

	"git.neuromancer.ovh/bastien-mrq/gitfed/internal/i18n"
	"git.neuromancer.ovh/bastien-mrq/gitfed/internal/store"
)

// repoDiskUsageView pairs a repo with its on-disk size, sorted largest
// first so the biggest consumers surface without scanning the whole list.
type repoDiskUsageView struct {
	store.Repo
	Bytes int64
}

var adminReposTpl = newTpl("admin-repos", `
<p><a href="/admin">&larr; {{t .Lang "nav.admin"}}</a></p>
<h1>{{t .Lang "admin.repos_title"}}</h1>
<p class="muted">{{t .Lang "admin.repos_sub" .Total (humanBytes .TotalBytes)}}</p>
<table>
<tr><th>{{t .Lang "admin.repos_col_name"}}</th><th>{{t .Lang "admin.repos_col_owner"}}</th><th>{{t .Lang "admin.repos_col_visibility"}}</th><th>{{t .Lang "admin.repos_col_size"}}</th></tr>
{{range .Repos}}
<tr>
  <td><a href="/r/{{.Name}}">{{.Name}}</a></td>
  <td class="muted">{{.Owner}}</td>
  <td>{{if .Public}}<span class="badge trusted">{{t $.Lang "common.public"}}</span>{{else}}<span class="badge pending">{{t $.Lang "common.private"}}</span>{{end}}</td>
  <td>{{humanBytes .Bytes}}</td>
</tr>
{{else}}
<tr><td colspan="4" class="muted">{{t .Lang "admin.repos_empty"}}</td></tr>
{{end}}
</table>
`)

func (s *server) handleAdminRepos(w http.ResponseWriter, r *http.Request) {
	lang := s.lang(r)
	repos, err := s.ops.ListRepos()
	if err != nil {
		s.serverError(w, r, err)
		return
	}

	views := make([]repoDiskUsageView, 0, len(repos))
	var total int64
	for _, repo := range repos {
		// Best-effort per repo — a repo whose directory vanished out from
		// under the store shouldn't take down the whole admin page.
		size, err := s.ops.RepoDiskUsage(repo.Name)
		if err != nil {
			continue
		}
		views = append(views, repoDiskUsageView{Repo: repo, Bytes: size})
		total += size
	}
	sort.Slice(views, func(i, j int) bool { return views[i].Bytes > views[j].Bytes })

	var buf bytes.Buffer
	_ = adminReposTpl.Execute(&buf, struct {
		Repos      []repoDiskUsageView
		Total      int
		TotalBytes int64
		Lang       string
	}{views, len(views), total, string(lang)})
	s.render(w, r, i18n.T(lang, "admin.repos_title"), "admin", template.HTML(buf.String()))
}