cerrado @ e8265117372cf262ce7cb4f6ce3b61f19373aee6

feat: Add configuration for ordering repo list

Now it is possible to order the list by; unordered, alphabetical and
last commit both ascendent and descendent.
  1diff --git a/config.example.scfg b/config.example.scfg
  2index 59a04ad1644103962c89fb9c498e64d1035b3666..3ba89594f3683497a1ab44cdff372ed1eb1dfebc 100644
  3--- a/config.example.scfg
  4+++ b/config.example.scfg
  5@@ -10,6 +10,14 @@ # and login UI will be disabled, and only public repository will be displayed.
  6 passphrase $2a$14$VnB/ZcB1DUDkMnosRA6Y7.dj8h5eroslDxTeXlLwfQX/x86mh6WAq
  7 aes-key 8XHptZxSWCGs1m7QzztX5zNQ7D9NiQevVX0DaUTNMbDpRwFzoJiB0U7K6O/kqIt01jJVgzBUfiR8ES46ZLLb4w==
  8 
  9+# order of the list of repository, values:
 10+# unordered
 11+# alphabetical-asc
 12+# alphabetical-desc
 13+# lastcommit-asc
 14+# lastcommit-desc
 15+order-by lastcommit-asc
 16+
 17 # repository section is order dependent where the first repository has priority
 18 # in case of conflict. Repository has also priority over scan. The order
 19 # between scan and repository is irrelevant which means that all repository
 20diff --git a/pkg/config/config.go b/pkg/config/config.go
 21index 1ad5108b7b9319683627faa0e89059686d9b0a10..60a34443248c65059a5aeed1b49e6055acab33fa 100644
 22--- a/pkg/config/config.go
 23+++ b/pkg/config/config.go
 24@@ -4,6 +4,7 @@ import (
 25 	"errors"
 26 	"fmt"
 27 	"io"
 28+	"log/slog"
 29 	"os"
 30 	"path"
 31 	"path/filepath"
 32@@ -19,6 +20,16 @@ 	ErrRepoPath        = errors.New("Repository path does not exist")
 33 	ErrInvalidProperty = errors.New("Invalid property")
 34 )
 35 
 36+type OrderBy int
 37+
 38+const (
 39+	Unordered OrderBy = iota
 40+	AlphabeticalAsc
 41+	AlphabeticalDesc
 42+	LastCommitAsc
 43+	LastCommitDesc
 44+)
 45+
 46 type (
 47 
 48 	// scan represents piece of the scan from the configuration file.
 49@@ -36,6 +47,7 @@ 		ListenAddr      string
 50 		Passphrase      string
 51 		SyntaxHighlight string
 52 		AESKey          string
 53+		OrderBy         string
 54 		Repositories    []*GitRepositoryConfiguration
 55 	}
 56 
 57@@ -58,6 +70,7 @@ 		listenAddr      string
 58 		passphrase      []byte
 59 		aesKey          []byte
 60 		syntaxHighlight string
 61+		orderBy         OrderBy
 62 		repositories    []*GitRepositoryConfiguration
 63 	}
 64 )
 65@@ -80,6 +93,7 @@ 		passphrase:      []byte(config.Passphrase),
 66 		repositories:    config.Repositories,
 67 		rootReadme:      config.RootReadme,
 68 		syntaxHighlight: config.SyntaxHighlight,
 69+		orderBy:         parseOrderBy(config.OrderBy),
 70 	}
 71 
 72 	for _, scan := range config.Scans {
 73@@ -97,6 +111,10 @@
 74 // GetRootReadme returns root read path
 75 func (c *ConfigurationRepository) GetRootReadme() string {
 76 	return c.rootReadme
 77+}
 78+
 79+func (c *ConfigurationRepository) GetOrderBy() OrderBy {
 80+	return c.orderBy
 81 }
 82 
 83 func (c *ConfigurationRepository) GetSyntaxHighlight() string {
 84@@ -211,6 +229,11 @@ 	if err != nil {
 85 		return nil, err
 86 	}
 87 
 88+	err = setOrderby(block, &config.OrderBy)
 89+	if err != nil {
 90+		return nil, err
 91+	}
 92+
 93 	err = setRepositories(block, &config.Repositories)
 94 	if err != nil {
 95 		return nil, err
 96@@ -316,6 +339,11 @@ 	scanDir := block.Get("syntax-highlight")
 97 	return setString(scanDir, listenAddr)
 98 }
 99 
100+func setOrderby(block scfg.Block, orderBy *string) error {
101+	scanDir := block.Get("order-by")
102+	return setString(scanDir, orderBy)
103+}
104+
105 func setListenAddr(block scfg.Block, listenAddr *string) error {
106 	scanDir := block.Get("listen-addr")
107 	return setString(scanDir, listenAddr)
108@@ -363,3 +391,24 @@ 		*field = u.FirstOrZero(dir.Params)
109 	}
110 	return nil
111 }
112+
113+func parseOrderBy(s string) OrderBy {
114+	switch s {
115+	case "":
116+		return LastCommitAsc
117+	case "unordered":
118+		return Unordered
119+	case "alphabetical-asc":
120+		return AlphabeticalAsc
121+	case "alphabetical-desc":
122+		return AlphabeticalDesc
123+	case "lastcommit-asc":
124+		return LastCommitAsc
125+	case "lastcommit-desc":
126+		return LastCommitDesc
127+	default:
128+		slog.Warn("Invalid order-by using default unordered")
129+		return LastCommitAsc
130+
131+	}
132+}
133diff --git a/pkg/handler/git/handler.go b/pkg/handler/git/handler.go
134index 436d36430c4c952af21c7fb95c9af8018cdd414f..9c7ba5b1ee25615a2347ae54a661ea06372a33c6 100644
135--- a/pkg/handler/git/handler.go
136+++ b/pkg/handler/git/handler.go
137@@ -9,8 +9,10 @@ 	"log/slog"
138 	"net/http"
139 	"os"
140 	"path/filepath"
141+	"sort"
142 	"strings"
143 
144+	"git.gabrielgio.me/cerrado/pkg/config"
145 	"git.gabrielgio.me/cerrado/pkg/ext"
146 	"git.gabrielgio.me/cerrado/pkg/service"
147 	"git.gabrielgio.me/cerrado/pkg/u"
148@@ -34,6 +36,7 @@
149 	configurationRepository interface {
150 		GetRootReadme() string
151 		GetSyntaxHighlight() string
152+		GetOrderBy() config.OrderBy
153 	}
154 )
155 
156@@ -79,7 +82,7 @@
157 	bs = markdown.Render(doc, renderer)
158 
159 	gitList := &templates.GitListPage{
160-		Respositories: repos,
161+		Respositories: orderBy(repos, g.config.GetOrderBy()),
162 		About:         bs,
163 	}
164 	templates.WritePageTemplate(w, gitList, r.Context())
165@@ -390,3 +393,26 @@
166 func isPublic(r *service.Repository) bool {
167 	return r.Public
168 }
169+
170+func orderBy(repos []*service.Repository, order config.OrderBy) []*service.Repository {
171+	switch order {
172+	case config.AlphabeticalAsc:
173+		sort.Slice(repos, func(i, j int) bool {
174+			return repos[i].Name < repos[j].Name
175+		})
176+	case config.AlphabeticalDesc:
177+		sort.Slice(repos, func(i, j int) bool {
178+			return repos[i].Name > repos[j].Name
179+		})
180+	case config.LastCommitAsc:
181+		sort.Slice(repos, func(i, j int) bool {
182+			return repos[i].LastCommit.Committer.When.Before(repos[j].LastCommit.Committer.When)
183+		})
184+	case config.LastCommitDesc:
185+		sort.Slice(repos, func(i, j int) bool {
186+			return repos[i].LastCommit.Committer.When.After(repos[j].LastCommit.Committer.When)
187+		})
188+	}
189+
190+	return repos
191+}