- adding logic for authenticate repo on mongo

- move error message into separate file
- move choose repo function from helper to repo helper
- adding logic for remove existing test data if any for each test file
- remove change password and user activation from login interface
This commit is contained in:
rinosukmandityo
2020-02-07 19:54:41 +07:00
parent f0ef2591ed
commit f627bf2222
13 changed files with 128 additions and 41 deletions

View File

@@ -4,7 +4,7 @@ import (
"io/ioutil"
"net/http"
"github.com/rinosukmandityo/hexagonal-login/logic"
"github.com/rinosukmandityo/hexagonal-login/helper"
svc "github.com/rinosukmandityo/hexagonal-login/services"
"github.com/go-chi/chi"
@@ -30,7 +30,7 @@ func (u *userhandler) Get(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id")
user, e := u.userService.GetById(id)
if e != nil {
if errors.Cause(e) == logic.ErrUserNotFound {
if errors.Cause(e) == helper.ErrUserNotFound {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
return
}

View File

@@ -15,10 +15,10 @@ import (
"testing"
. "github.com/rinosukmandityo/hexagonal-login/api"
"github.com/rinosukmandityo/hexagonal-login/helper"
"github.com/rinosukmandityo/hexagonal-login/logic"
m "github.com/rinosukmandityo/hexagonal-login/models"
repo "github.com/rinosukmandityo/hexagonal-login/repositories"
rh "github.com/rinosukmandityo/hexagonal-login/repositories/helper"
"github.com/go-chi/chi"
)
@@ -74,7 +74,7 @@ func UserTestData() []m.User {
}
func init() {
userRepo = helper.ChooseRepo()
userRepo = rh.ChooseRepo()
userService := logic.NewUserService(userRepo)
handler := NewUserHandler(userService)
r = RegisterHandler(handler)
@@ -150,6 +150,16 @@ func InsertUser(t *testing.T) {
testdata := UserTestData()
wg := sync.WaitGroup{}
// Clean test data if any
for _, data := range testdata {
wg.Add(1)
go func(_data m.User) {
userService.Delete(&_data)
wg.Done()
}(data)
}
wg.Wait()
t.Run("Case 1: Save data", func(t *testing.T) {
for _, data := range testdata {
wg.Add(1)

11
helper/errmsg.go Normal file
View File

@@ -0,0 +1,11 @@
package helper
import (
"errors"
)
var (
ErrUserNotFound = errors.New("User Not Found")
ErrUserInvalid = errors.New("User Invalid")
ErrUserNameDuplicate = errors.New("User Name Already Exists")
)

View File

@@ -19,12 +19,3 @@ func NewLoginService(loginRepo repo.LoginRepository) svc.LoginService {
func (u *loginService) Authenticate(username, password string) (bool, *m.User, error) {
return u.loginRepo.Authenticate(username, password)
}
func (u *loginService) ChangePassword(user m.User, newpassword string) error {
return u.loginRepo.ChangePassword(user, newpassword)
}
func (u *loginService) UserActivation(activationkey string) error {
return u.loginRepo.UserActivation(activationkey)
}

View File

@@ -1,8 +1,7 @@
package logic
import (
"errors"
"github.com/rinosukmandityo/hexagonal-login/helper"
m "github.com/rinosukmandityo/hexagonal-login/models"
repo "github.com/rinosukmandityo/hexagonal-login/repositories"
svc "github.com/rinosukmandityo/hexagonal-login/services"
@@ -16,12 +15,6 @@ type userService struct {
userRepo repo.UserRepository
}
var (
ErrUserNotFound = errors.New("User Not Found")
ErrUserInvalid = errors.New("User Invalid")
ErrUserNameDuplicate = errors.New("User Name Already Exists")
)
func NewUserService(userRepo repo.UserRepository) svc.UserService {
return &userService{
userRepo,
@@ -38,20 +31,20 @@ func (u *userService) GetById(id string) (*m.User, error) {
}
func (u *userService) Store(user *m.User) error {
if e := validate.Validate(user); e != nil {
return errs.Wrap(ErrUserInvalid, "service.User.Store")
return errs.Wrap(helper.ErrUserInvalid, "service.User.Store")
}
if user.ID == "" {
user.ID = shortid.MustGenerate()
}
if isFound, _, _ := u.userRepo.GetByUsername(user.Username); isFound {
return errs.Wrap(ErrUserNameDuplicate, "service.User.Store")
return errs.Wrap(helper.ErrUserNameDuplicate, "service.User.Store")
}
return u.userRepo.Store(user)
}
func (u *userService) Update(user *m.User) error {
if e := validate.Validate(user); e != nil {
return errs.Wrap(ErrUserInvalid, "service.User.Update")
return errs.Wrap(helper.ErrUserInvalid, "service.User.Update")
}
if user.ID == "" {
user.ID = shortid.MustGenerate()
@@ -61,7 +54,7 @@ func (u *userService) Update(user *m.User) error {
}
func (u *userService) Delete(user *m.User) error {
if user.ID == "" {
return errs.Wrap(ErrUserNotFound, "service.User.Delete")
return errs.Wrap(helper.ErrUserNotFound, "service.User.Delete")
}
if e := u.userRepo.Delete(user); e != nil {
return e

View File

@@ -9,8 +9,8 @@ import (
"syscall"
h "github.com/rinosukmandityo/hexagonal-login/api"
"github.com/rinosukmandityo/hexagonal-login/helper"
"github.com/rinosukmandityo/hexagonal-login/logic"
rh "github.com/rinosukmandityo/hexagonal-login/repositories/helper"
)
/*
@@ -24,7 +24,7 @@ import (
*/
func main() {
userRepo := helper.ChooseRepo()
userRepo := rh.ChooseRepo()
userService := logic.NewUserService(userRepo)
handler := h.NewUserHandler(userService)

View File

@@ -1,4 +1,4 @@
package helper
package repohelper
import (
"log"

View File

@@ -6,6 +6,4 @@ import (
type LoginRepository interface {
Authenticate(username, password string) (bool, *m.User, error)
ChangePassword(user m.User, newpassword string) error
UserActivation(activationkey string) error
}

View File

@@ -0,0 +1,76 @@
package mongo
import (
"context"
"crypto/md5"
"fmt"
"io"
"time"
"github.com/rinosukmandityo/hexagonal-login/helper"
m "github.com/rinosukmandityo/hexagonal-login/models"
repo "github.com/rinosukmandityo/hexagonal-login/repositories"
"github.com/pkg/errors"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readpref"
)
type loginMongoRepository struct {
client *mongo.Client
database string
timeout time.Duration
}
func newLoginMongoClient(mongoURL string, mongoTimeout int) (*mongo.Client, error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(mongoTimeout)*time.Second)
defer cancel()
client, e := mongo.Connect(ctx, options.Client().ApplyURI(mongoURL))
if e != nil {
return nil, e
}
if e = client.Ping(ctx, readpref.Primary()); e != nil {
return nil, e
}
return client, e
}
func NewLoginMongoRepository(mongoURL, mongoDB string, mongoTimeout int) (repo.LoginRepository, error) {
repo := &loginMongoRepository{
timeout: time.Duration(mongoTimeout) * time.Second,
database: mongoDB,
}
client, e := newLoginMongoClient(mongoURL, mongoTimeout)
if e != nil {
return nil, errors.Wrap(e, "repository.NewLoginMongoRepository")
}
repo.client = client
return repo, nil
}
func (r *loginMongoRepository) Authenticate(username, password string) (bool, *m.User, error) {
ctx, cancel := context.WithTimeout(context.Background(), r.timeout)
defer cancel()
user := new(m.User)
c := r.client.Database(r.database).Collection(user.TableName())
if e := c.FindOne(ctx, bson.M{"$or": []bson.M{
{"Username": username},
{"Email": username},
}}).Decode(user); e != nil {
if e == mongo.ErrNoDocuments {
return false, nil, errors.Wrap(helper.ErrUserNotFound, "repository.Login.Authenticate")
}
return false, user, errors.Wrap(e, "repository.Login.Authenticate")
}
tPass := md5.New()
io.WriteString(tPass, password)
ePassword := fmt.Sprintf("%x", tPass.Sum(nil))
if ePassword != user.Password {
return false, user, errors.Wrap(errors.New("Password is incorrect"), "repository.Login.Authenticate")
}
return true, user, nil
}

View File

@@ -4,7 +4,7 @@ import (
"context"
"time"
"github.com/rinosukmandityo/hexagonal-login/logic"
"github.com/rinosukmandityo/hexagonal-login/helper"
m "github.com/rinosukmandityo/hexagonal-login/models"
repo "github.com/rinosukmandityo/hexagonal-login/repositories"
@@ -68,7 +68,7 @@ func (r *userMongoRepository) GetById(id string) (*m.User, error) {
c := r.client.Database(r.database).Collection(user.TableName())
if e := c.FindOne(ctx, bson.M{"_id": id}).Decode(user); e != nil {
if e == mongo.ErrNoDocuments {
return nil, errors.Wrap(logic.ErrUserNotFound, "repository.User.GetById")
return nil, errors.Wrap(helper.ErrUserNotFound, "repository.User.GetById")
}
return user, errors.Wrap(e, "repository.User.GetById")
}
@@ -82,7 +82,7 @@ func (r *userMongoRepository) GetByUsername(username string) (bool, *m.User, err
c := r.client.Database(r.database).Collection(user.TableName())
if e := c.FindOne(ctx, bson.M{"Username": username}).Decode(user); e != nil {
if e == mongo.ErrNoDocuments {
return false, nil, errors.Wrap(logic.ErrUserNotFound, "repository.User.GetById")
return false, nil, errors.Wrap(helper.ErrUserNotFound, "repository.User.GetById")
}
return false, user, errors.Wrap(e, "repository.User.GetById")
}
@@ -119,7 +119,7 @@ func (r *userMongoRepository) Delete(user *m.User) error {
ctx, cancel := context.WithTimeout(context.Background(), r.timeout)
defer cancel()
c := r.client.Database(r.database).Collection(new(m.User).TableName())
if res, e := c.DeleteOne(ctx, user); e != nil {
if res, e := c.DeleteOne(ctx, bson.M{"_id": user.ID}); e != nil {
return errors.Wrap(e, "repository.User.Delete")
} else {
if res.DeletedCount == 0 {

View File

@@ -4,7 +4,7 @@ import (
"fmt"
"strconv"
"github.com/rinosukmandityo/hexagonal-login/logic"
"github.com/rinosukmandityo/hexagonal-login/helper"
m "github.com/rinosukmandityo/hexagonal-login/models"
repo "github.com/rinosukmandityo/hexagonal-login/repositories"
@@ -59,7 +59,7 @@ func (r *userRedisRepository) GetById(id string) (*m.User, error) {
return user, errors.Wrap(e, "repository.Redis.GetById")
}
if len(data) == 0 {
return nil, errors.Wrap(logic.ErrUserNotFound, "repository.User.GetById")
return nil, errors.Wrap(helper.ErrUserNotFound, "repository.User.GetById")
}
user.ID = data["ID"]
user.Username = data["Username"]
@@ -78,7 +78,7 @@ func (r *userRedisRepository) GetByUsername(username string) (bool, *m.User, err
return false, user, errors.Wrap(e, "repository.Redis.GetById")
}
if len(data) == 0 {
return false, nil, errors.Wrap(logic.ErrUserNotFound, "repository.User.GetById")
return false, nil, errors.Wrap(helper.ErrUserNotFound, "repository.User.GetById")
}
user.ID = data["ID"]
user.Username = data["Username"]

View File

@@ -6,6 +6,4 @@ import (
type LoginService interface {
Authenticate(username, password string) (bool, *m.User, error)
ChangePassword(user m.User, newpassword string) error
UserActivation(activationkey string) error
}

View File

@@ -6,9 +6,9 @@ import (
"sync"
"testing"
"github.com/rinosukmandityo/hexagonal-login/helper"
"github.com/rinosukmandityo/hexagonal-login/logic"
m "github.com/rinosukmandityo/hexagonal-login/models"
rh "github.com/rinosukmandityo/hexagonal-login/repositories/helper"
. "github.com/rinosukmandityo/hexagonal-login/services"
)
@@ -61,7 +61,7 @@ func UserTestData() []m.User {
}
func init() {
userRepo := helper.ChooseRepo()
userRepo := rh.ChooseRepo()
userService = logic.NewUserService(userRepo)
}
@@ -76,6 +76,16 @@ func InsertUser(t *testing.T) {
testdata := UserTestData()
wg := sync.WaitGroup{}
// Clean test data if any
for _, data := range testdata {
wg.Add(1)
go func(_data m.User) {
userService.Delete(&_data)
wg.Done()
}(data)
}
wg.Wait()
t.Run("Case 1: Save data", func(t *testing.T) {
for _, data := range testdata {
wg.Add(1)