views package, add, update in userStore, user model rules, add todo.md

This commit is contained in:
Ruidy Nemausat 2020-03-16 14:32:34 +01:00
parent 9044e6ed21
commit ffa87e8131
17 changed files with 202 additions and 128 deletions

3
TODO.md Normal file
View file

@ -0,0 +1,3 @@
# TO DO
- [x] The mail field is case sensitive. Convert mail to lowercase before they are sent to InsertUser

View file

@ -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)

View file

@ -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)
}
}

59
data/psql.go Normal file
View file

@ -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)
}

View file

@ -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
`
)

34
data/userQueries.go Normal file
View file

@ -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;
`
)

58
data/userStore.go Normal file
View file

@ -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
}

View file

@ -8,7 +8,7 @@ import (
)
func main() {
data.Connect()
data.UsePSQL()
// startServer(settings.Port, controller.Router)
}

View file

@ -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
}

27
views/render.go Normal file
View file

@ -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
// }

View file

@ -0,0 +1 @@
<h1>Hi there, I love {{.Title}}</h1>