From ffa87e8131ec4794cc69ab1768cd3f80d2037383 Mon Sep 17 00:00:00 2001 From: Ruidy Nemausat Date: Mon, 16 Mar 2020 14:32:34 +0100 Subject: [PATCH] views package, add, update in userStore, user model rules, add todo.md --- TODO.md | 3 + controller/router.go | 33 ++------- data/database.go | 70 ------------------- data/psql.go | 59 ++++++++++++++++ data/queries.go | 21 ------ data/userQueries.go | 34 +++++++++ data/userStore.go | 58 +++++++++++++++ main.go | 2 +- model/user.go | 22 +++--- views/render.go | 27 +++++++ {templates => views/templates}/base.html | 0 {templates => views/templates}/contact.html | 0 .../templates}/contact_sent.html | 0 {templates => views/templates}/edit.html | 0 {templates => views/templates}/home.html | 0 views/templates/love.html | 1 + {templates => views/templates}/view.html | 0 17 files changed, 202 insertions(+), 128 deletions(-) create mode 100644 TODO.md delete mode 100644 data/database.go create mode 100644 data/psql.go delete mode 100644 data/queries.go create mode 100644 data/userQueries.go create mode 100644 data/userStore.go create mode 100644 views/render.go rename {templates => views/templates}/base.html (100%) rename {templates => views/templates}/contact.html (100%) rename {templates => views/templates}/contact_sent.html (100%) rename {templates => views/templates}/edit.html (100%) rename {templates => views/templates}/home.html (100%) create mode 100644 views/templates/love.html rename {templates => views/templates}/view.html (100%) diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..119ea94 --- /dev/null +++ b/TODO.md @@ -0,0 +1,3 @@ +# TO DO + +- [x] The mail field is case sensitive. Convert mail to lowercase before they are sent to InsertUser diff --git a/controller/router.go b/controller/router.go index adc6428..2b88949 100644 --- a/controller/router.go +++ b/controller/router.go @@ -2,18 +2,15 @@ package controller import ( "fmt" - "html/template" "net/http" "regexp" "github.com/rjNemo/go-wiki/model" "github.com/rjNemo/go-wiki/service" - "github.com/rjNemo/go-wiki/settings" + "github.com/rjNemo/go-wiki/views" ) -// func ParseTemplates() *template.Template { -// return template.Must(template.ParseFiles("templates/edit.html", "templates/view.html")) // add slice of fileNAmes -// } +var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$") // Router dispatch the request to the corresponding route handlers. func Router() { @@ -27,7 +24,7 @@ func Router() { } func homeHandler(w http.ResponseWriter, r *http.Request) { - renderTemplate(w, "home", nil) + views.Template(w, "home", nil) } func viewHandler(w http.ResponseWriter, r *http.Request, title string) { @@ -36,7 +33,7 @@ func viewHandler(w http.ResponseWriter, r *http.Request, title string) { http.Redirect(w, r, "/edit/"+title, http.StatusFound) return } - renderTemplate(w, "view", p) + views.Template(w, "view", p) } func editHandler(w http.ResponseWriter, r *http.Request, title string) { @@ -44,7 +41,7 @@ func editHandler(w http.ResponseWriter, r *http.Request, title string) { if err != nil { p = model.NewPage(title, nil) } - renderTemplate(w, "edit", p) + views.Template(w, "edit", p) } func saveHandler(w http.ResponseWriter, r *http.Request, title string) { @@ -56,7 +53,7 @@ func saveHandler(w http.ResponseWriter, r *http.Request, title string) { } func contactHandler(w http.ResponseWriter, r *http.Request) { - renderTemplate(w, "contact", nil) + views.Template(w, "contact", nil) } func postContactHandler(w http.ResponseWriter, r *http.Request) { @@ -65,27 +62,13 @@ func postContactHandler(w http.ResponseWriter, r *http.Request) { mail := parseContactForm(r) mail.Send() fmt.Println(mail) - renderTemplate(w, "contact_sent", nil) + views.Template(w, "contact_sent", nil) } func parseContactForm(r *http.Request) service.Mail { return service.NewMail(r.PostFormValue("email"), r.PostFormValue("message")) } -// var templates = template.Must(template.ParseFiles("templates/edit.html", "templates/view.html")) // add slice of fileNAmes - -func renderTemplate(w http.ResponseWriter, tmpl string, p *model.Page) { - // err := templates.ExecuteTemplate(w, "templates/"+tmpl+".html", p) - t, err := template.ParseFiles(getTmplName("base"), getTmplName(tmpl)) - checkError(err, w) - err = t.Execute(w, p) - checkError(err, w) -} - -func getTmplName(tmpl string) string { - return settings.TmplDir + tmpl + ".html" -} - func checkError(err error, w http.ResponseWriter) { if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) @@ -93,8 +76,6 @@ func checkError(err error, w http.ResponseWriter) { } } -var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$") - func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { m := validPath.FindStringSubmatch(r.URL.Path) diff --git a/data/database.go b/data/database.go deleted file mode 100644 index 07edeb9..0000000 --- a/data/database.go +++ /dev/null @@ -1,70 +0,0 @@ -package data - -import ( - "database/sql" - "log" - - _ "github.com/lib/pq" // postgresql database package - "github.com/rjNemo/go-wiki/model" - "github.com/rjNemo/go-wiki/settings" -) - -// Connect read the connection parameters to establish a connection to the -// database. -func Connect() { - log.Print("Inside connect func") - connStr := settings.ConnStr - db, err := sql.Open("postgres", connStr) - log.Print("opened connect") - if err != nil { - log.Fatal(err) - } - defer db.Close() - - log.Print("try to ping") - err = db.Ping() - if err != nil { - log.Fatal(err) - } - - log.Println("Database successfully connected!") - - createTable(db) - u := model.TestUser() - insertUser(db, u) - log.Print(u) -} - -func sqlExec(db *sql.DB, s string) { - if _, err := db.Exec(s); err != nil { - log.Fatal(err) - return - } - log.Printf("Command successfully executed!: %s", s) -} - -func createTable(db *sql.DB) { - sqlExec(db, QueryCreateTable) - log.Print("Table successfully created!") -} - -func insertUser(db *sql.DB, u model.User) { - id := 0 - err := db.QueryRow(QueryInsertUser, u.Age(), u.Email(), u.FirstName(), u.LastName()).Scan(&id) - if err != nil { - log.Fatal(err) - } - // u.SetID(id) - log.Println("New User ID is:", id) -} - -func insertUsers(db *sql.DB) { - query := ` - INSERT INTO users (age, email, first_name, last_name) - VALUES ($1, $2, $3, $4)` - - _, err := db.Exec(query, 32, "ruidy.nemausat@gmail.com", "Ruidy", "Nemausat") - if err != nil { - log.Fatal(err) - } -} diff --git a/data/psql.go b/data/psql.go new file mode 100644 index 0000000..0ebfc4d --- /dev/null +++ b/data/psql.go @@ -0,0 +1,59 @@ +package data + +import ( + "database/sql" + "log" + + _ "github.com/lib/pq" // postgresql database package + "github.com/rjNemo/go-wiki/model" + "github.com/rjNemo/go-wiki/settings" +) + +// UsePSQL read the connection parameters to establish a connection to the +// database. +func UsePSQL() { + connStr := settings.ConnStr + db, err := sql.Open("postgres", connStr) + if err != nil { + log.Fatal(err) + } + defer db.Close() + + err = db.Ping() + if err != nil { + log.Fatal(err) + } + + log.Println("Database successfully connected!") + + createUserTable(db) + store := NewUserStore(db) + // u := model.TestUser() + // store.Add(u) + // log.Print(u) + u1 := model.NewUser(3, 19, "paul", "newman", "PdsN@FDKML.COM") + store.Update(16, u1) +} + +func sqlExec(db *sql.DB, s string) { + if _, err := db.Exec(s); err != nil { + log.Fatal(err) + return + } + log.Printf("Command successfully executed!: %s", s) +} + +func createUserTable(db *sql.DB) { + sqlExec(db, QueryCreateTable) + log.Print("Table successfully created!") +} + +// Store interface defines the methods any store must satisfy +type Store interface { + CreateTable() + Add(i interface{}) + Get() + Find(id int) + Update(id int, i interface{}) + Delete(id int) +} diff --git a/data/queries.go b/data/queries.go deleted file mode 100644 index b93659b..0000000 --- a/data/queries.go +++ /dev/null @@ -1,21 +0,0 @@ -package data - -const ( - // QueryCreateTable is the SQL command used to create the users table if it - // not exists. - QueryCreateTable = ` - CREATE TABLE IF NOT EXISTS users ( - id SERIAL PRIMARY KEY, - age INT, - first_name TEXT, - last_name TEXT, - email TEXT UNIQUE NOT NULL) - ` - // QueryInsertUser is the SQL command used to insert a user in the table. - // Returning the new ID. - QueryInsertUser = ` - INSERT INTO users (age, email, first_name, last_name) - VALUES ($1, $2, $3, $4) - RETURNING id - ` -) diff --git a/data/userQueries.go b/data/userQueries.go new file mode 100644 index 0000000..c2273c6 --- /dev/null +++ b/data/userQueries.go @@ -0,0 +1,34 @@ +package data + +const ( + // QueryCreateTable is the SQL command used to create the users table if it + // not exists. + QueryCreateTable = ` + CREATE TABLE IF NOT EXISTS users ( + id SERIAL PRIMARY KEY, + age INT, + first_name TEXT, + last_name TEXT, + email TEXT UNIQUE NOT NULL) + ` + // QueryInsert is the SQL command used to insert a user in the table. + // Returning the new ID. + QueryInsert = ` + INSERT INTO users (age, email, first_name, last_name) + VALUES ($1, $2, $3, $4) + RETURNING id + ` + + // QueryUpdate is the SQL command used to update a user in the database. + QueryUpdate = ` + UPDATE users + SET age = $2, email = $3, first_name = $4, last_name = $5 + WHERE id = $1; + ` + + // QueryDelete is the SQL command used to delete a user from the database. + QueryDelete = ` + DELETE FROM users + WHERE id = $1; + ` +) diff --git a/data/userStore.go b/data/userStore.go new file mode 100644 index 0000000..62f58f8 --- /dev/null +++ b/data/userStore.go @@ -0,0 +1,58 @@ +package data + +import ( + "database/sql" + "log" + + "github.com/rjNemo/go-wiki/model" +) + +// UserStore is used to perform user-related CRUD operations on the DB +type UserStore struct { + db *sql.DB +} + +// NewUserStore constructs a UserStore connected to the database. +func NewUserStore(db *sql.DB) UserStore { + return UserStore{db: db} +} + +// Add inserts a user in the database. +func (us UserStore) Add(u model.User) { + id := 0 + err := us.db.QueryRow(QueryInsert, u.Age(), u.Email(), u.FirstName(), u.LastName()).Scan(&id) + if err != nil { + log.Fatal(err) // too severe + } + log.Println("New User ID is:", id) +} + +// Update edits user identified by 'id' in the database +func (us UserStore) Update(id int, u model.User) { + res, err := us.db.Exec(QueryUpdate, id, u.Age(), u.Email(), u.FirstName(), u.LastName()) + if err != nil { + log.Fatal(err) // too severe + } + count, err := res.RowsAffected() + if err != nil { + log.Fatal(err) // too severe + } + if count == 0 { + log.Fatal("Update failed") // too severe + } +} + + +// Delete removes user identified by 'id' from the database +func (us UserStore) Delete(id int) { + res, err := us.db.Exec(QueryDelete, id) + if err != nil { + log.Fatal(err) // too severe + } + count, err := res.RowsAffected() + if err != nil { + log.Fatal(err) // too severe + } + if count == 0 { + log.Fatal("Update failed") // too severe + } \ No newline at end of file diff --git a/main.go b/main.go index 361027c..ecbcf49 100644 --- a/main.go +++ b/main.go @@ -8,7 +8,7 @@ import ( ) func main() { - data.Connect() + data.UsePSQL() // startServer(settings.Port, controller.Router) } diff --git a/model/user.go b/model/user.go index bede2b4..1dcb60c 100644 --- a/model/user.go +++ b/model/user.go @@ -1,5 +1,7 @@ package model +import "strings" + // User represent a go-wiki user. It encapsulate its unique identifier, first and // last names, email and age type User struct { @@ -16,7 +18,7 @@ func TestUser() User { id: 42, firstName: "John", lastName: "Doe", - email: "jddd@mail.com", + email: "jddddSZ@mail.com", age: 42, } } @@ -25,9 +27,9 @@ func TestUser() User { func NewUser(id, age int, first, last, email string) User { return User{ id: id, - firstName: first, - lastName: last, - email: email, + firstName: strings.Title(first), + lastName: strings.Title(last), + email: strings.ToLower(email), age: age, } } @@ -37,11 +39,6 @@ func (u User) ID() int { return u.id } -// // SetID is a setter -// func (u *User) SetID(id int) { -// u.id = id -// } - // FirstName is a getter func (u User) FirstName() string { return u.firstName @@ -57,7 +54,12 @@ func (u User) Email() string { return u.email } -// FirstName is a getter +// SetEmail is a setter +func (u *User) SetEmail(email string) { + u.email = strings.ToLower(email) +} + +// Age is a getter func (u User) Age() int { return u.age } diff --git a/views/render.go b/views/render.go new file mode 100644 index 0000000..a7dd4bc --- /dev/null +++ b/views/render.go @@ -0,0 +1,27 @@ +package views + +import ( + "net/http" + "text/template" + + "github.com/rjNemo/go-wiki/model" + "github.com/rjNemo/go-wiki/settings" +) + +func Template(w http.ResponseWriter, tmpl string, p *model.Page) { + // err := templates.ExecuteTemplate(w, "templates/"+tmpl+".html", p) + t, err := template.ParseFiles(getTmplName("base"), getTmplName(tmpl)) + checkError(err, w) + err = t.Execute(w, p) + checkError(err, w) +} + +func getTmplName(tmpl string) string { + return settings.TmplDir + tmpl + ".html" +} + +// var templates = template.Must(template.ParseFiles("templates/edit.html", "templates/view.html")) // add slice of fileNAmes + +// func ParseTemplates() *template.Template { +// return template.Must(template.ParseFiles("templates/edit.html", "templates/view.html")) // add slice of fileNAmes +// } diff --git a/templates/base.html b/views/templates/base.html similarity index 100% rename from templates/base.html rename to views/templates/base.html diff --git a/templates/contact.html b/views/templates/contact.html similarity index 100% rename from templates/contact.html rename to views/templates/contact.html diff --git a/templates/contact_sent.html b/views/templates/contact_sent.html similarity index 100% rename from templates/contact_sent.html rename to views/templates/contact_sent.html diff --git a/templates/edit.html b/views/templates/edit.html similarity index 100% rename from templates/edit.html rename to views/templates/edit.html diff --git a/templates/home.html b/views/templates/home.html similarity index 100% rename from templates/home.html rename to views/templates/home.html diff --git a/views/templates/love.html b/views/templates/love.html new file mode 100644 index 0000000..ddc349c --- /dev/null +++ b/views/templates/love.html @@ -0,0 +1 @@ +

Hi there, I love {{.Title}}

diff --git a/templates/view.html b/views/templates/view.html similarity index 100% rename from templates/view.html rename to views/templates/view.html