diff options
author | Julian T <julian@jtle.dk> | 2020-09-09 15:44:07 +0200 |
---|---|---|
committer | Julian T <julian@jtle.dk> | 2020-09-09 15:44:07 +0200 |
commit | d9cc1aabe83261e5249f7493a59c484fb99b4772 (patch) | |
tree | 1a351c53c0adfeb4dacdb2ee933c359965860108 /main.go |
Initial working version
Diffstat (limited to 'main.go')
-rw-r--r-- | main.go | 169 |
1 files changed, 169 insertions, 0 deletions
@@ -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") +} |