forked from tangled.org/core
Monorepo for Tangled — https://tangled.org

add login, timeline, settings pages

Changed files
+200 -5
appview
+30 -2
appview/auth/auth.go
···
}
func (a *Auth) GetDID(r *http.Request) string {
-
clientSession, _ := a.Store.Get(r, appview.SessionName)
+
clientSession, err := a.Store.Get(r, appview.SessionName)
+
if err != nil || clientSession.IsNew {
+
return ""
+
}
+
return clientSession.Values[appview.SessionDid].(string)
}
func (a *Auth) GetHandle(r *http.Request) string {
-
clientSession, _ := a.Store.Get(r, appview.SessionHandle)
+
clientSession, err := a.Store.Get(r, appview.SessionName)
+
if err != nil || clientSession.IsNew {
+
return ""
+
}
+
return clientSession.Values[appview.SessionHandle].(string)
}
+
+
type User struct {
+
Handle string
+
Did string
+
Pds string
+
}
+
+
func (a *Auth) GetUser(r *http.Request) *User {
+
clientSession, err := a.Store.Get(r, appview.SessionName)
+
+
if err != nil || clientSession.IsNew {
+
return nil
+
}
+
+
return &User{
+
Handle: clientSession.Values[appview.SessionHandle].(string),
+
Did: clientSession.Values[appview.SessionDid].(string),
+
Pds: clientSession.Values[appview.SessionPds].(string),
+
}
+
}
+20
appview/pages/layout.html
···
+
<!DOCTYPE html>
+
<html lang="en">
+
<head>
+
<meta charset="UTF-8">
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
+
<script src="https://unpkg.com/htmx.org@2.0.4" integrity="sha384-HGfztofotfshcF7+8n44JQL2oJmowVChPTg48S+jvZoztPfvwD79OC/LTtG6dMp+" crossorigin="anonymous"></script>
+
<title>{{block "title" .}}tangled{{end}}</title>
+
</head>
+
<body>
+
+
<div class="navbar">
+
<a href="/" style="color: white; text-decoration: none;">Home</a>
+
</div>
+
+
<div class="content">
+
{{block "content" .}}{{end}}
+
</div>
+
+
</body>
+
</html>
+14
appview/pages/login.html
···
+
{{define "title"}}login{{end}}
+
+
{{define "content"}}
+
<h1>Login</h1>
+
<form method="POST" action="/login">
+
<label for="handle">handle</label>
+
<input type="text" id="handle" name="handle" required>
+
+
<label for="app_password">app password</label>
+
<input type="password" id="app_password" name="app_password" required>
+
+
<button type="submit">login</button>
+
</form>
+
{{end}}
+59
appview/pages/pages.go
···
+
package pages
+
+
import (
+
"embed"
+
"html/template"
+
"io"
+
"sync"
+
+
"github.com/sotangled/tangled/appview/auth"
+
"github.com/sotangled/tangled/appview/db"
+
)
+
+
//go:embed *.html
+
var files embed.FS
+
+
var (
+
cache = make(map[string]*template.Template)
+
mutex sync.Mutex
+
)
+
+
func parse(file string) *template.Template {
+
mutex.Lock()
+
defer mutex.Unlock()
+
+
if tmpl, found := cache[file]; found {
+
return tmpl
+
}
+
+
tmpl := template.Must(
+
template.New("layout.html").ParseFS(files, "layout.html", file),
+
)
+
+
cache[file] = tmpl
+
return tmpl
+
}
+
+
type LoginParams struct {
+
}
+
+
func Login(w io.Writer, p LoginParams) error {
+
return parse("login.html").Execute(w, p)
+
}
+
+
type TimelineParams struct {
+
User *auth.User
+
}
+
+
func Timeline(w io.Writer, p TimelineParams) error {
+
return parse("timeline.html").Execute(w, p)
+
}
+
+
type SettingsParams struct {
+
User *auth.User
+
PubKeys []db.PublicKey
+
}
+
+
func Settings(w io.Writer, p SettingsParams) error {
+
return parse("settings.html").Execute(w, p)
+
}
+34
appview/pages/settings.html
···
+
{{define "title"}}settings{{end}}
+
+
{{define "content"}}
+
<a href="/">back to timeline</a>
+
<h1>settings</h1>
+
+
<h2>profile</h2>
+
<p><strong>handle:</strong> {{.User.Handle}}</p>
+
<p><strong>did:</strong> {{.User.Did}}</p>
+
<p><strong>pds:</strong> {{.User.Pds}}</p>
+
+
<h2>ssh keys</h2>
+
<form hx-put="/settings/keys">
+
<label for="name">key name:</label>
+
<input type="text" id="name" name="name" required>
+
+
<label for="key">pub key:</label>
+
<textarea id="key" name="key" placeholder="ssh-rsa AAAAAA..." required></textarea>
+
+
<button type="submit">add key</button>
+
</form>
+
+
<h3>existing keys</h3>
+
<ul id="key-list">
+
{{range .PubKeys}}
+
<li>
+
<strong>{{.Name}}</strong><br>
+
<code>{{.Key}}</code>
+
</li>
+
{{else}}
+
<p>no ssh keys added yet</p>
+
{{end}}
+
</ul>
+
{{end}}
+10
appview/pages/timeline.html
···
+
{{define "title"}}timeline{{end}}
+
+
{{define "content"}}
+
<h1>timeline</h1>
+
+
{{ if .User }}
+
<p>logged in as {{ .User.Handle }}</p>
+
<a href="/settings">settings</a>
+
{{ end }}
+
{{end}}
+33 -3
appview/state/state.go
···
"github.com/sotangled/tangled/appview"
"github.com/sotangled/tangled/appview/auth"
"github.com/sotangled/tangled/appview/db"
+
"github.com/sotangled/tangled/appview/pages"
)
type State struct {
···
switch r.Method {
case http.MethodGet:
-
log.Println("unimplemented")
+
pages.Login(w, pages.LoginParams{})
return
case http.MethodPost:
handle := r.FormValue("handle")
···
}
}
+
func (s *State) Timeline(w http.ResponseWriter, r *http.Request) {
+
user := s.auth.GetUser(r)
+
fmt.Printf("%+v\n", user)
+
pages.Timeline(w, pages.TimelineParams{
+
User: user,
+
})
+
return
+
}
+
// requires auth
func (s *State) RegistrationKey(w http.ResponseWriter, r *http.Request) {
switch r.Method {
···
w.Write([]byte(key))
}
+
}
+
+
func (s *State) Settings(w http.ResponseWriter, r *http.Request) {
+
// for now, this is just pubkeys
+
user := s.auth.GetUser(r)
+
pubKeys, err := s.db.GetPublicKeys(user.Did)
+
if err != nil {
+
log.Println(err)
+
}
+
+
pages.Settings(w, pages.SettingsParams{
+
User: user,
+
PubKeys: pubKeys,
+
})
+
return
+
}
func (s *State) Keys(w http.ResponseWriter, r *http.Request) {
···
func (s *State) Router() http.Handler {
r := chi.NewRouter()
+
r.Get("/", s.Timeline)
+
+
r.Get("/login", s.Login)
r.Post("/login", s.Login)
r.Route("/node", func(r chi.Router) {
···
})
})
-
r.Route("/settings", func(r chi.Router) {
+
r.Group(func(r chi.Router) {
r.Use(AuthMiddleware(s))
-
r.Put("/keys", s.Keys)
+
r.Get("/settings", s.Settings)
+
r.Put("/settings/keys", s.Keys)
})
return r