package main import ( "fmt" "html/template" "io/ioutil" "log" "net" "net/http" "os" "os/signal" "path" "time" "github.com/VictorAvelar/mollie-api-go/v3/mollie" "github.com/gin-contrib/multitemplate" "github.com/gin-gonic/gin" yaml "gopkg.in/yaml.v2" "gorm.io/gorm" ) // var SOCKNAME = "thomas.sock" var addr = "0.0.0.0:3000" type Config struct { MollieToken string `yaml:"mollie_token"` MollieTesting bool `yaml:"mollie_testing"` MollieWebhook string `yaml:"mollie_webhook"` MollieRedirectURL string `yaml:"mollie_redirect_url"` MailServer string `yaml:"mail_server"` MailPort int `yaml:"mail_port"` MailUser string `yaml:"mail_user"` MailPass string `yaml:"mail_pass"` FromAddr string `yaml:"from_addr"` BCC string `yaml:"bcc"` } var config Config var mollieClient *mollie.Client var ROOT_DIR string func notFound(w http.ResponseWriter, r *http.Request) error { w.WriteHeader(http.StatusNotFound) t, err := template.ParseFiles(path.Join(ROOT_DIR, "templates/404.html")) if err != nil { return err } return t.Execute(w, nil) } func index(c *gin.Context) { db := getDB(c) products := []Product{} db.Order("id desc").Find(&products) c.HTML(http.StatusOK, "index", map[string]interface{}{ "products": products, }) } func getPage(name string) func(c *gin.Context) { return func(c *gin.Context) { c.HTML(http.StatusOK, name, map[string]interface{}{}) } } func handle404(c *gin.Context) { c.HTML(http.StatusOK, "404.html", map[string]interface{}{}) } func createSocket(s string) net.Listener { os.Remove(s) log.Println("Creating UNIX socket:", s) sock, err := net.Listen("unix", s) if err != nil { panic(err) } err = os.Chmod(s, 0777) if err != nil { panic(err) } return sock } func getDB(c *gin.Context) *gorm.DB { item, _ := c.Get("db") db := item.(*gorm.DB) return db } func getProd(id uint, products []Product) *Product { for _, prod := range products { if prod.ID == id { return &prod } } return nil } func createMyRender(base string) multitemplate.Renderer { r := multitemplate.NewRenderer() f := template.FuncMap{ "formatMoney": func(cents int) string { return fmt.Sprintf("€%.2f", float64(float64(cents)/100)) }, "mult": func(x, y int) int { return x * y }, "plus": func(a, b int) int { return a + b }, "total": func(a Product, ac int, b Product, bc int, c Product, cc int) int { return a.Price*ac + b.Price*bc + c.Price*cc }, "nowYear": func() string { return time.Now().Format("2006") }, "getProd": getProd, "countries": func() map[string]string { return countries }, "menu": func() []MenuItem { return getMenuItems() }, } r.AddFromFilesFuncs("404.html", f, path.Join(base, "base.html"), path.Join(base, "404.html")) r.AddFromFilesFuncs("index", f, path.Join(base, "base.html"), path.Join(base, "index.html")) r.AddFromFilesFuncs("orderInfo", f, path.Join(base, "base.html"), path.Join(base, "order_info.html")) r.AddFromFilesFuncs("orderPending", f, path.Join(base, "base.html"), path.Join(base, "order_pending.html")) r.AddFromFilesFuncs("orderThankyou", f, path.Join(base, "base.html"), path.Join(base, "order_thankyou.html")) r.AddFromFilesFuncs("checkout", f, path.Join(base, "base.html"), path.Join(base, "order_checkout.html")) r.AddFromFilesFuncs("terms-and-conditions", f, path.Join(base, "base.html"), path.Join(base, "new_terms.html")) r.AddFromFilesFuncs("terms-of-delivery", f, path.Join(base, "base.html"), path.Join(base, "terms-of-delivery.html")) return r } func main() { if len(os.Args) > 1 { ROOT_DIR = os.Args[1] } go func() { getMenuItems() }() log.Printf("Running from with app root dir: %s\n", ROOT_DIR) configPath := path.Join(ROOT_DIR, "data/config/config.yaml") configBytes, err := ioutil.ReadFile(configPath) if err != nil { panic(fmt.Sprintf("Can't open config file at %s; %v", configPath, err)) } if err := yaml.Unmarshal([]byte(configBytes), &config); err != nil { panic(fmt.Sprintf("Can't parse config file at %s; %v", configPath, err)) } if mollieClient, err = initMollie(); err != nil { panic(err) } db := GetDB() r := gin.Default() r.HTMLRender = createMyRender(path.Join(ROOT_DIR, "templates")) r.Use(func(c *gin.Context) { c.Set("db", db) c.Next() }) if k, v := os.LookupEnv("RUN_STATIC"); v && k == "true" { r.Static("/static", "./dist") } r.GET("/", index) r.POST("/order", postGetOrderInfo) r.GET("/order", index) r.POST("/order/checkout", postCheckout) r.POST("/order/create-order", createOrder) r.POST("/order/webhook", postMollieWebhook) r.GET("/order/thankyou", getPreOrderThankYou) r.POST("/order/retry/:orderid", postOrderRetry) r.GET("/order/pending/:orderid", getPendingOrder) r.GET("/terms-and-conditions", getPage("terms-and-conditions")) r.GET("/terms-of-delivery", getPage("terms-of-delivery")) r.NoRoute(handle404) // sockPath := path.Join(ROOT_DIR, "run", SOCKNAME) // sock := createSocket(sockPath) server := http.Server{ Handler: r, Addr: addr, } fmt.Println("Running...") go func() { log.Fatal(server.ListenAndServe()) }() c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt) // Block until a signal is received. <-c fmt.Println("Stopping...") // os.Remove(path.Join(ROOT_DIR, "run", SOCKNAME)) }