this repo has no description

add login, timeline, settings pages

Akshay abdf4e5f 4a455312

Changed files
+200 -5
appview
+30 -2
appview/auth/auth.go
··· 179 179 } 180 180 181 181 func (a *Auth) GetDID(r *http.Request) string { 182 - clientSession, _ := a.Store.Get(r, appview.SessionName) 182 + clientSession, err := a.Store.Get(r, appview.SessionName) 183 + if err != nil || clientSession.IsNew { 184 + return "" 185 + } 186 + 183 187 return clientSession.Values[appview.SessionDid].(string) 184 188 } 185 189 186 190 func (a *Auth) GetHandle(r *http.Request) string { 187 - clientSession, _ := a.Store.Get(r, appview.SessionHandle) 191 + clientSession, err := a.Store.Get(r, appview.SessionName) 192 + if err != nil || clientSession.IsNew { 193 + return "" 194 + } 195 + 188 196 return clientSession.Values[appview.SessionHandle].(string) 189 197 } 198 + 199 + type User struct { 200 + Handle string 201 + Did string 202 + Pds string 203 + } 204 + 205 + func (a *Auth) GetUser(r *http.Request) *User { 206 + clientSession, err := a.Store.Get(r, appview.SessionName) 207 + 208 + if err != nil || clientSession.IsNew { 209 + return nil 210 + } 211 + 212 + return &User{ 213 + Handle: clientSession.Values[appview.SessionHandle].(string), 214 + Did: clientSession.Values[appview.SessionDid].(string), 215 + Pds: clientSession.Values[appview.SessionPds].(string), 216 + } 217 + }
+20
appview/pages/layout.html
··· 1 + <!DOCTYPE html> 2 + <html lang="en"> 3 + <head> 4 + <meta charset="UTF-8"> 5 + <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 + <script src="https://unpkg.com/htmx.org@2.0.4" integrity="sha384-HGfztofotfshcF7+8n44JQL2oJmowVChPTg48S+jvZoztPfvwD79OC/LTtG6dMp+" crossorigin="anonymous"></script> 7 + <title>{{block "title" .}}tangled{{end}}</title> 8 + </head> 9 + <body> 10 + 11 + <div class="navbar"> 12 + <a href="/" style="color: white; text-decoration: none;">Home</a> 13 + </div> 14 + 15 + <div class="content"> 16 + {{block "content" .}}{{end}} 17 + </div> 18 + 19 + </body> 20 + </html>
+14
appview/pages/login.html
··· 1 + {{define "title"}}login{{end}} 2 + 3 + {{define "content"}} 4 + <h1>Login</h1> 5 + <form method="POST" action="/login"> 6 + <label for="handle">handle</label> 7 + <input type="text" id="handle" name="handle" required> 8 + 9 + <label for="app_password">app password</label> 10 + <input type="password" id="app_password" name="app_password" required> 11 + 12 + <button type="submit">login</button> 13 + </form> 14 + {{end}}
+59
appview/pages/pages.go
··· 1 + package pages 2 + 3 + import ( 4 + "embed" 5 + "html/template" 6 + "io" 7 + "sync" 8 + 9 + "github.com/sotangled/tangled/appview/auth" 10 + "github.com/sotangled/tangled/appview/db" 11 + ) 12 + 13 + //go:embed *.html 14 + var files embed.FS 15 + 16 + var ( 17 + cache = make(map[string]*template.Template) 18 + mutex sync.Mutex 19 + ) 20 + 21 + func parse(file string) *template.Template { 22 + mutex.Lock() 23 + defer mutex.Unlock() 24 + 25 + if tmpl, found := cache[file]; found { 26 + return tmpl 27 + } 28 + 29 + tmpl := template.Must( 30 + template.New("layout.html").ParseFS(files, "layout.html", file), 31 + ) 32 + 33 + cache[file] = tmpl 34 + return tmpl 35 + } 36 + 37 + type LoginParams struct { 38 + } 39 + 40 + func Login(w io.Writer, p LoginParams) error { 41 + return parse("login.html").Execute(w, p) 42 + } 43 + 44 + type TimelineParams struct { 45 + User *auth.User 46 + } 47 + 48 + func Timeline(w io.Writer, p TimelineParams) error { 49 + return parse("timeline.html").Execute(w, p) 50 + } 51 + 52 + type SettingsParams struct { 53 + User *auth.User 54 + PubKeys []db.PublicKey 55 + } 56 + 57 + func Settings(w io.Writer, p SettingsParams) error { 58 + return parse("settings.html").Execute(w, p) 59 + }
+34
appview/pages/settings.html
··· 1 + {{define "title"}}settings{{end}} 2 + 3 + {{define "content"}} 4 + <a href="/">back to timeline</a> 5 + <h1>settings</h1> 6 + 7 + <h2>profile</h2> 8 + <p><strong>handle:</strong> {{.User.Handle}}</p> 9 + <p><strong>did:</strong> {{.User.Did}}</p> 10 + <p><strong>pds:</strong> {{.User.Pds}}</p> 11 + 12 + <h2>ssh keys</h2> 13 + <form hx-put="/settings/keys"> 14 + <label for="name">key name:</label> 15 + <input type="text" id="name" name="name" required> 16 + 17 + <label for="key">pub key:</label> 18 + <textarea id="key" name="key" placeholder="ssh-rsa AAAAAA..." required></textarea> 19 + 20 + <button type="submit">add key</button> 21 + </form> 22 + 23 + <h3>existing keys</h3> 24 + <ul id="key-list"> 25 + {{range .PubKeys}} 26 + <li> 27 + <strong>{{.Name}}</strong><br> 28 + <code>{{.Key}}</code> 29 + </li> 30 + {{else}} 31 + <p>no ssh keys added yet</p> 32 + {{end}} 33 + </ul> 34 + {{end}}
+10
appview/pages/timeline.html
··· 1 + {{define "title"}}timeline{{end}} 2 + 3 + {{define "content"}} 4 + <h1>timeline</h1> 5 + 6 + {{ if .User }} 7 + <p>logged in as {{ .User.Handle }}</p> 8 + <a href="/settings">settings</a> 9 + {{ end }} 10 + {{end}}
+33 -3
appview/state/state.go
··· 18 18 "github.com/sotangled/tangled/appview" 19 19 "github.com/sotangled/tangled/appview/auth" 20 20 "github.com/sotangled/tangled/appview/db" 21 + "github.com/sotangled/tangled/appview/pages" 21 22 ) 22 23 23 24 type State struct { ··· 50 51 51 52 switch r.Method { 52 53 case http.MethodGet: 53 - log.Println("unimplemented") 54 + pages.Login(w, pages.LoginParams{}) 54 55 return 55 56 case http.MethodPost: 56 57 handle := r.FormValue("handle") ··· 84 85 } 85 86 } 86 87 88 + func (s *State) Timeline(w http.ResponseWriter, r *http.Request) { 89 + user := s.auth.GetUser(r) 90 + fmt.Printf("%+v\n", user) 91 + pages.Timeline(w, pages.TimelineParams{ 92 + User: user, 93 + }) 94 + return 95 + } 96 + 87 97 // requires auth 88 98 func (s *State) RegistrationKey(w http.ResponseWriter, r *http.Request) { 89 99 switch r.Method { ··· 118 128 119 129 w.Write([]byte(key)) 120 130 } 131 + } 132 + 133 + func (s *State) Settings(w http.ResponseWriter, r *http.Request) { 134 + // for now, this is just pubkeys 135 + user := s.auth.GetUser(r) 136 + pubKeys, err := s.db.GetPublicKeys(user.Did) 137 + if err != nil { 138 + log.Println(err) 139 + } 140 + 141 + pages.Settings(w, pages.SettingsParams{ 142 + User: user, 143 + PubKeys: pubKeys, 144 + }) 145 + return 146 + 121 147 } 122 148 123 149 func (s *State) Keys(w http.ResponseWriter, r *http.Request) { ··· 284 310 func (s *State) Router() http.Handler { 285 311 r := chi.NewRouter() 286 312 313 + r.Get("/", s.Timeline) 314 + 315 + r.Get("/login", s.Login) 287 316 r.Post("/login", s.Login) 288 317 289 318 r.Route("/node", func(r chi.Router) { ··· 295 324 }) 296 325 }) 297 326 298 - r.Route("/settings", func(r chi.Router) { 327 + r.Group(func(r chi.Router) { 299 328 r.Use(AuthMiddleware(s)) 300 - r.Put("/keys", s.Keys) 329 + r.Get("/settings", s.Settings) 330 + r.Put("/settings/keys", s.Keys) 301 331 }) 302 332 303 333 return r