Refacotor: Added repository to cover UserRepository dependency
Some checks are pending
continuous-integration/drone/push Build is pending

This commit is contained in:
2025-10-24 10:25:38 +02:00
parent 5540e02644
commit e33f6a65df
15 changed files with 112 additions and 83 deletions

View File

@@ -9,17 +9,6 @@ import (
)
type (
Doer interface {
Start() error
RegisterHandler(string, func() any)
OnShutdown()
}
Application interface {
Start(while chan struct{})
RegisterPlugin(PluginFn) error
Shutdown()
}
App struct {
doer Doer
}

View File

@@ -9,38 +9,33 @@ import (
)
const (
defName = "identity-svc"
defDomain = "identity-svc"
defCacheAddr = "api-cache:6379"
defCacheUsername = "default"
defCachePassword = "12345678"
defDbURL = "postgres://postgres:12345678@db-postgres:5432/egommerce"
defNetAddr = ":443"
defMongoDbURL = "mongodb://mongodb:12345678@mongo-db:27017"
defPathPrefix = "/identity"
defEbEventsExchange = "api-events"
defEbEventsQueue = "identity-svc"
defName = "identity-svc"
defNetAddr = ":443"
defDomain = "identity-svc"
defCacheAddr = "api-cache:6379"
defCacheUsername = "default"
defCachePassword = "12345678"
defDbURL = "postgres://postgres:12345678@db-postgres:5432/egommerce"
defMongoDbURL = "mongodb://mongodb:12345678@db-mongo:27017"
// defEventBusExchange = "api-events"
// defEventBusQueue = "identity-svc"
)
type Config struct {
ID string
Name string
Domain string
NetAddr string
PathPrefix string
ID string
Name string
Domain string
NetAddr string
IdleTimeout time.Duration // miliseconds
ReadTimeout time.Duration // miliseconds
WriteTimeout time.Duration // miliseconds
DbURL string `json:"db_url"`
CacheAddr string `json:"cache_addr"`
CacheUsername string `json:"cache_username"`
CachePassword string `json:"cache_password"`
MongoDbUrl string `json:"mongodb_url"`
EventBusURL string `json:"eventbus_url"`
EventBusExchange string `json:"eventbus_exchange"`
EventBusQueue string `json:"eventbus_queue"`
DbURL string `json:"db_url"`
CacheAddr string `json:"cache_addr"`
CacheUsername string `json:"cache_username"`
CachePassword string `json:"cache_password"`
MongoDbUrl string `json:"mongodb_url"`
}
func NewConfig(name string) *Config {
@@ -54,7 +49,6 @@ func NewConfig(name string) *Config {
c.CacheUsername = cnf.GetEnv("API_CACHE_USERNAME", defCacheUsername)
c.CachePassword = cnf.GetEnv("API_CACHE_PASSWORD", defCachePassword)
c.DbURL = cnf.GetEnv("API_DATABASE_URL", defDbURL)
c.PathPrefix = cnf.GetEnv("APP_PATH_PREFIX", defPathPrefix)
return c
}
@@ -70,13 +64,10 @@ func (c *Config) GetArray() map[string]string { // FIXME fix types etc
arr["appFullname"] = c.GetAppFullName()
arr["domain"] = c.Domain
arr["netAddr"] = c.NetAddr
arr["pathPrefix"] = c.PathPrefix
arr["cacheAddr"] = c.CacheAddr
arr["cacheUsername"] = c.CacheUsername
arr["cachePassword"] = c.CachePassword
arr["dbURL"] = c.DbURL
arr["eventBusExchange"] = c.EventBusExchange
arr["eventBusURL"] = c.EventBusURL
return arr
}

14
src/common/interface.go Normal file
View File

@@ -0,0 +1,14 @@
package common
type (
Doer interface {
Start() error
RegisterHandler(string, func() any)
OnShutdown()
}
Application interface {
Start(while chan struct{})
RegisterPlugin(PluginFn) error
Shutdown()
}
)

View File

@@ -1,9 +1,12 @@
package common
import (
"log"
"os"
"time"
db "git.ego.freeddns.org/egommerce/go-api-pkg/database"
redis "github.com/go-redis/redis/v8"
)
@@ -34,11 +37,11 @@ func DatabasePlugin(cArr map[string]string) Plugin {
return Plugin{
name: "database",
fn: func() any {
dbConn, _ := db.Connect(cArr["dbURL"])
// if err != nil {
// log.Fatalf("Failed to connect to the Database: %s. Err: %v\n", cArr["dbURL"], err)
// os.Exit(1)
// }
dbConn, err := db.Connect(cArr["dbURL"])
if err != nil {
log.Fatalf("Failed to connect to the Database: %s. Err: %v\n", cArr["dbURL"], err)
os.Exit(1)
}
return dbConn
},

View File

@@ -5,8 +5,9 @@ go 1.24.0
toolchain go1.24.1
require (
git.ego.freeddns.org/egommerce/api-entities v0.3.20
git.ego.freeddns.org/egommerce/api-entities v0.3.34
git.ego.freeddns.org/egommerce/go-api-pkg v0.4.9
github.com/georgysavva/scany/v2 v2.1.4
github.com/go-pg/migrations/v8 v8.1.0
github.com/go-pg/pg/v10 v10.15.0
github.com/go-redis/redis/v8 v8.11.5

View File

@@ -1,6 +1,6 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
git.ego.freeddns.org/egommerce/api-entities v0.3.20 h1:CSxwbfsd2zYzwT985f3GaP6sTDXSwf3tq6GOQQ/MdHA=
git.ego.freeddns.org/egommerce/api-entities v0.3.20/go.mod h1:IqynARw+06GOm4eZGZuepmbi7bUxWBnOB4jd5cI7jf8=
git.ego.freeddns.org/egommerce/api-entities v0.3.34 h1:WftM9cvV3JmbS1DlHCIiV3tsYIpALj9IXo90mkgZNWQ=
git.ego.freeddns.org/egommerce/api-entities v0.3.34/go.mod h1:IqynARw+06GOm4eZGZuepmbi7bUxWBnOB4jd5cI7jf8=
git.ego.freeddns.org/egommerce/go-api-pkg v0.4.9 h1:Y9MisGDhl/ti4gsegl9MC7KoY2aHuyA0LvIESPoiPkE=
git.ego.freeddns.org/egommerce/go-api-pkg v0.4.9/go.mod h1:Q4onxocNdFhzD9QnQK3ubd68chbJPexjDraEHoIEN3Y=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
@@ -14,6 +14,8 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/clipperhouse/uax29/v2 v2.2.0 h1:ChwIKnQN3kcZteTXMgb1wztSgaU+ZemkgWdohwgs8tY=
github.com/clipperhouse/uax29/v2 v2.2.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
github.com/cockroachdb/cockroach-go/v2 v2.2.0 h1:/5znzg5n373N/3ESjHF5SMLxiW4RKB05Ql//KWfeTFs=
github.com/cockroachdb/cockroach-go/v2 v2.2.0/go.mod h1:u3MiKYGupPPjkn3ozknpMUpxPaNLTFWAya419/zv6eI=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -27,6 +29,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/georgysavva/scany/v2 v2.1.4 h1:nrzHEJ4oQVRoiKmocRqA1IyGOmM/GQOEsg9UjMR5Ip4=
github.com/georgysavva/scany/v2 v2.1.4/go.mod h1:fqp9yHZzM/PFVa3/rYEC57VmDx+KDch0LoqrJzkvtos=
github.com/go-pg/migrations/v8 v8.1.0 h1:bc1wQwFoWRKvLdluXCRFRkeaw9xDU4qJ63uCAagh66w=
github.com/go-pg/migrations/v8 v8.1.0/go.mod h1:o+CN1u572XHphEHZyK6tqyg2GDkRvL2bIoLNyGIewus=
github.com/go-pg/pg/v10 v10.4.0/go.mod h1:BfgPoQnD2wXNd986RYEHzikqv9iE875PrFaZ9vXvtNM=
@@ -40,6 +44,8 @@ github.com/gofiber/contrib/jwt v1.1.2 h1:GmWnOqT4A15EkA8IPXwSpvNUXZR4u5SMj+geBmy
github.com/gofiber/contrib/jwt v1.1.2/go.mod h1:CpIwrkUQ3Q6IP8y9n3f0wP9bOnSKx39EDp2fBVgMFVk=
github.com/gofiber/fiber/v2 v2.52.9 h1:YjKl5DOiyP3j0mO61u3NTmK7or8GzzWzCFzkboyP5cw=
github.com/gofiber/fiber/v2 v2.52.9/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
@@ -88,6 +94,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.10.0 h1:Zx5DJFEYQXio93kgXnQ09fXNiUKsqv4OUEu2UtGcB1E=
github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
@@ -111,6 +119,8 @@ github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDs
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -119,12 +129,14 @@ github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/f
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo=
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=

View File

@@ -2,9 +2,11 @@ package repository
import entity "git.ego.freeddns.org/egommerce/api-entities/identity/entity"
type RepositoryInterface interface {
type UserRepositoryInterface interface {
FindAll() ([]entity.User, error)
FindByID(id string) (*entity.User, error)
Create(user *entity.User) (*entity.User, error)
FindByUsername(login string) (*entity.User, error)
Create(user *entity.User) (string, error)
Update(user *entity.User) (*entity.User, error)
Delete(id int64) (bool, error)
}

View File

@@ -6,6 +6,7 @@ import (
"fmt"
entity "git.ego.freeddns.org/egommerce/api-entities/identity/entity"
"git.ego.freeddns.org/egommerce/go-api-pkg/database"
"github.com/jackc/pgx/v5/pgxpool"
@@ -86,6 +87,7 @@ func (r *URLAccessRepository) FindByURLAndServiceForRole(url, service, role stri
err := r.db.QueryRow(context.Background(), sql, url, service).
Scan(&entity.ID, &entity.Roles, &entity.URL, &entity.Service)
if err != nil {
fmt.Println(sql, url, service, role)
if err = database.NoRowsInQuerySet(err); err != nil {
return nil, errors.New("no url found for: " + url + " and role: " + role)
}

View File

@@ -5,8 +5,10 @@ import (
"errors"
entity "git.ego.freeddns.org/egommerce/api-entities/identity/entity"
db "git.ego.freeddns.org/egommerce/go-api-pkg/database"
"github.com/georgysavva/scany/v2/pgxscan"
"github.com/jackc/pgx/v5/pgxpool"
)
@@ -18,17 +20,44 @@ func NewUserRepository(db *pgxpool.Pool) *UserRepository {
return &UserRepository{db}
}
func (r *UserRepository) FindByID(id string) (*entity.User, error) {
var user entity.User
func (r *UserRepository) FindAll() ([]entity.User, error) {
users := []entity.User{}
sql := `SELECT id, username, password, email, created_at FROM identity.users WHERE id=$1 LIMIT 1`
err := r.db.QueryRow(context.Background(), sql, id).
Scan(&user.ID, &user.Username, &user.Password, &user.Email, &user.CreatedAt)
sql := `SELECT id, username, password, email, created_at, updated_at FROM identity.users`
rows, err := r.db.Query(context.Background(), sql)
if err != nil {
return nil, err
}
if err := pgxscan.ScanAll(&users, rows); err != nil {
return nil, err
}
return users, nil
}
func (r *UserRepository) FindByID(id string) (*entity.User, error) {
user := new(entity.User)
sql := `SELECT id, username, password, email, created_at, updated_at FROM identity.users WHERE id=$1 LIMIT 1`
err := pgxscan.Get(context.Background(), r.db, user, sql, id)
if err != nil {
return nil, errors.New("failed to fetch user from DB: " + err.Error())
}
return &user, nil
return user, nil
}
func (r *UserRepository) FindByUsername(login string) (*entity.User, error) {
user := new(entity.User)
sql := `SELECT id, username, password, email, created_at, updated_at FROM identity.users WHERE username=$1 LIMIT 1`
err := pgxscan.Get(context.Background(), r.db, user, sql, login)
if err != nil {
return nil, errors.New("failed to fetch user from DB: " + err.Error())
}
return user, nil
}
func (r *UserRepository) Create(user *entity.User) (string, error) {
@@ -54,16 +83,3 @@ func (r *UserRepository) Update(user *entity.User) (*entity.User, error) {
func (r *UserRepository) Delete(id int64) (bool, error) {
return true, nil
}
func (r *UserRepository) FindByUsername(login string) (*entity.User, error) {
var user entity.User
sql := `SELECT id, username, password, email, created_at FROM identity.users WHERE username=$1 LIMIT 1`
err := r.db.QueryRow(context.Background(), sql, login).
Scan(&user.ID, &user.Username, &user.Password, &user.Email, &user.CreatedAt)
if err != nil {
return nil, errors.New("failed to fetch user from DB: " + err.Error())
}
return &user, nil
}

View File

@@ -2,6 +2,7 @@ package server
import (
dto "git.ego.freeddns.org/egommerce/api-entities/identity/dto"
"git.ego.freeddns.org/egommerce/identity-service/infra/repository"
"git.ego.freeddns.org/egommerce/identity-service/internal/service"
"git.ego.freeddns.org/egommerce/identity-service/internal/ui"

View File

@@ -15,13 +15,11 @@ func (s *Server) HealthHandler(c *fiber.Ctx) error {
// Only 404 indicate service as not-healthy
err := s.GetDatabase().Ping(context.Background())
if err != nil {
// fmt.Println("db unavailable", err)
return c.SendStatus(http.StatusNotFound)
}
err = s.GetCache().Ping(context.Background()).Err()
if err != nil {
// fmt.Println("cache unavailable", err)
return c.SendStatus(http.StatusNotFound)
}

View File

@@ -10,15 +10,15 @@ import (
)
func (s *Server) LoginHandlerFn(c *fiber.Ctx) error {
data := new(dto.AuthLoginRequestDTO)
if err := c.BodyParser(data); err != nil {
return s.Error(c, fiber.StatusBadRequest, "Error parsing input")
req := new(dto.AuthLoginRequestDTO)
if err := c.BodyParser(req); err != nil {
return s.Error(c, fiber.StatusBadRequest, "error parsing input")
}
userRepo := repository.NewUserRepository(s.GetDatabase())
authSrv := service.NewAuthService(userRepo, s.GetCache())
token, err := ui.NewLoginActionUI(authSrv).Execute(data)
token, err := ui.NewLoginActionUI(authSrv).Execute(req)
if err != nil { // TODO: handle other response status codes -- add struct to decorate error with code and message
return s.Error(c, fiber.StatusBadRequest, err.Error())
}

View File

@@ -51,8 +51,8 @@ func (s *Server) Start() error {
if err != nil {
log.Fatal(err)
}
tlsCnf := &tls.Config{Certificates: []tls.Certificate{crt}}
tlsCnf := &tls.Config{Certificates: []tls.Certificate{crt}}
ln, _ := net.Listen("tcp", s.addr)
ln = tls.NewListener(ln, tlsCnf)
@@ -68,6 +68,7 @@ func (s *Server) OnShutdown() {
s.GetDatabase().Close()
s.GetCache().Close()
s.Shutdown()
}

View File

@@ -29,11 +29,11 @@ func init() {
}
type AuthService struct {
userRepo *repository.UserRepository
userRepo repository.UserRepositoryInterface
cache *redis.Client
}
func NewAuthService(userRepo *repository.UserRepository, cache *redis.Client) *AuthService {
func NewAuthService(userRepo repository.UserRepositoryInterface, cache *redis.Client) *AuthService {
return &AuthService{
userRepo: userRepo,
cache: cache,

View File

@@ -2,6 +2,7 @@ package ui
import (
dto "git.ego.freeddns.org/egommerce/api-entities/identity/dto"
"git.ego.freeddns.org/egommerce/identity-service/internal/service"
)
@@ -10,12 +11,10 @@ type AccessActionUI struct {
}
func NewAccessActionUI(guard *service.GuardService) *AccessActionUI {
return &AccessActionUI{
guard: guard,
}
return &AccessActionUI{guard: guard}
}
func (ui *AccessActionUI) Execute(data *dto.AuthorizationHeaderDTO, url, srvName string) error {
func (ui *AccessActionUI) Execute(data *dto.AuthorizationHeaderDTO, url, srvName string) error { // TODO: rename to CheckAccess
err := ui.guard.CheckUserPermissions(data, url, srvName)
if err != nil {
return err