Skip to content

Commit

Permalink
add user CRUD
Browse files Browse the repository at this point in the history
  • Loading branch information
John-Lin committed Jul 24, 2018
1 parent 6069e60 commit ce01990
Show file tree
Hide file tree
Showing 5 changed files with 247 additions and 0 deletions.
32 changes: 32 additions & 0 deletions src/entity/user.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package entity

import (
"time"

"github.com/satori/go.uuid"
"gopkg.in/mgo.v2/bson"
)

// UserCollectionName's const
const (
UserCollectionName string = "users"
)

// User is the structure for user info
type User struct {
ID bson.ObjectId `bson:"_id,omitempty" json:"id" validate:"-"`
UUID uuid.UUID `bson:"uuid" json:"uuid" validate:"required,uuid4"`
JWT string `bson:"jwt" json:"jwt" validate:"-"`
UserName string `bson:"username" json:"username" validate:"required"`
Email string `bson:"email" json:"email" validate:"required,email"`
Password string `bson:"password" json:"password" validate:"required"`
FirstName string `bson:"firstname" json:"firstName" validate:"required"`
LastName string `bson:"lastName" json:"lastName" validate:"required"`
PhoneNumber string `bson:"phoneNumber" json:"phoneNumber" validate:"required,numeric"`
CreatedAt *time.Time `bson:"createdAt,omitempty" json:"createdAt,omitempty" validate:"-"`
}

// GetCollection - get model mongo collection name.
func (u User) GetCollection() string {
return UserCollectionName
}
163 changes: 163 additions & 0 deletions src/server/handler_user.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
package server

