Skip to content

Commit

Permalink
prepare project to refactoring use cases (#25)
Browse files Browse the repository at this point in the history
refactoring use case layer
  • Loading branch information
arkanjoms committed Jan 29, 2022
1 parent d899ef1 commit c50b3e3
Show file tree
Hide file tree
Showing 73 changed files with 1,933 additions and 1,831 deletions.
13 changes: 13 additions & 0 deletions core/util/ExtractToken.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package util

import (
"net/http"
)

func ExtractToken(r *http.Request) (string, error) {
authorization := r.Header.Get("Authorization")
if len(authorization) > len("Bearer ") {
return authorization[7:], nil
}
return "", ErrBearerTokenExtract
}
53 changes: 53 additions & 0 deletions core/util/ExtractToken_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package util

import (
"fmt"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"net/http"
"strings"
"testing"
)

type ExtractTokenSuite struct {
suite.Suite
*require.Assertions
mockCtrl *gomock.Controller
}

func TestExtractToken(t *testing.T) {
suite.Run(t, new(ExtractTokenSuite))
}

func (s *ExtractTokenSuite) SetupTest() {
s.Assertions = require.New(s.T())
s.mockCtrl = gomock.NewController(s.T())
}

func (s *ExtractTokenSuite) TearDownTest() {
s.mockCtrl.Finish()
}
func (s ExtractTokenSuite) TestExtractTokenOk() {
tk := "aeyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZmlyc3ROYW1lIjoiQWRtaW4iLCJsYXN0TmFtZSI6IkFkbWluIiwiYXV0aG9yaXRpZXMiOlsiQURNSU4iLCJVU0VSIl0sImV4cCI6MTYyNTExMDI4MH0.aXZnvA7IGvVbXcv3xYWv2ApCzb4mSfCElDS2-8I0Eoey2yZjTXun7ToKZEp3ANUSNsAp0Cc2T-NwsvXw-28ZzJG6OW1BmZ8in6DGk5c82zWEuokt_oqF496jZC4doeomop39dO-ETgpD1j63M6jzwz0joecbvCg_rixYdtN52Ix6ekIFMae6mvElD68wLTIlJLp6ld58on_jyHV3o5K13SUhP8SHkFJzUfgVaJxLGFRAa8qeOPJakTDsIqigbOUQVw3RdNGVpCGwCj86G9NWhcz0SdMsOMLsnLAhqUSOf6sqyagt3-mvquD_ehv4KDdx8g1wLzsz62bwJUzl85PdJQ"
reader := strings.NewReader("")
req, err := http.NewRequest(http.MethodPost, "/check_token", reader)
s.NoError(err)
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tk))
extracted, err := ExtractToken(req)
s.NoError(err)
s.NotEmpty(extracted)
s.Equal(tk, extracted)
}

func (s ExtractTokenSuite) TestExtractTokenNotOk() {
reader := strings.NewReader("")
req, err := http.NewRequest(http.MethodPost, "/check_token", reader)
if err != nil {
s.T().Fatal("error when creating request: %w", err)
}
extracted, err := ExtractToken(req)
s.Error(err)
s.Empty(extracted)
s.ErrorAs(err, &ErrBearerTokenExtract)
}
77 changes: 77 additions & 0 deletions core/util/GenerateJwtToken.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//go:generate mockgen -source GenerateJwtToken.go -destination mock/GenerateJwtToken_mock.go -package mock
package util

import (
"crypto/rand"
"crypto/rsa"
"errors"
"fmt"
"github.com/cristalhq/jwt/v3"
"github.com/golauth/golauth/domain/entity"
"github.com/golauth/golauth/infra/api/controller/model"
"time"
)

var (
ErrBearerTokenExtract = errors.New("bearer token extract error")
errSignerGenerate = errors.New("could not generate signer from private key")
errVerifierGenerate = errors.New("could not generate verifier from public key")
keyAlgorithm = jwt.RS512
TokenExpirationTime = 60
)

type GenerateJwtToken interface {
Execute(user *entity.User, authorities []string) (string, error)
}

func NewGenerateJwtToken(key *rsa.PrivateKey) GenerateJwtToken {
return generateJwtToken{signer: GenerateSigner(key)}
}

type generateJwtToken struct {
signer jwt.Signer
}

