mirror of
https://github.com/rjNemo/go-wiki
synced 2026-06-12 13:36:38 +00:00
views package, add, update in userStore, user model rules, add todo.md
This commit is contained in:
parent
9044e6ed21
commit
ffa87e8131
17 changed files with 202 additions and 128 deletions
3
TODO.md
Normal file
3
TODO.md
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# TO DO
|
||||||
|
|
||||||
|
- [x] The mail field is case sensitive. Convert mail to lowercase before they are sent to InsertUser
|
||||||
|
|
@ -2,18 +2,15 @@ package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/rjNemo/go-wiki/model"
|
"github.com/rjNemo/go-wiki/model"
|
||||||
"github.com/rjNemo/go-wiki/service"
|
"github.com/rjNemo/go-wiki/service"
|
||||||
"github.com/rjNemo/go-wiki/settings"
|
"github.com/rjNemo/go-wiki/views"
|
||||||
)
|
)
|
||||||
|
|
||||||
// func ParseTemplates() *template.Template {
|
var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$")
|
||||||
// return template.Must(template.ParseFiles("templates/edit.html", "templates/view.html")) // add slice of fileNAmes
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Router dispatch the request to the corresponding route handlers.
|
// Router dispatch the request to the corresponding route handlers.
|
||||||
func Router() {
|
func Router() {
|
||||||
|
|
@ -27,7 +24,7 @@ func Router() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func homeHandler(w http.ResponseWriter, r *http.Request) {
|
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) {
|
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)
|
http.Redirect(w, r, "/edit/"+title, http.StatusFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
renderTemplate(w, "view", p)
|
views.Template(w, "view", p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func editHandler(w http.ResponseWriter, r *http.Request, title string) {
|
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 {
|
if err != nil {
|
||||||
p = model.NewPage(title, 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) {
|
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) {
|
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) {
|
func postContactHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
@ -65,27 +62,13 @@ func postContactHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
mail := parseContactForm(r)
|
mail := parseContactForm(r)
|
||||||
mail.Send()
|
mail.Send()
|
||||||
fmt.Println(mail)
|
fmt.Println(mail)
|
||||||
renderTemplate(w, "contact_sent", nil)
|
views.Template(w, "contact_sent", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseContactForm(r *http.Request) service.Mail {
|
func parseContactForm(r *http.Request) service.Mail {
|
||||||
return service.NewMail(r.PostFormValue("email"), r.PostFormValue("message"))
|
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) {
|
func checkError(err error, w http.ResponseWriter) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
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 {
|
func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
m := validPath.FindStringSubmatch(r.URL.Path)
|
m := validPath.FindStringSubmatch(r.URL.Path)
|
||||||
|
|
|
||||||
|
|
@ -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
59
data/psql.go
Normal 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)
|
||||||
|
}
|
||||||
|
|
@ -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
34
data/userQueries.go
Normal 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
58
data/userStore.go
Normal 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
|
||||||
|
}
|
||||||
2
main.go
2
main.go
|
|
@ -8,7 +8,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
data.Connect()
|
data.UsePSQL()
|
||||||
// startServer(settings.Port, controller.Router)
|
// startServer(settings.Port, controller.Router)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
// User represent a go-wiki user. It encapsulate its unique identifier, first and
|
// User represent a go-wiki user. It encapsulate its unique identifier, first and
|
||||||
// last names, email and age
|
// last names, email and age
|
||||||
type User struct {
|
type User struct {
|
||||||
|
|
@ -16,7 +18,7 @@ func TestUser() User {
|
||||||
id: 42,
|
id: 42,
|
||||||
firstName: "John",
|
firstName: "John",
|
||||||
lastName: "Doe",
|
lastName: "Doe",
|
||||||
email: "jddd@mail.com",
|
email: "jddddSZ@mail.com",
|
||||||
age: 42,
|
age: 42,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -25,9 +27,9 @@ func TestUser() User {
|
||||||
func NewUser(id, age int, first, last, email string) User {
|
func NewUser(id, age int, first, last, email string) User {
|
||||||
return User{
|
return User{
|
||||||
id: id,
|
id: id,
|
||||||
firstName: first,
|
firstName: strings.Title(first),
|
||||||
lastName: last,
|
lastName: strings.Title(last),
|
||||||
email: email,
|
email: strings.ToLower(email),
|
||||||
age: age,
|
age: age,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -37,11 +39,6 @@ func (u User) ID() int {
|
||||||
return u.id
|
return u.id
|
||||||
}
|
}
|
||||||
|
|
||||||
// // SetID is a setter
|
|
||||||
// func (u *User) SetID(id int) {
|
|
||||||
// u.id = id
|
|
||||||
// }
|
|
||||||
|
|
||||||
// FirstName is a getter
|
// FirstName is a getter
|
||||||
func (u User) FirstName() string {
|
func (u User) FirstName() string {
|
||||||
return u.firstName
|
return u.firstName
|
||||||
|
|
@ -57,7 +54,12 @@ func (u User) Email() string {
|
||||||
return u.email
|
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 {
|
func (u User) Age() int {
|
||||||
return u.age
|
return u.age
|
||||||
}
|
}
|
||||||
|
|
|
||||||
27
views/render.go
Normal file
27
views/render.go
Normal 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
|
||||||
|
// }
|
||||||
1
views/templates/love.html
Normal file
1
views/templates/love.html
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<h1>Hi there, I love {{.Title}}</h1>
|
||||||
Loading…
Reference in a new issue