import (
"math"
"strconv"

"github.com/linkernetworks/utils/timeutils"
"github.com/linkernetworks/vortex/src/entity"
response "github.com/linkernetworks/vortex/src/net/http"
"github.com/linkernetworks/vortex/src/net/http/query"
"github.com/linkernetworks/vortex/src/web"

"github.com/satori/go.uuid"
mgo "gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)

func createUserHandler(ctx *web.Context) {
sp, req, resp := ctx.ServiceProvider, ctx.Request, ctx.Response

user := entity.User{}
if err := req.ReadEntity(&user); err != nil {
response.BadRequest(req.Request, resp.ResponseWriter, err)
return
}

uuid4, _ := uuid.NewV4()
user.UUID = uuid4
encryptedPassword, err := hashPassword(user.Password)
if err != nil {
response.InternalServerError(req.Request, resp.ResponseWriter, err)
return
}
user.Password = encryptedPassword

if err := sp.Validator.Struct(user); err != nil {
response.BadRequest(req.Request, resp.ResponseWriter, err)
return
}

session := sp.Mongo.NewSession()
defer session.Close()

user.ID = bson.NewObjectId()
user.CreatedAt = timeutils.Now()

if err := session.Insert(entity.UserCollectionName, &user); err != nil {
response.InternalServerError(req.Request, resp.ResponseWriter, err)
return
}

resp.WriteEntity(ActionResponse{
Error: false,
Message: "User Created Success",
})
}

func deleteUserHandler(ctx *web.Context) {
sp, req, resp := ctx.ServiceProvider, ctx.Request, ctx.Response

id := req.PathParameter("id")

session := sp.Mongo.NewSession()
defer session.Close()

user := entity.User{}
if err := session.FindOne(
entity.UserCollectionName,
bson.M{"_id": bson.ObjectIdHex(id)},
&user,
); err != nil {
response.BadRequest(req.Request, resp.ResponseWriter, err)
return
}

if err := session.Remove(entity.UserCollectionName, "_id", bson.ObjectIdHex(id)); err != nil {
switch err {
case mgo.ErrNotFound:
response.NotFound(req.Request, resp.ResponseWriter, err)
return
default:
response.InternalServerError(req.Request, resp.ResponseWriter, err)
return
}
}

resp.WriteEntity(ActionResponse{
Error: false,
Message: "User Deleted Success",
})
}

func listUserHandler(ctx *web.Context) {
sp, req, resp := ctx.ServiceProvider, ctx.Request, ctx.Response

var pageSize = 10
query := query.New(req.Request.URL.Query())

page, err := query.Int("page", 1)
if err != nil {
response.BadRequest(req.Request, resp.ResponseWriter, err)
return
}
pageSize, err = query.Int("page_size", pageSize)
if err != nil {
response.BadRequest(req.Request, resp.ResponseWriter, err)
return
}

session := sp.Mongo.NewSession()
defer session.Close()

users := []entity.User{}
var c = session.C(entity.UserCollectionName)
var q *mgo.Query

selector := bson.M{}
q = c.Find(selector).Sort("_id").Skip((page - 1) * pageSize).Limit(pageSize)

if err := q.All(&users); err != nil {
switch err {
case mgo.ErrNotFound:
response.NotFound(req.Request, resp.ResponseWriter, err)
return
default:
response.InternalServerError(req.Request, resp.ResponseWriter, err)
return
}
}

count, err := session.Count(entity.UserCollectionName, bson.M{})
if err != nil {
response.InternalServerError(req.Request, resp.ResponseWriter, err)
return
}
totalPages := int(math.Ceil(float64(count) / float64(pageSize)))
resp.AddHeader("X-Total-Count", strconv.Itoa(count))
resp.AddHeader("X-Total-Pages", strconv.Itoa(totalPages))
resp.WriteEntity(users)
}

func getUserHandler(ctx *web.Context) {
sp, req, resp := ctx.ServiceProvider, ctx.Request, ctx.Response

id := req.PathParameter("id")

session := sp.Mongo.NewSession()
defer session.Close()
c := session.C(entity.UserCollectionName)

user := entity.User{}
if err := c.FindId(bson.ObjectIdHex(id)).One(&user); err != nil {
switch err {
case mgo.ErrNotFound:
response.NotFound(req.Request, resp.ResponseWriter, err)
return
default:
response.InternalServerError(req.Request, resp.ResponseWriter, err)
return
}
}
resp.WriteEntity(user)
}
15 changes: 15 additions & 0 deletions src/server/password.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package server

import (
"golang.org/x/crypto/bcrypt"
)

func hashPassword(password string) (string, error) {
bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
return string(bytes), err
}

func checkPasswordHash(password, hash string) bool {
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
return err == nil
}
19 changes: 19 additions & 0 deletions src/server/password_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package server

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestHashPassword(t *testing.T) {
_, err := hashPassword("p@ssw0rd")
assert.NoError(t, err)
}

func TestCheckPasswordHash(t *testing.T) {
hashed, err := hashPassword("p@ssw0rd")
assert.NoError(t, err)
correct := checkPasswordHash("p@ssw0rd", hashed)
assert.True(t, true, correct)
}
18 changes: 18 additions & 0 deletions vendor/vendor.json
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,12 @@
"revision": "62f5e0662816a462697d29f396fd19376d17f65b",
"revisionTime": "2018-03-13T18:34:24Z"
},
{
"checksumSHA1": "eDQ6f1EsNf+frcRO/9XukSEchm8=",
"path": "github.com/satori/go.uuid",
"revision": "36e9d2ebbde5e3f13ab2e25625fd453271d6522e",
"revisionTime": "2018-01-03T17:44:51Z"
},
{
"checksumSHA1": "5fRTP+zI9WQqNzyHbi2qarMGauQ=",
"path": "github.com/sirupsen/logrus",
Expand Down Expand Up @@ -578,6 +584,18 @@
"revision": "a8fb68e7206f8c78be19b432c58eb52a6aa34462",
"revisionTime": "2018-06-11T18:48:21Z"
},
{
"checksumSHA1": "oCH3J96RWvO8W4xjix47PModpio=",
"path": "golang.org/x/crypto/bcrypt",
"revision": "c126467f60eb25f8f27e5a981f32a87e3965053f",
"revisionTime": "2018-07-23T15:26:11Z"
},
{
"checksumSHA1": "oVPHWesOmZ02vLq2fglGvf+AMgk=",
"path": "golang.org/x/crypto/blowfish",
"revision": "c126467f60eb25f8f27e5a981f32a87e3965053f",
"revisionTime": "2018-07-23T15:26:11Z"
},
{
"checksumSHA1": "1MGpGDQqnUoRpv7VEcQrXOBydXE=",
"path": "golang.org/x/crypto/pbkdf2",
Expand Down

0 comments on commit ce01990

Please sign in to comment.