func (uc generateJwtToken) Execute(user *entity.User, authorities []string) (string, error) {
expirationTime := time.Now().Add(time.Duration(TokenExpirationTime) * time.Minute)
claims := &model.Claims{
Username: user.Username,
FirstName: user.FirstName,
LastName: user.LastName,
Authorities: authorities,
StandardClaims: jwt.StandardClaims{
ExpiresAt: jwt.NewNumericDate(expirationTime),
},
}
builder := jwt.NewBuilder(uc.signer)
tk, err := builder.Build(claims)
if err != nil {
return "", fmt.Errorf("could not build token with claims: %w", err)
}

return tk.String(), nil
}

func GenerateSigner(key *rsa.PrivateKey) jwt.Signer {
signer, err := jwt.NewSignerRS(keyAlgorithm, key)
if err != nil {
panic(errSignerGenerate)
}
return signer
}

func GeneratePrivateKey() *rsa.PrivateKey {
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(fmt.Errorf("could not generate private key: %w", err))
}
return privateKey
}

func GenerateVerifier(key *rsa.PrivateKey) jwt.Verifier {
verifier, err := jwt.NewVerifierRS(keyAlgorithm, &key.PublicKey)
if err != nil {
panic(errVerifierGenerate)
}
return verifier
}
5 changes: 5 additions & 0 deletions domain/entity/Token.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package entity

type Token struct {
AccessToken string
}
8 changes: 8 additions & 0 deletions domain/entity/role.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,11 @@ type Role struct {
Enabled bool
CreationDate time.Time
}

func NewRole(name string, description string) *Role {
return &Role{
Name: name,
Description: description,
Enabled: true,
}
}
13 changes: 13 additions & 0 deletions domain/factory/RepositoryFactory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//go:generate mockgen -source RepositoryFactory.go -destination mock/RepositoryFactory_mock.go -package mock
package factory

import (
"github.com/golauth/golauth/domain/repository"
)

type RepositoryFactory interface {
NewRoleRepository() repository.RoleRepository
NewUserAuthorityRepository() repository.UserAuthorityRepository
NewUserRepository() repository.UserRepository
NewUserRoleRepository() repository.UserRoleRepository
}
11 changes: 6 additions & 5 deletions domain/repository/RoleRepository.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
package repository

import (
"context"
"github.com/golauth/golauth/domain/entity"
"github.com/google/uuid"
)

type RoleRepository interface {
FindByName(name string) (entity.Role, error)
Create(role entity.Role) (entity.Role, error)
Edit(role entity.Role) error
ChangeStatus(id uuid.UUID, enabled bool) error
ExistsById(id uuid.UUID) (bool, error)
FindByName(ctx context.Context, name string) (*entity.Role, error)
Create(ctx context.Context, role *entity.Role) (*entity.Role, error)
Edit(ctx context.Context, role *entity.Role) error
ChangeStatus(ctx context.Context, id uuid.UUID, enabled bool) error
ExistsById(ctx context.Context, id uuid.UUID) (bool, error)
}
7 changes: 5 additions & 2 deletions domain/repository/UserAuthorityRepository.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
//go:generate mockgen -source UserAuthorityRepository.go -destination mock/UserAuthorityRepository_mock.go -package mock
package repository

import "github.com/google/uuid"
import (
"context"
"github.com/google/uuid"
)

type UserAuthorityRepository interface {
FindAuthoritiesByUserID(userId uuid.UUID) ([]string, error)
FindAuthoritiesByUserID(ctx context.Context, userId uuid.UUID) ([]string, error)
}
7 changes: 4 additions & 3 deletions domain/repository/UserRepository.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
package repository

import (
"context"
"github.com/golauth/golauth/domain/entity"
"github.com/google/uuid"
)

type UserRepository interface {
FindByUsername(username string) (entity.User, error)
FindByID(id uuid.UUID) (entity.User, error)
Create(user entity.User) (entity.User, error)
FindByUsername(ctx context.Context, username string) (*entity.User, error)
FindByID(ctx context.Context, id uuid.UUID) (*entity.User, error)
Create(ctx context.Context, user *entity.User) (*entity.User, error)
}
7 changes: 5 additions & 2 deletions domain/repository/UserRoleRepository.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
//go:generate mockgen -source UserRoleRepository.go -destination mock/UserRoleRepository_mock.go -package mock
package repository

import "github.com/google/uuid"
import (
"context"
"github.com/google/uuid"
)

type UserRoleRepository interface {
AddUserRole(userId uuid.UUID, roleId uuid.UUID) error
AddUserRole(ctx context.Context, userId uuid.UUID, roleId uuid.UUID) error
}
29 changes: 29 additions & 0 deletions domain/usecase/role/AddRole.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//go:generate mockgen -source AddRole.go -destination mock/AddRole_mock.go -package mock
package role

