- 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:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
11
helper/errmsg.go
Normal 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")
|
||||
)
|
||||
@@ -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)
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
4
main.go
4
main.go
@@ -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)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package helper
|
||||
package repohelper
|
||||
|
||||
import (
|
||||
"log"
|
||||
@@ -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
|
||||
}
|
||||
|
||||
76
repositories/mongodb/login_mongo_repo.go
Normal file
76
repositories/mongodb/login_mongo_repo.go
Normal 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
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user