summaryrefslogtreecommitdiff
path: root/main.go
diff options
context:
space:
mode:
authorJulian T <julian@jtle.dk>2020-09-09 15:44:07 +0200
committerJulian T <julian@jtle.dk>2020-09-09 15:44:07 +0200
commitd9cc1aabe83261e5249f7493a59c484fb99b4772 (patch)
tree1a351c53c0adfeb4dacdb2ee933c359965860108 /main.go
Initial working version
Diffstat (limited to 'main.go')
-rw-r--r--main.go169
1 files changed, 169 insertions, 0 deletions
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, `
+ <html>
+ <p><b>Note:</b> %s</p>
+ <p><b>Location:</b> %s</p>
+ <p><b>Hash:</b> %s"</p>
+ <p><b>Ref:</b> %s</p>
+ </html>`, 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")
+}