blob: fe80fe023d2579ca6a74c8216480928c321d6fa2 [file] [log] [blame]
Davit Tabidze207ce082024-04-09 19:15:25 +04001package welcome
2
3import (
4 "embed"
5 "fmt"
6 "html/template"
7 "log"
8 "net/http"
9 "strings"
Davit Tabidze56f86a42024-04-09 19:15:25 +040010
11 "github.com/giolekva/pcloud/core/installer"
gioc23530e2024-05-01 11:06:09 +040012
13 "github.com/gomarkdown/markdown"
Davit Tabidze207ce082024-04-09 19:15:25 +040014)
15
16//go:embed launcher-tmpl/launcher.html
17var indexHTML embed.FS
18
19//go:embed static/*
20var files embed.FS
21
22type AppLauncherInfo struct {
Davit Tabidze56f86a42024-04-09 19:15:25 +040023 Name string
24 Icon template.HTML
gioc23530e2024-05-01 11:06:09 +040025 Help []HelpDocumentRendered
Davit Tabidze56f86a42024-04-09 19:15:25 +040026 Url string
Davit Tabidze207ce082024-04-09 19:15:25 +040027}
28
gioc23530e2024-05-01 11:06:09 +040029type HelpDocumentRendered struct {
30 Title string
31 Contents template.HTML
32 Children []HelpDocumentRendered
33}
34
Davit Tabidze207ce082024-04-09 19:15:25 +040035type AppDirectory interface {
36 GetAllApps() ([]AppLauncherInfo, error)
37}
38
Davit Tabidze56f86a42024-04-09 19:15:25 +040039type AppManagerDirectory struct {
40 AppManager *installer.AppManager
41}
42
gio09a3e5b2024-04-26 14:11:06 +040043func (d *AppManagerDirectory) GetAllApps() ([]AppLauncherInfo, error) {
44 all, err := d.AppManager.FindAllInstances()
45 if err != nil {
46 return nil, err
47 }
48 ret := []AppLauncherInfo{}
49 for _, a := range all {
50 if a.URL == "" && len(a.Help) == 0 {
51 continue
52 }
53 ret = append(ret, AppLauncherInfo{
54 Name: a.AppId,
55 Icon: template.HTML(a.Icon),
gioc23530e2024-05-01 11:06:09 +040056 Help: toMarkdown(a.Help),
gio09a3e5b2024-04-26 14:11:06 +040057 Url: a.URL,
58 })
59 }
60 return ret, nil
61}
62
Davit Tabidze207ce082024-04-09 19:15:25 +040063type LauncherServer struct {
64 port int
65 logoutUrl string
66 appDirectory AppDirectory
67 homeTmpl *template.Template
68}
69
70func NewLauncherServer(
71 port int,
72 logoutUrl string,
73 appDirectory AppDirectory,
74) (*LauncherServer, error) {
75 tmpl, err := indexHTML.ReadFile("launcher-tmpl/launcher.html")
76 if err != nil {
77 return nil, fmt.Errorf("failed to parse template: %v", err)
78 }
79 t := template.New("index").Funcs(template.FuncMap{
80 "GetUserInitials": getUserInitials,
81 "CleanAppName": cleanAppName,
82 })
83 t, err = t.Parse(string(tmpl))
84 if err != nil {
85 return nil, fmt.Errorf("failed to parse template: %v", err)
86 }
87 return &LauncherServer{
88 port,
89 logoutUrl,
90 appDirectory,
91 t,
92 }, nil
93}
94
95func getUserInitials(username string) string {
96 if username == "" {
97 return ""
98 }
99 return strings.ToUpper(username[:1])
100}
101
102func cleanAppName(name string) string {
103 cleanName := strings.ToLower(name)
104 cleanName = strings.ReplaceAll(cleanName, " ", "-")
105 return cleanName
106}
107
Davit Tabidze56f86a42024-04-09 19:15:25 +0400108func getLoggedInUser(r *http.Request) (string, error) {
109 if user := r.Header.Get("X-User"); user != "" {
110 return user, nil
111 } else {
112 return "", fmt.Errorf("unauthenticated")
113 }
114 // return "Username", nil
115}
116
Davit Tabidze207ce082024-04-09 19:15:25 +0400117func (s *LauncherServer) Start() {
118 http.Handle("/static/", http.FileServer(http.FS(files)))
119 http.HandleFunc("/", s.homeHandler)
120 log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", s.port), nil))
121}
122
123type homeHandlerData struct {
124 LoggedInUsername string
125 AllAppsInfo []AppLauncherInfo
126}
127
128func (s *LauncherServer) homeHandler(w http.ResponseWriter, r *http.Request) {
Davit Tabidze56f86a42024-04-09 19:15:25 +0400129 loggedInUsername, err := getLoggedInUser(r)
130 if err != nil {
131 http.Error(w, "User Not Logged In", http.StatusUnauthorized)
132 return
133 }
Davit Tabidze207ce082024-04-09 19:15:25 +0400134 allAppsInfo, err := s.appDirectory.GetAllApps()
135 if err != nil {
Davit Tabidze56f86a42024-04-09 19:15:25 +0400136 http.Error(w, err.Error(), http.StatusInternalServerError)
Davit Tabidze207ce082024-04-09 19:15:25 +0400137 }
138 data := homeHandlerData{
139 LoggedInUsername: loggedInUsername,
140 AllAppsInfo: allAppsInfo,
141 }
142 if err := s.homeTmpl.Execute(w, data); err != nil {
143 http.Error(w, err.Error(), http.StatusInternalServerError)
144 return
145 }
146}
gioc23530e2024-05-01 11:06:09 +0400147
148func toMarkdown(help []installer.HelpDocument) []HelpDocumentRendered {
149 if help == nil {
150 return nil
151 }
152 var ret []HelpDocumentRendered
153 for _, h := range help {
154 ret = append(ret, HelpDocumentRendered{
155 Title: h.Title,
156 Contents: template.HTML(markdown.ToHTML([]byte(h.Contents), nil, nil)),
157 Children: toMarkdown(h.Children),
158 })
159 }
160 return ret
161}