Put discussions feature behind flag

60b8dd63c9ab310178d391edd8d71ffc0ea2a618
Alexis Sellier committed ago 1 parent 1f53abd7
handler.go +19 -7
18 18
	Ref             string
19 19
	CommitHash      string
20 20
	Handle          string
21 21
	Avatar          string
22 22
	DevMode         bool
23 +
	Discussions     bool
23 24
	Data            any
24 25
}
25 26
26 27
func (s *server) newPageData(r *http.Request, repo *RepoInfo, section, ref string) pageData {
27 -
	handle := getSessionHandle(r)
28 -
	var avatar string
29 -
	if handle != "" {
30 -
		avatar = getAvatar(s.db, handle)
28 +
	var handle, avatar string
29 +
	if s.discussions {
30 +
		handle = getSessionHandle(r)
31 +
		if handle != "" {
32 +
			avatar = getAvatar(s.db, handle)
33 +
		}
31 34
	}
32 35
	pd := pageData{
33 36
		SiteTitle:       s.title,
34 37
		SiteDescription: s.description,
35 38
		BaseURL:         s.baseURL,
36 39
		Section:         section,
37 40
		Ref:             ref,
38 41
		Handle:          handle,
39 42
		Avatar:          avatar,
40 43
		DevMode:         s.dev,
44 +
		Discussions:     s.discussions,
41 45
	}
42 46
	if repo != nil {
43 47
		pd.Repo = repo.Name
44 48
		pd.Description = repo.Description
45 49
	}
106 110
	if path == "" {
107 111
		s.handleIndex(w, r)
108 112
		return
109 113
	}
110 114
111 -
	if path == "login" {
115 +
	if path == "login" && s.discussions {
112 116
		s.handleLogin(w, r)
113 117
		return
114 118
	}
115 -
	if path == "logout" {
119 +
	if path == "logout" && s.discussions {
116 120
		s.handleLogout(w, r)
117 121
		return
118 122
	}
119 123
120 -
	if path == "dev/login" && s.dev {
124 +
	if path == "dev/login" && s.dev && s.discussions {
121 125
		s.handleDevLogin(w, r)
122 126
		return
123 127
	}
124 128
125 129
	// Site-level forum (discussions not scoped to a repo).
126 130
	if path == "discussions" || strings.HasPrefix(path, "discussions/") {
131 +
		if !s.discussions {
132 +
			s.renderError(w, r, http.StatusNotFound, "Page not found")
133 +
			return
134 +
		}
127 135
		rest := strings.TrimPrefix(path, "discussions")
128 136
		rest = strings.TrimPrefix(rest, "/")
129 137
		s.routeSiteDiscussions(w, r, rest)
130 138
		return
131 139
	}
166 174
	case "commit":
167 175
		s.handleCommit(w, r, repo, rest)
168 176
	case "raw":
169 177
		s.handleRaw(w, r, repo, rest)
170 178
	case "discussions":
179 +
		if !s.discussions {
180 +
			s.renderError(w, r, http.StatusNotFound, "Page not found")
181 +
			return
182 +
		}
171 183
		s.routeDiscussions(w, r, repo, rest)
172 184
	default:
173 185
		s.renderError(w, r, http.StatusNotFound, "Page not found")
174 186
	}
175 187
}
main.go +10 -4
22 22
	baseURL     string
23 23
	scanPath    string
24 24
	username    string
25 25
	password    string
26 26
	dev         bool
27 +
	discussions bool
27 28
}
28 29
29 30
func main() {
30 31
	listen := flag.String("listen", ":8080", "listen address")
31 32
	scanPath := flag.String("scan-path", ".", "path to scan for git repos")
34 35
	baseURL := flag.String("base-url", "", "base URL prefix (e.g. /git)")
35 36
	nonBare := flag.Bool("non-bare", false, "also scan for non-bare repos (dirs containing .git)")
36 37
	username := flag.String("username", "", "HTTP basic auth username (requires -password)")
37 38
	password := flag.String("password", "", "HTTP basic auth password (requires -username)")
38 39
	dbPath := flag.String("db-path", "./forge.db", "path to SQLite database for discussions")
40 +
	discussions := flag.Bool("discussions", false, "enable discussions feature")
39 41
	dev := flag.Bool("dev", false, "enable dev mode (auto sign-in link)")
40 42
	flag.Parse()
41 43
42 44
	if (*username == "") != (*password == "") {
43 45
		log.Fatal("-username and -password must both be set, or both be omitted")
64 66
	tmpl, err := loadTemplates()
65 67
	if err != nil {
66 68
		log.Fatalf("load templates: %v", err)
67 69
	}
68 70
69 -
	db, err := openDB(*dbPath)
70 -
	if err != nil {
71 -
		log.Fatalf("open database: %v", err)
71 +
	var db *sql.DB
72 +
	if *discussions {
73 +
		db, err = openDB(*dbPath)
74 +
		if err != nil {
75 +
			log.Fatalf("open database: %v", err)
76 +
		}
77 +
		defer db.Close()
72 78
	}
73 -
	defer db.Close()
74 79
75 80
	srv := &server{
76 81
		repos:       repos,
77 82
		sorted:      sorted,
78 83
		tmpl:        tmpl,
82 87
		baseURL:     strings.TrimRight(*baseURL, "/"),
83 88
		scanPath:    abs,
84 89
		username:    *username,
85 90
		password:    *password,
86 91
		dev:         *dev,
92 +
		discussions: *discussions,
87 93
	}
88 94
89 95
	mux := http.NewServeMux()
90 96
	mux.HandleFunc("/style.css", srv.serveCSS)
91 97
	mux.HandleFunc("/radiant.svg", srv.serveLogo)
templates/layout.html +5 -5
10 10
<div class="container">
11 11
{{if not .Repo}}
12 12
<nav class="repo-nav">
13 13
  <span class="repo-name"><a href="{{.BaseURL}}/" class="logo-link"><img class="logo" src="{{.BaseURL}}/radiant.svg" alt="" width="16" height="16"></a><a href="{{.BaseURL}}/">{{.SiteTitle}}</a>{{if .SiteDescription}}<span class="repo-desc desktop">{{.SiteDescription}}</span>{{end}}</span>
14 14
  <a href="{{.BaseURL}}/" class="tab{{if eq .Section "repositories"}} active{{end}}">repositories</a>
15 -
  <a href="{{.BaseURL}}/discussions" class="tab{{if eq .Section "forum"}} active{{end}}">discussions</a>
16 -
  <span class="nav-auth">{{if .Handle}}<details class="avatar-menu"><summary>{{if .Avatar}}<img class="avatar" src="{{.Avatar}}" alt="" width="24" height="24">{{else}}<span class="avatar-placeholder">{{.Handle}}</span>{{end}}</summary><div class="avatar-dropdown"><span class="signed-in">{{.Handle}}</span><a href="{{.BaseURL}}/logout?return={{.BaseURL}}/" class="btn nav-btn">Sign out</a></div></details>{{else}}<a href="{{.BaseURL}}/login?return={{.BaseURL}}/" class="btn nav-btn">Sign in</a>{{end}}</span>
15 +
  {{if .Discussions}}<a href="{{.BaseURL}}/discussions" class="tab{{if eq .Section "forum"}} active{{end}}">discussions</a>{{end}}
16 +
  {{if .Discussions}}<span class="nav-auth">{{if .Handle}}<details class="avatar-menu"><summary>{{if .Avatar}}<img class="avatar" src="{{.Avatar}}" alt="" width="24" height="24">{{else}}<span class="avatar-placeholder">{{.Handle}}</span>{{end}}</summary><div class="avatar-dropdown"><span class="signed-in">{{.Handle}}</span><a href="{{.BaseURL}}/logout?return={{.BaseURL}}/" class="btn nav-btn">Sign out</a></div></details>{{else}}<a href="{{.BaseURL}}/login?return={{.BaseURL}}/" class="btn nav-btn">Sign in</a>{{end}}</span>{{end}}
17 17
</nav>
18 18
{{end}}
19 19
{{if .Repo}}
20 20
<nav class="repo-nav">
21 21
  <span class="repo-name"><a href="{{.BaseURL}}/" class="logo-link"><img class="logo" src="{{.BaseURL}}/radiant.svg" alt="" width="16" height="16"></a><a href="{{.BaseURL}}/{{.Repo}}/">{{.Repo}}</a>{{if .Description}}<span class="repo-desc desktop">{{.Description}}</span>{{end}}</span>
22 22
  <a href="{{.BaseURL}}/{{.Repo}}/" class="tab{{if eq .Section "home"}} active{{end}}">home</a>
23 23
  <a href="{{.BaseURL}}/{{.Repo}}/log/{{.Ref}}" class="tab{{if eq .Section "log"}} active{{end}}">log</a>
24 24
  <a href="{{.BaseURL}}/{{.Repo}}/refs" class="tab{{if eq .Section "refs"}} active{{end}}">refs</a>
25 -
  <a href="{{.BaseURL}}/{{.Repo}}/discussions" class="tab{{if eq .Section "discussions"}} active{{end}}">discussions</a>
25 +
  {{if .Discussions}}<a href="{{.BaseURL}}/{{.Repo}}/discussions" class="tab{{if eq .Section "discussions"}} active{{end}}">discussions</a>{{end}}
26 26
  {{if .CommitHash}}<a href="{{.BaseURL}}/{{.Repo}}/commit/{{.CommitHash}}" class="tab tab-mono active">{{shortHash .CommitHash}}</a>{{end}}
27 -
  <span class="nav-auth">{{if .Handle}}<details class="avatar-menu"><summary>{{if .Avatar}}<img class="avatar" src="{{.Avatar}}" alt="" width="24" height="24">{{else}}<span class="avatar-placeholder">{{.Handle}}</span>{{end}}</summary><div class="avatar-dropdown"><span class="signed-in">{{.Handle}}</span><a href="{{.BaseURL}}/logout?return={{.BaseURL}}/{{.Repo}}/" class="btn nav-btn">Sign out</a></div></details>{{else}}<a href="{{.BaseURL}}/login?return={{.BaseURL}}/{{.Repo}}/" class="btn nav-btn">Sign in</a>{{end}}</span>
27 +
  {{if .Discussions}}<span class="nav-auth">{{if .Handle}}<details class="avatar-menu"><summary>{{if .Avatar}}<img class="avatar" src="{{.Avatar}}" alt="" width="24" height="24">{{else}}<span class="avatar-placeholder">{{.Handle}}</span>{{end}}</summary><div class="avatar-dropdown"><span class="signed-in">{{.Handle}}</span><a href="{{.BaseURL}}/logout?return={{.BaseURL}}/{{.Repo}}/" class="btn nav-btn">Sign out</a></div></details>{{else}}<a href="{{.BaseURL}}/login?return={{.BaseURL}}/{{.Repo}}/" class="btn nav-btn">Sign in</a>{{end}}</span>{{end}}
28 28
</nav>
29 29
{{end}}
30 30
<main>
31 31
{{template "content" .}}
32 32
</main>
33 33
{{if not .Repo}}
34 34
<footer>
35 -
  <p><span class="powered-by">Powered by <a href="https://code.radiant.computer/forge">Radiant Forge</a></span>{{if and .DevMode (not .Handle)}}<span class="dev-login"><a href="{{.BaseURL}}/dev/login?return={{.BaseURL}}/">Sign in as cloudhead.io</a></span>{{end}}<span class="copyright">&copy; 2026 Radiant Computer</span></p>
35 +
  <p><span class="powered-by">Powered by <a href="https://code.radiant.computer/forge">Radiant Forge</a></span>{{if and .Discussions .DevMode (not .Handle)}}<span class="dev-login"><a href="{{.BaseURL}}/dev/login?return={{.BaseURL}}/">Sign in as cloudhead.io</a></span>{{end}}<span class="copyright">&copy; 2026 Radiant Computer</span></p>
36 36
</footer>
37 37
{{end}}
38 38
</div>
39 39
<script src="{{.BaseURL}}/js/hirad.js"></script>
40 40
<script src="{{.BaseURL}}/js/hiril.js"></script>