internal/httpd/page.go

a32f7f2001c1c0bf38ba8c3360e6bc7ca3982fee
gitbay/internal/httpd/page.go history · blame · raw

77 lines · 2263 bytes

 1package httpd
 2
 3import (
 4	"net/http"
 5
 6	"gitbay.org/gitbay/internal/policy"
 7	"gitbay.org/gitbay/internal/store"
 8)
 9
10// railRepo is one pinned repository in the rail.
11type railRepo struct {
12	Owner string
13	Name  string
14}
15
16// rail is the viewer's cross-repo state the layout needs. The rail itself
17// is icons only, so what is left is the unread count on its bell; the
18// pinned repositories it used to list are rendered by the dashboard.
19type rail struct {
20	Pinned []railRepo
21	Unread int
22}
23
24// basePage is what the layout needs on every page, repo or not. Page
25// structs embed it so the rail and the site name are always in scope.
26type basePage struct {
27	// Site is the instance's display name; Host is the name a command or
28	// URL must use. Anything copy-pasteable takes Host.
29	Site   string
30	Host   string
31	Viewer string
32	Admin  bool // the viewer is an instance admin: the rail shows /admin
33	Rail   rail
34	// Theme is stamped on <html> as data-theme: light or dark when the
35	// viewer chose one, empty when the browser's own scheme decides.
36	Theme string
37}
38
39// base builds the layout-wide data for a request that has not already
40// resolved a viewer.
41func (s *Server) base(r *http.Request) basePage {
42	if s.cfg.Web.Mode != "accounts" {
43		return basePage{Site: s.siteName(), Host: s.cfg.SiteHost()}
44	}
45	return s.baseFor(s.viewer(r))
46}
47
48// baseFor is base for a handler that already holds the viewer, so the
49// session lookup is not repeated.
50func (s *Server) baseFor(viewer store.User) basePage {
51	b := basePage{Site: s.siteName(), Host: s.cfg.SiteHost()}
52	if viewer.ID == 0 {
53		return b
54	}
55	b.Viewer = viewer.Username
56	b.Admin = viewer.IsAdmin
57	b.Rail = s.railFor(viewer)
58	if theme, err := s.st.Theme(viewer.ID); err == nil && theme != "system" {
59		b.Theme = theme
60	}
61	return b
62}
63
64// railFor collects the viewer's pinned repositories and unread count,
65// dropping anything they may no longer read.
66func (s *Server) railFor(viewer store.User) rail {
67	var rl rail
68	pinned, _ := s.st.PinnedRepos(viewer.ID)
69	for _, rp := range pinned {
70		grant, _ := s.st.AccessRole(rp.ID, viewer.ID)
71		if policy.CanRead(viewer, rp, grant) {
72			rl.Pinned = append(rl.Pinned, railRepo{Owner: rp.OwnerName, Name: rp.Name})
73		}
74	}
75	rl.Unread = s.st.UnreadNotices(viewer.ID)
76	return rl
77}