From d9cc1aabe83261e5249f7493a59c484fb99b4772 Mon Sep 17 00:00:00 2001 From: Julian T Date: Wed, 9 Sep 2020 15:44:07 +0200 Subject: Initial working version --- config.json | 5 ++ main.go | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ root.template | 57 ++++++++++++++++++++ 3 files changed, 231 insertions(+) create mode 100644 config.json create mode 100644 main.go create mode 100644 root.template diff --git a/config.json b/config.json new file mode 100644 index 0000000..ec59916 --- /dev/null +++ b/config.json @@ -0,0 +1,5 @@ +{ + "listen": "localhost:8080", + "db": "user=julian dbname=noteman sslmode=disable", + "tmpl": "" +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..dcb7d47 --- /dev/null +++ b/main.go @@ -0,0 +1,169 @@ +package main + +import ( + "net/http" + "flag" + "fmt" + "strings" + "crypto/md5" + "encoding/json" + "os" + "html/template" + "log" + "path" + + _"github.com/lib/pq" + "github.com/jmoiron/sqlx" +) + +type Config struct { + Listen string `json:"listen"` + DBStr string `json:"db"` + TmplPath string `json:"tmpl"` +} + +type Server struct { + mux *http.ServeMux + conf *Config + db *sqlx.DB +} + +type note struct { + Hash string + Name string + Location string +} + +const scheme = ` + CREATE TABLE IF NOT EXISTS notes ( + hash VARCHAR(4) PRIMARY KEY, + name TEXT NOT NULL, + location TEXT NOT NULL, + available BOOL DEFAULT True + ) +` + +func main() { + confFlag := flag.String("c", "config.json", "config file") + flag.Parse() + + f, err := os.Open(*confFlag) + if err != nil { + log.Fatal(err) + } + + var conf Config + err = json.NewDecoder(f).Decode(&conf) + if err != nil { + log.Fatal(err) + } + + s := NewServer(&conf) + if err != nil { + log.Fatal(err) + } + + err = s.Connect() + if err != nil { + log.Fatal(err) + } + + log.Fatal(s.Run()) +} + +func NewServer(conf *Config) *Server { + s := &Server{} + s.mux = http.NewServeMux() + s.mux.HandleFunc("/", s.httpRoot) + s.conf = conf + + return s +} + +func (s *Server) Connect() error { + var err error + s.db, err = sqlx.Connect("postgres", s.conf.DBStr) + if err != nil { + return err + } + + s.db.MustExec(scheme) + return nil +} + +func (s *Server) Run() error { + log.Printf("Listening on %s", s.conf.Listen) + return http.ListenAndServe(s.conf.Listen, s.mux) +} + +func (s *Server) renderTemplate(w http.ResponseWriter, data interface{}, pathname string) error { + + tmpl, err := template.ParseFiles(path.Join(s.conf.TmplPath, pathname)) + if err != nil { + log.Print(err) + return err + } + + err = tmpl.Execute(w, data) + if err != nil { + log.Print(err) + } + return err +} + +func (s *Server) httpCreateNode(w http.ResponseWriter, r *http.Request) { + var ( + name = r.FormValue("name") + location = r.FormValue("location") + ) + + hash := fmt.Sprintf("%x", md5.Sum([]byte(name)))[0:4] + + _, err := s.db.ExecContext(r.Context(), ` + INSERT INTO notes (hash, name, location) + VALUES ($1, $2, $3)`, hash, name, location) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + var ref strings.Builder + fmt.Fprintf(&ref, "#%s", hash) + if location != "" { + fmt.Fprintf(&ref, "/%s", location) + } + + fmt.Fprintf(w, ` + +

Note: %s

+

Location: %s

+

Hash: %s"

+

Ref: %s

+ `, name, location, hash, ref.String()) +} + +func (s *Server) httpRoot(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/" { + w.WriteHeader(http.StatusNotFound) + return + } + + if r.Method == "POST" { + s.httpCreateNode(w, r) + return + } + + var page struct { + Notes []note + Msg string + } + + err := s.db.SelectContext(r.Context(), &page.Notes, ` + SELECT hash, name, location FROM notes WHERE available = True`) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + s.renderTemplate(w, &page, "root.template") +} diff --git a/root.template b/root.template new file mode 100644 index 0000000..a492b7a --- /dev/null +++ b/root.template @@ -0,0 +1,57 @@ + + + Noteman + + + +
+ + + + + + + + + + + + + + + + +
Location format
PageP
BookB[id]S[page]
Notes git repoG


+
+ + + + + +
+


+ + + + + + {{ range .Notes }} + + + + + {{ end }} +
RefName
#{{ .Hash }}/{{ .Location }}{{ .Name }}
+ + -- cgit v1.2.3