feat: add password and fix errors

This commit is contained in:
Elton Minetto
2020-06-29 13:38:13 -03:00
parent 328b4e428c
commit d4b9b713e4
12 changed files with 246 additions and 21 deletions
+22 -4
View File
@@ -29,7 +29,7 @@ curl -X "POST" "http://localhost:8080/v1/book" \
"title": "I Am Ozzy",
"author": "Ozzy Osbourne",
"pages": 294,
"quantity":1
"quantity":10
}'
```
### Search book
@@ -56,10 +56,9 @@ curl -X "POST" "http://localhost:8080/v1/user" \
-H 'Accept: application/json' \
-d $'{
"email": "ozzy@metal.net",
"fist_name": "Ozzy",
"first_name": "Ozzy",
"last_name": "Osbourne",
"password": "bateater666",
"quantity":1
"password": "bateater666"
}'
```
@@ -79,6 +78,25 @@ curl "http://localhost:8080/v1/user" \
-H 'Accept: application/json'
```
### Borrow a book
```
curl "http://localhost:8080/v1/loan/borrow/be8b1757-b043-4dbd-b873-63fa9ecd8bb1/282885d7-5d5e-4205-87eb-edc2b2ac5022" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json'
```
### Return a book
```
curl "http://localhost:8080/v1/loan/return/be8b1757-b043-4dbd-b873-63fa9ecd8bb1" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json'
```
## CMD
### Search for a book
+2
View File
@@ -1,6 +1,7 @@
package handler
import (
"fmt"
"net/http"
"github.com/eminetto/clean-architecture-go-v2/domain/entity/user"
@@ -56,6 +57,7 @@ func borrowBook(bService book.UseCase, uService user.UseCase, loanService loan.U
}
err = loanService.Borrow(u, b)
if err != nil {
fmt.Println(err)
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(errorMessage))
return
+3 -1
View File
@@ -9,6 +9,8 @@ import (
"strconv"
"time"
"github.com/eminetto/clean-architecture-go-v2/pkg/password"
"github.com/eminetto/clean-architecture-go-v2/domain/loan"
"github.com/eminetto/clean-architecture-go-v2/domain/entity/user"
@@ -39,7 +41,7 @@ func main() {
bookService := book.NewService(bookRepo)
userRepo := user.NewMySQLRepoRepository(db)
userService := user.NewService(userRepo)
userService := user.NewService(userRepo, password.NewService())
loanService := loan.NewService(userService, bookService)
+28 -7
View File
@@ -21,7 +21,7 @@ func NewMySQLRepoRepository(db *sql.DB) *MySQLRepo {
}
}
//Create an user
//Create a book
func (r *MySQLRepo) Create(e *Book) (entity.ID, error) {
stmt, err := r.db.Prepare(`
insert into book (id, title, author, pages, quantity, created_at)
@@ -47,17 +47,34 @@ func (r *MySQLRepo) Create(e *Book) (entity.ID, error) {
return e.ID, nil
}
//Get an user
//Get a book
func (r *MySQLRepo) Get(id entity.ID) (*Book, error) {
return nil, nil
stmt, err := r.db.Prepare(`select id, title, author, pages, quantity, created_at from book where id = ?`)
if err != nil {
return nil, err
}
var b Book
rows, err := stmt.Query(id)
if err != nil {
return nil, err
}
for rows.Next() {
err = rows.Scan(&b.ID, &b.Title, &b.Author, &b.Pages, &b.Quantity, &b.CreatedAt)
}
return &b, nil
}
//Update an user
//Update a book
func (r *MySQLRepo) Update(e *Book) error {
e.UpdatedAt = time.Now()
_, err := r.db.Exec("update book set title = ?, author = ?, pages = ?, quantity = ?, updated_at = ? where id = ?", e.Title, e.Author, e.Pages, e.Quantity, e.UpdatedAt.Format("2006-01-02"), e.ID)
if err != nil {
return err
}
return nil
}
//Search users
//Search books
func (r *MySQLRepo) Search(query string) ([]*Book, error) {
stmt, err := r.db.Prepare(`select id, title, author, pages, quantity, created_at from book where title like ?`)
if err != nil {
@@ -82,7 +99,7 @@ func (r *MySQLRepo) Search(query string) ([]*Book, error) {
return books, nil
}
//List users
//List books
func (r *MySQLRepo) List() ([]*Book, error) {
stmt, err := r.db.Prepare(`select id, title, author, pages, quantity, created_at from book`)
if err != nil {
@@ -107,7 +124,11 @@ func (r *MySQLRepo) List() ([]*Book, error) {
return books, nil
}
//Delete an user
//Delete a book
func (r *MySQLRepo) Delete(id entity.ID) error {
_, err := r.db.Exec("delete from book where id = ?", id)
if err != nil {
return err
}
return nil
}
+111 -4
View File
@@ -4,6 +4,8 @@ import (
"database/sql"
"time"
"github.com/eminetto/clean-architecture-go-v2/domain"
"github.com/eminetto/clean-architecture-go-v2/domain/entity"
)
@@ -47,26 +49,131 @@ func (r *MySQLRepo) Create(e *User) (entity.ID, error) {
//Get an user
func (r *MySQLRepo) Get(id entity.ID) (*User, error) {
return nil, nil
return getUser(id, r.db)
}
func getUser(id entity.ID, db *sql.DB) (*User, error) {
stmt, err := db.Prepare(`select id, email, first_name, last_name, created_at from user where id = ?`)
if err != nil {
return nil, err
}
var u User
rows, err := stmt.Query(id)
if err != nil {
return nil, err
}
for rows.Next() {
err = rows.Scan(&u.ID, &u.Email, &u.FirstName, &u.LastName, &u.CreatedAt)
}
stmt, err = db.Prepare(`select book_id from book_user where user_id = ?`)
if err != nil {
return nil, err
}
rows, err = stmt.Query(id)
if err != nil {
return nil, err
}
for rows.Next() {
var i entity.ID
err = rows.Scan(&i)
u.Books = append(u.Books, i)
}
return &u, nil
}
//Update an user
func (r *MySQLRepo) Update(e *User) error {
e.UpdatedAt = time.Now()
_, err := r.db.Exec("update user set email = ?, password = ?, first_name = ?, last_name = ?, updated_at = ? where id = ?", e.Email, e.Password, e.FirstName, e.LastName, e.UpdatedAt.Format("2006-01-02"), e.ID)
if err != nil {
return err
}
_, err = r.db.Exec("delete from book_user where user_id = ?", e.ID)
if err != nil {
return err
}
for _, b := range e.Books {
_, err := r.db.Exec("insert into book_user values(?,?,?)", e.ID, b, time.Now().Format("2006-01-02"))
if err != nil {
return err
}
}
return nil
}
//Search users
func (r *MySQLRepo) Search(query string) ([]*User, error) {
return nil, nil
stmt, err := r.db.Prepare(`select id from user where name like ?`)
if err != nil {
return nil, err
}
defer stmt.Close()
var ids []entity.ID
rows, err := stmt.Query()
if err != nil {
return nil, err
}
for rows.Next() {
var i entity.ID
err = rows.Scan(&i)
if err != nil {
return nil, err
}
ids = append(ids, i)
}
if len(ids) == 0 {
return nil, domain.ErrNotFound
}
var users []*User
for _, id := range ids {
u, err := getUser(id, r.db)
if err != nil {
return nil, err
}
users = append(users, u)
}
return users, nil
}
//List users
func (r *MySQLRepo) List() ([]*User, error) {
return nil, nil
stmt, err := r.db.Prepare(`select id from user`)
if err != nil {
return nil, err
}
defer stmt.Close()
var ids []entity.ID
rows, err := stmt.Query()
if err != nil {
return nil, err
}
for rows.Next() {
var i entity.ID
err = rows.Scan(&i)
if err != nil {
return nil, err
}
ids = append(ids, i)
}
if len(ids) == 0 {
return nil, domain.ErrNotFound
}
var users []*User
for _, id := range ids {
u, err := getUser(id, r.db)
if err != nil {
return nil, err
}
users = append(users, u)
}
return users, nil
}
//Delete an user
func (r *MySQLRepo) Delete(id entity.ID) error {
_, err := r.db.Exec("delete from user where id = ?", id)
if err != nil {
return err
}
return nil
}
+10 -1
View File
@@ -4,18 +4,22 @@ import (
"strings"
"time"
"github.com/eminetto/clean-architecture-go-v2/pkg/password"
"github.com/eminetto/clean-architecture-go-v2/domain/entity"
)
//Service service interface
type Service struct {
repo Repository
pwd password.UseCase
}
//NewService create new use case
func NewService(r Repository) *Service {
func NewService(r Repository, pwd password.UseCase) *Service {
return &Service{
repo: r,
pwd: pwd,
}
}
@@ -23,6 +27,11 @@ func NewService(r Repository) *Service {
func (s *Service) Create(e *User) (entity.ID, error) {
e.ID = entity.NewID()
e.CreatedAt = time.Now()
pwd, err := s.pwd.Generate(e.Password)
if err != nil {
return e.ID, err
}
e.Password = pwd
return s.repo.Create(e)
}
+6 -4
View File
@@ -3,6 +3,8 @@ package user
import (
"testing"
"github.com/eminetto/clean-architecture-go-v2/pkg/password"
"github.com/eminetto/clean-architecture-go-v2/domain"
"github.com/eminetto/clean-architecture-go-v2/domain/entity"
@@ -11,7 +13,7 @@ import (
func Test_Create(t *testing.T) {
repo := NewInmemRepository()
service := NewService(repo)
service := NewService(repo, password.NewFakeService())
u := NewFixtureUser()
id, err := service.Create(u)
assert.Nil(t, err)
@@ -22,7 +24,7 @@ func Test_Create(t *testing.T) {
func Test_SearchAndFind(t *testing.T) {
repo := NewInmemRepository()
service := NewService(repo)
service := NewService(repo, password.NewFakeService())
u1 := NewFixtureUser()
u2 := NewFixtureUser()
u2.FirstName = "Lemmy"
@@ -55,7 +57,7 @@ func Test_SearchAndFind(t *testing.T) {
func Test_Update(t *testing.T) {
repo := NewInmemRepository()
service := NewService(repo)
service := NewService(repo, password.NewFakeService())
u := NewFixtureUser()
id, err := service.Create(u)
assert.Nil(t, err)
@@ -72,7 +74,7 @@ func Test_Update(t *testing.T) {
func TestDelete(t *testing.T) {
repo := NewInmemRepository()
service := NewService(repo)
service := NewService(repo, password.NewFakeService())
u1 := NewFixtureUser()
u2 := NewFixtureUser()
u2ID, _ := service.Create(u2)
+1
View File
@@ -15,5 +15,6 @@ require (
github.com/juju/mgosession v0.0.0-20170206150231-9ae6df2882cd
github.com/prometheus/client_golang v1.7.1
github.com/stretchr/testify v1.6.1
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce
)
+1
View File
@@ -112,6 +112,7 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+24
View File
@@ -0,0 +1,24 @@
package password
import "errors"
//FakePassword password
type FakePassword struct{}
//NewFakeService create a new fake password
func NewFakeService() *FakePassword {
return &FakePassword{}
}
//Generate a new password
func (p *FakePassword) Generate(raw string) (string, error) {
return raw, nil
}
//Compare compare two passwords
func (p *FakePassword) Compare(p1, p2 string) error {
if p1 == p2 {
return nil
}
return errors.New("Invalid password")
}
+7
View File
@@ -0,0 +1,7 @@
package password
//UseCase interface
type UseCase interface {
Generate(raw string) (string, error)
Compare(p1, p2 string) error
}
+31
View File
@@ -0,0 +1,31 @@
package password
import (
"golang.org/x/crypto/bcrypt"
)
//Password password
type Password struct{}
//NewService create a new fake password
func NewService() *Password {
return &Password{}
}
//Generate a new password
func (p *Password) Generate(raw string) (string, error) {
hash, err := bcrypt.GenerateFromPassword([]byte(raw), 10)
if err != nil {
return "", err
}
return string(hash), nil
}
//Compare compare two passwords
func (p *Password) Compare(p1, p2 string) error {
err := bcrypt.CompareHashAndPassword([]byte(p1), []byte(p2))
if err != nil {
return err
}
return nil
}