import (
"context"
"github.com/golauth/golauth/domain/entity"
"github.com/golauth/golauth/domain/factory"
"github.com/golauth/golauth/domain/repository"
)

type AddRole interface {
Execute(ctx context.Context, input *entity.Role) (*entity.Role, error)
}

type addRole struct {
repo repository.RoleRepository
}

func NewAddRole(repoFactory factory.RepositoryFactory) *addRole {
return &addRole{repo: repoFactory.NewRoleRepository()}
}

func (uc addRole) Execute(ctx context.Context, input *entity.Role) (*entity.Role, error) {
role, err := uc.repo.Create(ctx, input)
if err != nil {
return nil, err
}
return role, nil
}
78 changes: 78 additions & 0 deletions domain/usecase/role/AddRole_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package role

import (
"context"
"fmt"
"github.com/golang/mock/gomock"
"github.com/golauth/golauth/domain/entity"
factoryMock "github.com/golauth/golauth/domain/factory/mock"
"github.com/golauth/golauth/domain/repository/mock"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"testing"
"time"
)

type AddRoleSuite struct {
suite.Suite
*require.Assertions
mockCtrl *gomock.Controller
rf *factoryMock.MockRepositoryFactory
repo *mock.MockRoleRepository
addRole *addRole
}

func TestAddRole(t *testing.T) {
suite.Run(t, new(AddRoleSuite))
}

func (s *AddRoleSuite) SetupTest() {
s.Assertions = require.New(s.T())
s.mockCtrl = gomock.NewController(s.T())
s.rf = factoryMock.NewMockRepositoryFactory(s.mockCtrl)
s.repo = mock.NewMockRoleRepository(s.mockCtrl)
s.rf.EXPECT().NewRoleRepository().Return(s.repo)
s.addRole = NewAddRole(s.rf)
}

func (s *AddRoleSuite) TearDownTest() {
s.mockCtrl.Finish()
}

func (s AddRoleSuite) TestCreateOk() {
input := entity.Role{
Name: "NEW_ROLE",
Description: "New Role",
Enabled: true,
}
savedEntity := entity.Role{
ID: uuid.New(),
Name: "NEW_ROLE",
Description: "New Role",
Enabled: true,
CreationDate: time.Now(),
}
s.repo.EXPECT().Create(gomock.Any(), gomock.Any()).Return(&savedEntity, nil).Times(1)
resp, err := s.addRole.Execute(context.Background(), &input)
s.NoError(err)
s.NotZero(resp)
s.Equal(savedEntity.ID, resp.ID)
s.Equal(savedEntity.Name, resp.Name)
s.Equal(savedEntity.Description, resp.Description)
s.Equal(savedEntity.Enabled, resp.Enabled)
s.Equal(savedEntity.CreationDate, resp.CreationDate)
}

func (s AddRoleSuite) TestCreateNotOk() {
errMessage := "could not create role"
input := &entity.Role{
Name: "NEW_ROLE",
Description: "New Role",
}
s.repo.EXPECT().Create(gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf(errMessage)).Times(1)
resp, err := s.addRole.Execute(context.Background(), input)
s.Error(err)
s.Zero(resp)
s.EqualError(err, errMessage)
}
32 changes: 32 additions & 0 deletions domain/usecase/role/ChangeRoleStatus.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//go:generate mockgen -source ChangeRoleStatus.go -destination mock/ChangeRoleStatus_mock.go -package mock
package role

import (
"context"
"fmt"
"github.com/golauth/golauth/domain/repository"
"github.com/google/uuid"
)

type ChangeRoleStatus interface {
Execute(ctx context.Context, id uuid.UUID, enabled bool) error
}

type changeRoleStatus struct {
repo repository.RoleRepository
}

func NewChangeRoleStatus(repo repository.RoleRepository) ChangeRoleStatus {
return changeRoleStatus{repo: repo}
}

func (uc changeRoleStatus) Execute(ctx context.Context, id uuid.UUID, enabled bool) error {
exists, err := uc.repo.ExistsById(ctx, id)
if err != nil {
return err
}
if !exists {
return fmt.Errorf("role with id %s does not exists", id)
}
return uc.repo.ChangeStatus(ctx, id, enabled)
}
Loading

0 comments on commit c50b3e3

Please sign in to comment.