diff --git a/.gitignore b/.gitignore index 3814ec6..0ece221 100644 --- a/.gitignore +++ b/.gitignore @@ -256,4 +256,5 @@ paket-files/ src/api/public/index.html src/api/public/static src/api/appsettings.json -build/ \ No newline at end of file +build/ +src/*.exe \ No newline at end of file diff --git a/src/api/data/data.go b/src/api/data/data.go index bf03927..127e12a 100644 --- a/src/api/data/data.go +++ b/src/api/data/data.go @@ -7,6 +7,8 @@ import ( "log" "time" + // Register the PostgreSQL driver. + _ "github.com/lib/pq" "github.com/lucsky/cuid" ) @@ -21,6 +23,15 @@ const ( AND "lastStatus" <> 'Answered'` ) +// Settings holds the PostgreSQL configuration for myPrayerJournal. +type Settings struct { + Host string `json:"host"` + Port int `json:"port"` + User string `json:"user"` + Password string `json:"password"` + DbName string `json:"dbname"` +} + /* Data Access */ // Retrieve a basic request @@ -74,7 +85,7 @@ func AddHistory(db *sql.DB, userID, reqID, status, text string) int { } _, err := db.Exec(` INSERT INTO mpj.history - ("requestId", "asOf", "status", "text") + ("requestId", "asOf", "status", "text") VALUES ($1, $2, $3, NULLIF($4, ''))`, reqID, jsNow(), status, text) @@ -123,9 +134,9 @@ func AddNote(db *sql.DB, userID, reqID, note string) int { return 404 } _, err := db.Exec(` - INSERT INTO mpj.note - ("requestId", "asOf", "notes") - VALUES + INSERT INTO mpj.note + ("requestId", "asOf", "notes") + VALUES ($1, $2, $3)`, reqID, jsNow(), note) if err != nil { @@ -166,6 +177,24 @@ func ByID(db *sql.DB, userID, reqID string) (*JournalRequest, bool) { return &req, true } +// Connect establishes a connection to the database. +func Connect(s *Settings) (*sql.DB, bool) { + connStr := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", + s.Host, s.Port, s.User, s.Password, s.DbName) + db, err := sql.Open("postgres", connStr) + if err != nil { + log.Print(err) + return nil, false + } + err = db.Ping() + if err != nil { + log.Print(err) + return nil, false + } + log.Printf("Connected to postgres://%s@%s:%d/%s\n", s.User, s.Host, s.Port, s.DbName) + return db, true +} + // FullByID retrieves a journal request, including its full history and notes. func FullByID(db *sql.DB, userID, reqID string) (*JournalRequest, bool) { req, ok := ByID(db, userID, reqID) diff --git a/src/api/routes/routes.go b/src/api/routes/routes.go new file mode 100644 index 0000000..7a02cc1 --- /dev/null +++ b/src/api/routes/routes.go @@ -0,0 +1,64 @@ +// Package routes contains endpoint handlers for the myPrayerJournal API. +package routes + +import ( + "database/sql" + "encoding/json" + "log" + "net/http" + + "github.com/danieljsummers/myPrayerJournal/src/api/data" + "github.com/julienschmidt/httprouter" +) + +/* Support */ + +// Set the content type, the HTTP error code, and return the error message. +func sendError(w http.ResponseWriter, r *http.Request, err error) { + m := map[string]string{"error": err.Error()} + j, jErr := json.Marshal(m) + if jErr != nil { + log.Print("Error creating error JSON: " + jErr.Error()) + } + w.WriteHeader(500) + w.Header().Set("Content-Type", "application/json") + w.Write(j) +} + +// Set the content type and return the JSON to the user. +func sendJSON(w http.ResponseWriter, r *http.Request, result interface{}) { + payload, err := json.Marshal(result) + if err != nil { + sendError(w, r, err) + return + } + w.Header().Set("Content-Type", "application/json") + w.Write([]byte("{ data: ")) + w.Write(payload) + w.Write([]byte(" }")) +} + +/* Handlers */ + +func journal(w http.ResponseWriter, r *http.Request, _ httprouter.Params, db *sql.DB) { + reqs := data.Journal(db, "TODO: get user ID") + if reqs == nil { + reqs = []data.JournalRequest{} + } + sendJSON(w, r, reqs) +} + +/* Wrappers */ + +func withDB(fn func(w http.ResponseWriter, r *http.Request, p httprouter.Params, db *sql.DB), db *sql.DB) httprouter.Handle { + return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { + fn(w, r, p, db) + } +} + +// Routes returns a configured router to handle all incoming requests. +func Routes(db *sql.DB) *httprouter.Router { + router := httprouter.New() + router.GET("/journal", withDB(journal, db)) + return router +} diff --git a/src/my-prayer-journal.go b/src/my-prayer-journal.go index 8d2b152..4993504 100644 --- a/src/my-prayer-journal.go +++ b/src/my-prayer-journal.go @@ -2,10 +2,17 @@ package main import ( - "fmt" - "time" + "log" + + "github.com/danieljsummers/myPrayerJournal/src/api/data" + "github.com/danieljsummers/myPrayerJournal/src/api/routes" ) func main() { - fmt.Print(time.Now().UnixNano() / int64(1000000)) + db, ok := data.Connect(&data.Settings{}) + if !ok { + log.Fatal("Unable to connect to database; exiting") + } + router := routes.Routes(db) + _ = router // TODO: remove }