/* guestbook - Standalone guestbook server for static websites * Copyright (C) 2025 Vidhu Kant Sharma * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package cmd import ( "fmt" "log" "strings" "net/http" "vidhukant.com/guestbook/db" "github.com/spf13/cobra" "github.com/spf13/viper" ) var serveCmd = &cobra.Command{ Use: "serve", Short: "Start the guestbook server", Long: "Start the guestbook server", Run: func(cmd *cobra.Command, args []string) { guestbookName, err := cmd.Flags().GetString("guestbook") if err != nil { log.Fatal(err) } port := viper.GetString(guestbookName + ".port") validationString := viper.GetString(guestbookName + ".validation_string") path := viper.GetString(guestbookName + ".path") if path == "/" { log.Fatalf("Setting %s.path to / is not allowed as it may cause issues.", guestbookName) } successRedirect := viper.GetString(guestbookName + ".success_redirect") if successRedirect == "" { log.Fatalf("%s.success_redirect cannot be blank.", guestbookName) } errorRedirect := viper.GetString(guestbookName + ".error_redirect") if errorRedirect == "" { log.Fatalf("%s.error_redirect cannot be blank.", guestbookName) } conn := db.Connect() defer conn.Close() _, err = conn.Exec( fmt.Sprintf( "CREATE TABLE IF NOT EXISTS %s (" + "id INT AUTO_INCREMENT PRIMARY KEY," + "name TEXT," + "website TEXT," + "message TEXT" + ");", guestbookName, ), ) if err != nil { log.Fatalf("Error while creating table: %v\n", err) } http.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Redirect(w, r, errorRedirect, http.StatusSeeOther) return } var data db.GuestbookEntry err := r.ParseForm() data.Name = r.FormValue("name") data.Website = r.FormValue("website") data.Message = strings.Replace(r.FormValue("message"), "\n", "
", -1) data.Validation = r.FormValue("validation") if err != nil { log.Printf("Error occurred while decoding data: %v") http.Redirect(w, r, errorRedirect, http.StatusSeeOther) return } if data.Validation != validationString || data.Name == "" || data.Message == "" { http.Redirect(w, r, errorRedirect, http.StatusSeeOther) return } stmt, err := conn.Prepare(fmt.Sprintf("INSERT INTO %s (name, website, message) VALUES (?, ?, ?)", guestbookName)) if err != nil { log.Printf("Error occurred while preparing statement data: %v\n") http.Redirect(w, r, errorRedirect, http.StatusSeeOther) return } defer stmt.Close() _, err = stmt.Exec(data.Name, data.Website, data.Message) if err != nil { log.Printf("Error occurred while saving data: %v\n") http.Redirect(w, r, errorRedirect, http.StatusSeeOther) return } http.Redirect(w, r, successRedirect, http.StatusSeeOther) }) log.Printf("Guestbook %s listening to POST %s on PORT %s.\n", guestbookName, path, port) log.Fatal(http.ListenAndServe(":" + port, nil)) }, } func init() { rootCmd.AddCommand(serveCmd) serveCmd.Flags().StringP("guestbook", "g", "my_guestbook", "Guestbook name (defined in /etc/guestbook.toml)") }