From 5a304f11ac33d33bc07952abcac6a1a01454fd0e Mon Sep 17 00:00:00 2001 From: Piotr Biernat Date: Mon, 27 Oct 2025 14:01:25 +0100 Subject: [PATCH] Big Refacotr -part1 --- .gitignore | 4 +- Dockerfile.builder | 7 +- Dockerfile.target | 4 +- Makefile | 8 +- deploy/.env.dist | 2 - deploy/image-build.sh | 6 +- deploy/image-push.sh | 2 +- src/app/app.go | 40 +++++ src/{common => app}/config.go | 34 ++-- src/app/dependencies.go | 19 ++ src/app/interface.go | 23 +++ src/app/plugins.go | 41 +++++ src/app/scheduler.go | 1 + src/app/server.go | 165 ++++++++++++++++++ src/cmd/chronos/main.go | 36 ---- src/cmd/scheduler/main.go | 36 ++++ src/cmd/server/main.go | 18 +- src/common/app.go | 53 ------ src/common/interface.go | 14 -- src/common/plugins.go | 49 ------ src/go.mod | 2 +- src/go.sum | 4 +- src/infra/repository/interface.go | 4 +- src/infra/repository/url_access_repository.go | 3 +- src/infra/repository/user_repository.go | 2 +- src/internal/chronos/chronos.go | 52 ------ .../scheduler}/cache_permissions_job.go | 6 +- src/internal/cli/scheduler/scheduler.go | 52 ++++++ src/internal/http/access_handler.go | 34 ++++ src/internal/http/health_handler.go | 33 ++++ src/internal/http/login_handler.go | 35 ++++ src/internal/http/refresh_handler.go | 35 ++++ src/internal/http/register_handler.go | 33 ++++ src/internal/server/access_handler.go | 28 --- src/internal/server/health_handler.go | 29 --- src/internal/server/login_handler.go | 27 --- src/internal/server/middlewares.go | 52 ------ src/internal/server/refresh_handler.go | 27 --- src/internal/server/register_handler.go | 25 --- src/internal/server/router.go | 27 --- src/internal/server/server.go | 95 ---------- src/internal/ui/access_action.go | 24 --- .../ui/check_user_permissions_action.go | 24 +++ src/internal/ui/login_action.go | 4 +- src/internal/ui/refresh_action.go | 4 +- src/internal/ui/register_action.go | 4 +- 46 files changed, 627 insertions(+), 600 deletions(-) create mode 100644 src/app/app.go rename src/{common => app}/config.go (75%) create mode 100644 src/app/dependencies.go create mode 100644 src/app/interface.go create mode 100644 src/app/plugins.go create mode 100644 src/app/scheduler.go create mode 100644 src/app/server.go delete mode 100644 src/cmd/chronos/main.go create mode 100644 src/cmd/scheduler/main.go delete mode 100644 src/common/app.go delete mode 100644 src/common/interface.go delete mode 100644 src/common/plugins.go delete mode 100644 src/internal/chronos/chronos.go rename src/internal/{chronos => cli/scheduler}/cache_permissions_job.go (88%) create mode 100644 src/internal/cli/scheduler/scheduler.go create mode 100644 src/internal/http/access_handler.go create mode 100644 src/internal/http/health_handler.go create mode 100644 src/internal/http/login_handler.go create mode 100644 src/internal/http/refresh_handler.go create mode 100644 src/internal/http/register_handler.go delete mode 100644 src/internal/server/access_handler.go delete mode 100644 src/internal/server/health_handler.go delete mode 100644 src/internal/server/login_handler.go delete mode 100644 src/internal/server/middlewares.go delete mode 100644 src/internal/server/refresh_handler.go delete mode 100644 src/internal/server/register_handler.go delete mode 100644 src/internal/server/router.go delete mode 100644 src/internal/server/server.go delete mode 100644 src/internal/ui/access_action.go create mode 100644 src/internal/ui/check_user_permissions_action.go diff --git a/.gitignore b/.gitignore index fd5b159..bd09b2f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,10 +2,8 @@ deploy/.env !deploy/.env.dist deploy/.env.* -deploy/app.run - deploy/server -deploy/chronos +deploy/scheduler !deploy/certs/.gitkeep deploy/certs/* diff --git a/Dockerfile.builder b/Dockerfile.builder index e1169f0..280ed7e 100644 --- a/Dockerfile.builder +++ b/Dockerfile.builder @@ -3,14 +3,13 @@ FROM golang:alpine ARG BIN_OUTPUT=/go/bin ARG GO_SERVER=cmd/server/main.go +ARG GO_CHRONOS=cmd/scheduler/main.go ARG GO_MIGRATE=cmd/migrate/main.go -ARG GO_CHRONOS=cmd/chronos/main.go WORKDIR /go/src/app COPY src/ ./ RUN export CGO_ENABLED=0 ; export GOOS=linux ; export GOARCH=amd64 && \ go build -ldflags="-w -s" -o "$BIN_OUTPUT/server" $GO_SERVER && \ - go build -ldflags="-w -s" -o "$BIN_OUTPUT/migrate" $GO_MIGRATE && \ - go build -ldflags="-w -s" -o "$BIN_OUTPUT/chronos" $GO_CHRONOS - \ No newline at end of file + go build -ldflags="-w -s" -o "$BIN_OUTPUT/scheduler" $GO_CHRONOS && \ + go build -ldflags="-w -s" -o "$BIN_OUTPUT/migrate" $GO_MIGRATE diff --git a/Dockerfile.target b/Dockerfile.target index 33df216..5e7978e 100644 --- a/Dockerfile.target +++ b/Dockerfile.target @@ -17,9 +17,11 @@ LABEL dev.egommerce.image.version=${SVC_VER} LABEL dev.egommerce.image.build_time=${BUILD_TIME} WORKDIR / + COPY --from=builder /go/bin/server /usr/local/bin/server COPY --from=builder /go/bin/migrate /usr/local/bin/migrate -COPY --from=builder /go/bin/chronos /usr/local/bin/chronos +COPY --from=builder /go/bin/scheduler /usr/local/bin/scheduler + COPY deploy/.env.docker /.env COPY ./bin/* /usr/local/bin/ diff --git a/Makefile b/Makefile index c4e95e2..04959f9 100644 --- a/Makefile +++ b/Makefile @@ -19,8 +19,8 @@ build-local-server: run-local-server: - cd deploy/ && ./server -build-local-chronos: - - go build -C ${SRC_DIR} -o ../deploy/chronos cmd/chronos/main.go +build-local-scheduler: + - go build -C ${SRC_DIR} -o ../deploy/scheduler cmd/scheduler/main.go -run-local-chronos: - - cd deploy/ && ./chronos +run-local-scheduler: + - cd deploy/ && ./scheduler diff --git a/deploy/.env.dist b/deploy/.env.dist index ae7b4d5..0376042 100644 --- a/deploy/.env.dist +++ b/deploy/.env.dist @@ -2,9 +2,7 @@ SERVER_ADDR=:443 APP_NAME=identity-svc APP_DOMAIN=identity.service.ego.io -APP_PATH_PREFIX=/identity -API_LOGGER_ADDR=api-logger:24224 API_DATABASE_URL=postgres://postgres:12345678@db-postgres:5432/egommerce API_CACHE_ADDR=api-cache:6379 API_CACHE_USERNAME=default diff --git a/deploy/image-build.sh b/deploy/image-build.sh index 874a9ce..548831b 100755 --- a/deploy/image-build.sh +++ b/deploy/image-build.sh @@ -10,7 +10,7 @@ TARGET=${1:-latest} [ ! -d "src/vendor" ] && sh -c "cd src; go mod vendor" -echo "Building tmp $IMAGE_PREFIX image..." +echo "Building target $IMAGE_PREFIX images..." docker build --rm -t $BUILDER_IMAGE -f Dockerfile.builder . if [ $TARGET = "latest" ] @@ -23,7 +23,7 @@ then --build-arg BUILD_TIME \ --rm --cache-from $SERVER_IMAGE:$TARGET \ -t $SERVER_IMAGE:$TARGET \ - -f Dockerfile.target . >/dev/null 2>&1 && echo "Successfully tagged $SERVER_IMAGE:$TARGET" + -f Dockerfile.target . > /dev/null 2>&1 && echo "Successfully tagged $SERVER_IMAGE:$TARGET" else # DEV docker build \ @@ -32,7 +32,7 @@ else --build-arg BUILDER_IMAGE=$BUILDER_IMAGE \ --build-arg BUILD_TIME \ --rm --no-cache -t $SERVER_IMAGE:$TARGET \ - -f Dockerfile.target . >/dev/null 2>&1 && echo "Successfully tagged $SERVER_IMAGE:$TARGET" + -f Dockerfile.target . > /dev/null 2>&1 && echo "Successfully tagged $SERVER_IMAGE:$TARGET" fi echo "Done." diff --git a/deploy/image-push.sh b/deploy/image-push.sh index 617395a..e9e76e7 100755 --- a/deploy/image-push.sh +++ b/deploy/image-push.sh @@ -11,4 +11,4 @@ echo $DOCKER_PASSWORD | docker login git.ego.freeddns.org -u $DOCKER_USERNAME -- docker push "$SERVER_IMAGE:$TARGET" # Restart container -curl -X POST http://127.0.0.1:9001/api/webhooks/64ea5d78-ae21-474c-ad4d-1d98f6b83acb +# TODO \ No newline at end of file diff --git a/src/app/app.go b/src/app/app.go new file mode 100644 index 0000000..1316dc8 --- /dev/null +++ b/src/app/app.go @@ -0,0 +1,40 @@ +package app + +import ( + "log" + "os" + "os/signal" + "syscall" +) + +type App struct { + worker Worker +} + +func NewApp(worker Worker) *App { + return &App{ + worker: worker, + } +} + +func (app *App) Start(while chan struct{}) error { + go func(while chan struct{}) { + sigint := make(chan os.Signal, 1) + signal.Notify(sigint, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) + <-sigint + + log.Println("Received signal:", sigint) + app.Shutdown() + close(while) + }(while) + + return app.worker.Start() +} + +func (app *App) Shutdown() { + app.worker.OnShutdown() +} + +func (app *App) RegisterPlugin(plugin Plugin) { + app.worker.addPlugin(plugin.name, plugin.fn) +} diff --git a/src/common/config.go b/src/app/config.go similarity index 75% rename from src/common/config.go rename to src/app/config.go index e8dbe80..e07d6da 100644 --- a/src/common/config.go +++ b/src/app/config.go @@ -1,4 +1,4 @@ -package common +package app import ( "fmt" @@ -53,21 +53,21 @@ func NewConfig(name string) *Config { return c } -func (c *Config) GetAppFullName() string { +// func (c *Config) GetArray() map[string]string { // FIXME fix types etc +// arr := make(map[string]string) +// arr["id"] = c.ID +// arr["name"] = c.Name +// arr["appFullname"] = c.getAppFullName() +// arr["domain"] = c.Domain +// arr["netAddr"] = c.NetAddr +// arr["cacheAddr"] = c.CacheAddr +// arr["cacheUsername"] = c.CacheUsername +// arr["cachePassword"] = c.CachePassword +// arr["dbURL"] = c.DbURL + +// return arr +// } + +func (c *Config) getAppFullName() string { return fmt.Sprintf("%s_%s", c.Name, c.ID) } - -func (c *Config) GetArray() map[string]string { // FIXME fix types etc - arr := make(map[string]string) - arr["id"] = c.ID - arr["name"] = c.Name - arr["appFullname"] = c.GetAppFullName() - arr["domain"] = c.Domain - arr["netAddr"] = c.NetAddr - arr["cacheAddr"] = c.CacheAddr - arr["cacheUsername"] = c.CacheUsername - arr["cachePassword"] = c.CachePassword - arr["dbURL"] = c.DbURL - - return arr -} diff --git a/src/app/dependencies.go b/src/app/dependencies.go new file mode 100644 index 0000000..48a7344 --- /dev/null +++ b/src/app/dependencies.go @@ -0,0 +1,19 @@ +package app + +import ( + "github.com/go-redis/redis/v8" + "github.com/jackc/pgx/v5/pgxpool" +) + +type Dependencies struct { + cache *redis.Client + db *pgxpool.Pool +} + +func (d *Dependencies) GetCache() *redis.Client { + return d.cache +} + +func (d *Dependencies) GetDatabase() *pgxpool.Pool { + return d.db +} diff --git a/src/app/interface.go b/src/app/interface.go new file mode 100644 index 0000000..1786f45 --- /dev/null +++ b/src/app/interface.go @@ -0,0 +1,23 @@ +package app + +type ( + Application interface { + Start() + RegisterPlugin(Plugin) + Shutdown() + } + + Worker interface { + Start() error + OnShutdown() + + addPlugin(name string, fn PluginFn) + } + + Plugin struct { + name string + fn PluginFn + } + + PluginFn func() any +) diff --git a/src/app/plugins.go b/src/app/plugins.go new file mode 100644 index 0000000..add159f --- /dev/null +++ b/src/app/plugins.go @@ -0,0 +1,41 @@ +package app + +import ( + "context" + "log" + "os" + "time" + + redis "github.com/go-redis/redis/v8" + db "github.com/jackc/pgx/v5/pgxpool" +) + +func CachePlugin(cnf *Config) Plugin { + return Plugin{ + name: "cache", + fn: func() any { + return redis.NewClient(&redis.Options{ + Addr: cnf.CacheAddr, + Username: cnf.CacheUsername, + Password: cnf.CachePassword, + DB: 0, // TODO + DialTimeout: 100 * time.Millisecond, // TODO + }) + }, + } +} + +func DatabasePlugin(cnf *Config) Plugin { + return Plugin{ + name: "database", + fn: func() any { + dbConn, err := db.New(context.Background(), cnf.DbURL) + if err != nil { + log.Fatalf("Failed to connect to the Database: %s. Err: %v\n", cnf.DbURL, err) + os.Exit(1) + } + + return dbConn + }, + } +} diff --git a/src/app/scheduler.go b/src/app/scheduler.go new file mode 100644 index 0000000..4879f7a --- /dev/null +++ b/src/app/scheduler.go @@ -0,0 +1 @@ +package app diff --git a/src/app/server.go b/src/app/server.go new file mode 100644 index 0000000..5d60efe --- /dev/null +++ b/src/app/server.go @@ -0,0 +1,165 @@ +package app + +import ( + "crypto/tls" + "log" + "net" + "time" + + "github.com/go-redis/redis/v8" + jwt "github.com/gofiber/contrib/jwt" + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/cors" + "github.com/google/uuid" + "github.com/jackc/pgx/v5/pgxpool" + + commonDTO "git.ego.freeddns.org/egommerce/api-entities/common/dto" + cnf "git.ego.freeddns.org/egommerce/go-api-pkg/config" + + "git.ego.freeddns.org/egommerce/identity-service/internal/http" +) + +var defaultCORS = cors.New( + cors.Config{ + // DEV CONFIG + AllowOrigins: "*", + AllowMethods: "GET, POST, PATCH, PUT, DELETE, OPTIONS", + AllowHeaders: "Accept, Authorization, Content-Type, Vary, X-Request-Id", + // PROD CONFIG + // AllowOrigins: "http://egommerce.io:3001", // client(reactjs) app url + // AllowCredentials: true, + // AllowMethods: "GET, POST, PATCH, PUT, DELETE", + }, +) + +type ( + Server struct { + *fiber.App + + ID string + addr string // e.g. "127.0.0.1:443" + plugins map[string]any + } + + // HeaderRequestID struct { + // RequestID string `reqHeader:"x-request-id"` + // } +) + +func NewServer(c *Config) *Server { + srv := &Server{ + ID: c.ID, + App: fiber.New(fiber.Config{ + AppName: c.ID, + ServerHeader: c.Name + ":" + c.ID, + ReadTimeout: c.ReadTimeout * time.Millisecond, + WriteTimeout: c.WriteTimeout * time.Millisecond, + IdleTimeout: c.IdleTimeout * time.Millisecond, + }), + addr: c.NetAddr, + plugins: make(map[string]any), + } + + return srv +} + +func (s *Server) Start() error { + s.setupMiddleware() + s.setupRouter() + + crt, err := tls.LoadX509KeyPair("certs/identity-svc.crt", "certs/identity-svc.key") + if err != nil { + log.Fatal(err) + } + + tlsCnf := &tls.Config{Certificates: []tls.Certificate{crt}} + ln, _ := net.Listen("tcp", s.addr) + ln = tls.NewListener(ln, tlsCnf) + + return s.Listener(ln) +} + +func (s *Server) OnShutdown() { + log.Printf("Server %s is going down...", s.ID) + + s.getDatabase().Close() + s.getCache().Close() + + s.Shutdown() +} + +func (s *Server) addPlugin(name string, fn PluginFn) { + s.plugins[name] = fn() +} + +// Plugin helper functions - using hardcoded keys because we rely on a specific implementation here... +func (s *Server) getCache() *redis.Client { + return (s.plugins["cache"]).(*redis.Client) +} + +func (s *Server) getDatabase() *pgxpool.Pool { + return (s.plugins["database"]).(*pgxpool.Pool) +} + +// func GetRequestID(c *fiber.Ctx) (string, error) { +// var hdr = new(HeaderRequestID) +// if err := c.ReqHeaderParser(hdr); err != nil { +// return "", err +// } + +// return hdr.RequestID, nil +// } + +func (s *Server) setupRouter() { + s.Options("*", defaultCORS) + s.Use(defaultCORS) + + s.Get("/health", http.HealthHandlerFn(s.getDatabase(), s.getCache())) + + s.Group("/v1"). + Post("/login", http.LoginHandlerFn(s.getDatabase(), s.getCache())). + Post("/refresh", http.RefreshHandlerFn(s.getDatabase(), s.getCache())). // add JWTProtected() and get token from Auth Bearer header not from the body? + Post("/register", http.RegisterHandlerFn(s.getDatabase(), s.getCache())). + Get("/access", JWTProtected(), http.AccessHandlerFn(s.getDatabase(), s.getCache())) +} + +func (s *Server) setupMiddleware() { + s.Use(LoggingMiddleware()) + s.Use(XRequestIDMiddleware()) +} + +func LoggingMiddleware() func(c *fiber.Ctx) error { + return func(c *fiber.Ctx) error { + log.Printf("Request: %s, remote: %s, via: %s", + c.Request().URI().String(), + c.Context().RemoteIP().String(), + string(c.Context().UserAgent()), + ) + + return c.Next() + } +} + +func XRequestIDMiddleware() func(c *fiber.Ctx) error { + return func(c *fiber.Ctx) error { + c.Set("X-Request-ID", uuid.New().String()) + + return c.Next() + } +} + +func JWTProtected() func(c *fiber.Ctx) error { + secret := []byte(cnf.GetEnv("JWT_ACCESS_TOKEN_SECRET_KEY", "FallbackAccessTokenSecret")) + + return jwt.New(jwt.Config{ + SigningKey: jwt.SigningKey{Key: secret}, + ContextKey: "jwt", + ErrorHandler: func(c *fiber.Ctx, err error) error { + return c.Status(fiber.StatusUnauthorized).JSON(commonDTO.ErrorResponseDTO{Error: "unauthorized"}) + }, + }) +} + +// func (s *Server) Error(c *fiber.Ctx, code int, msg string) error { +// return c.Status(code).JSON(dto.ErrorResponseDTO{Error: msg}) +// } diff --git a/src/cmd/chronos/main.go b/src/cmd/chronos/main.go deleted file mode 100644 index 295f628..0000000 --- a/src/cmd/chronos/main.go +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - "log" - "os" - - cnf "git.ego.freeddns.org/egommerce/go-api-pkg/config" - - "git.ego.freeddns.org/egommerce/identity-service/common" - "git.ego.freeddns.org/egommerce/identity-service/internal/chronos" -) - -func main() { - if cnf.ErrLoadingEnvs != nil { - log.Panicln(cnf.ErrLoadingEnvs) - } - - c := common.NewConfig("identity-cronjob") - cArr := c.GetArray() - - doer := chronos.New(c) - a := common.NewApp(doer) - a.RegisterPlugin(common.CachePlugin(cArr)) - a.RegisterPlugin(common.DatabasePlugin(cArr)) - - while := make(chan struct{}) - err := a.Start(while) - <-while - - if err != nil { - log.Fatalf("Failed to chronos. Reason: %v\n", err) - os.Exit(1) - } - - os.Exit(0) -} diff --git a/src/cmd/scheduler/main.go b/src/cmd/scheduler/main.go new file mode 100644 index 0000000..58740e4 --- /dev/null +++ b/src/cmd/scheduler/main.go @@ -0,0 +1,36 @@ +package main + +import ( + "log" + "os" + + cnf "git.ego.freeddns.org/egommerce/go-api-pkg/config" + + "git.ego.freeddns.org/egommerce/identity-service/app" + "git.ego.freeddns.org/egommerce/identity-service/internal/cli/scheduler" +) + +func main() { + if cnf.ErrLoadingEnvs != nil { + log.Panicln(cnf.ErrLoadingEnvs) + } + + c := app.NewConfig("identity-cronjob") + cArr := c.GetArray() + + doer := scheduler.New(c) + a := app.NewApp(doer) + a.RegisterPlugin(app.CachePlugin(cArr)) + a.RegisterPlugin(app.DatabasePlugin(cArr)) + + while := make(chan struct{}) + err := a.Start(while) + <-while + + if err != nil { + log.Fatalf("Failed to scheduler. Reason: %v\n", err) + os.Exit(1) + } + + os.Exit(0) +} diff --git a/src/cmd/server/main.go b/src/cmd/server/main.go index 1f36ac1..995a871 100644 --- a/src/cmd/server/main.go +++ b/src/cmd/server/main.go @@ -6,25 +6,23 @@ import ( cnf "git.ego.freeddns.org/egommerce/go-api-pkg/config" - "git.ego.freeddns.org/egommerce/identity-service/common" - "git.ego.freeddns.org/egommerce/identity-service/internal/server" + "git.ego.freeddns.org/egommerce/identity-service/app" ) func main() { if cnf.ErrLoadingEnvs != nil { - log.Panicln(cnf.ErrLoadingEnvs) + log.Panicln(cnf.ErrLoadingEnvs.Error()) } - c := common.NewConfig("identity-svc") - cArr := c.GetArray() + cnf := app.NewConfig("identity-svc") + worker := app.NewServer(cnf) - doer := server.New(c) - a := common.NewApp(doer) - a.RegisterPlugin(common.CachePlugin(cArr)) - a.RegisterPlugin(common.DatabasePlugin(cArr)) + srv := app.NewApp(worker) + srv.RegisterPlugin(app.CachePlugin(cnf)) + srv.RegisterPlugin(app.DatabasePlugin(cnf)) while := make(chan struct{}) - err := a.Start(while) + err := srv.Start(while) <-while if err != nil { diff --git a/src/common/app.go b/src/common/app.go deleted file mode 100644 index bcd92f1..0000000 --- a/src/common/app.go +++ /dev/null @@ -1,53 +0,0 @@ -package common - -import ( - "fmt" - "log" - "os" - "os/signal" - "syscall" -) - -type ( - App struct { - doer Doer - } -) - -func NewApp(d Doer) *App { - return &App{ - doer: d, - } -} - -func (a *App) Start(while chan struct{}) error { - go func() { - sigint := make(chan os.Signal, 1) - signal.Notify(sigint, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) - <-sigint - fmt.Println("Received signal:", sigint) - - a.Shutdown() - - close(while) - }() - - err := a.doer.Start() - if err != nil { - log.Fatalf("Failed to start app. Reason: %v\n", err) - close(while) - } - <-while - - return err -} - -func (a *App) RegisterPlugin(p Plugin) error { - a.doer.RegisterHandler(p.name, p.fn) - - return nil -} - -func (a *App) Shutdown() { - a.doer.OnShutdown() -} diff --git a/src/common/interface.go b/src/common/interface.go deleted file mode 100644 index 5aa349c..0000000 --- a/src/common/interface.go +++ /dev/null @@ -1,14 +0,0 @@ -package common - -type ( - Doer interface { - Start() error - RegisterHandler(string, func() any) - OnShutdown() - } - Application interface { - Start(while chan struct{}) - RegisterPlugin(PluginFn) error - Shutdown() - } -) diff --git a/src/common/plugins.go b/src/common/plugins.go deleted file mode 100644 index 9ad4c4c..0000000 --- a/src/common/plugins.go +++ /dev/null @@ -1,49 +0,0 @@ -package common - -import ( - "log" - "os" - "time" - - db "git.ego.freeddns.org/egommerce/go-api-pkg/database" - - redis "github.com/go-redis/redis/v8" -) - -type ( - Plugin struct { - name string - fn PluginFn - } - PluginFn func() any -) - -func CachePlugin(cArr map[string]string) Plugin { - return Plugin{ - name: "cache", - fn: func() any { - return redis.NewClient(&redis.Options{ - Addr: cArr["cacheAddr"], - Username: cArr["cacheUsername"], - Password: cArr["cachePassword"], - DB: 0, - DialTimeout: 100 * time.Millisecond, - }) - }, - } -} - -func DatabasePlugin(cArr map[string]string) Plugin { - return Plugin{ - name: "database", - fn: func() any { - 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 - }, - } -} diff --git a/src/go.mod b/src/go.mod index 453b8ad..a2a0e1e 100644 --- a/src/go.mod +++ b/src/go.mod @@ -6,7 +6,7 @@ toolchain go1.24.1 require ( git.ego.freeddns.org/egommerce/api-entities v0.3.34 - git.ego.freeddns.org/egommerce/go-api-pkg v0.4.9 + git.ego.freeddns.org/egommerce/go-api-pkg v0.5.2 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 diff --git a/src/go.sum b/src/go.sum index c42a828..f0dfbb8 100644 --- a/src/go.sum +++ b/src/go.sum @@ -1,8 +1,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 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= +git.ego.freeddns.org/egommerce/go-api-pkg v0.5.2 h1:szfCwZ8S1Yf3b6LwpBs0DZYQZMsVl4Fe6VU1ou4LTOE= +git.ego.freeddns.org/egommerce/go-api-pkg v0.5.2/go.mod h1:T3ia8iprzlTRznPVXYCgEzQb/1UvIcdn9FHabE58vy0= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/MicahParks/keyfunc/v2 v2.1.0 h1:6ZXKb9Rp6qp1bDbJefnG7cTH8yMN1IC/4nf+GVjO99k= github.com/MicahParks/keyfunc/v2 v2.1.0/go.mod h1:rW42fi+xgLJ2FRRXAfNx9ZA8WpD4OeE/yHVMteCkw9k= diff --git a/src/infra/repository/interface.go b/src/infra/repository/interface.go index 550e6b7..443f7e3 100644 --- a/src/infra/repository/interface.go +++ b/src/infra/repository/interface.go @@ -6,7 +6,7 @@ type UserRepositoryInterface interface { FindAll() ([]entity.User, error) FindByID(id string) (*entity.User, error) FindByUsername(login string) (*entity.User, error) - Create(user *entity.User) (string, error) - Update(user *entity.User) (*entity.User, error) + Create(user *entity.User) (string, error) // FIXME types + Update(user *entity.User) (*entity.User, error) // FIXME types Delete(id int64) (bool, error) } diff --git a/src/infra/repository/url_access_repository.go b/src/infra/repository/url_access_repository.go index cfef0eb..2f7f03c 100644 --- a/src/infra/repository/url_access_repository.go +++ b/src/infra/repository/url_access_repository.go @@ -7,7 +7,7 @@ import ( entity "git.ego.freeddns.org/egommerce/api-entities/identity/entity" - "git.ego.freeddns.org/egommerce/go-api-pkg/database" + database "git.ego.freeddns.org/egommerce/go-api-pkg/client/postgresql" "github.com/jackc/pgx/v5/pgxpool" ) @@ -87,7 +87,6 @@ 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) } diff --git a/src/infra/repository/user_repository.go b/src/infra/repository/user_repository.go index 942721d..ea3f356 100644 --- a/src/infra/repository/user_repository.go +++ b/src/infra/repository/user_repository.go @@ -6,7 +6,7 @@ import ( entity "git.ego.freeddns.org/egommerce/api-entities/identity/entity" - db "git.ego.freeddns.org/egommerce/go-api-pkg/database" + db "git.ego.freeddns.org/egommerce/go-api-pkg/client/postgresql" "github.com/georgysavva/scany/v2/pgxscan" "github.com/jackc/pgx/v5/pgxpool" diff --git a/src/internal/chronos/chronos.go b/src/internal/chronos/chronos.go deleted file mode 100644 index 6cd3c66..0000000 --- a/src/internal/chronos/chronos.go +++ /dev/null @@ -1,52 +0,0 @@ -package chronos - -import ( - "log" - "time" - - "git.ego.freeddns.org/egommerce/identity-service/common" - - "github.com/go-redis/redis/v8" - "github.com/jackc/pgx/v5/pgxpool" - "github.com/onatm/clockwerk" -) - -type Chronos struct { - handlers map[string]any -} - -func New(c *common.Config) *Chronos { - return &Chronos{ - handlers: make(map[string]any), - } -} - -func (c *Chronos) Start() error { - job := NewCachePermissionsJob(c) - sch := clockwerk.New() - sch.Every(30 * time.Minute).Do(job) - sch.Start() - - return nil -} - -func (c *Chronos) RegisterHandler(name string, fn func() any) { - c.handlers[name] = fn() -} - -func (c *Chronos) OnShutdown() { - log.Println("Chronos is going down...") - - c.GetDatabase().Close() - c.GetCache().Close() -} - -// Plugin helper funcitons - refactor needed cause funcs are duplcated in server.go -// TODO: move functions below to some common place -func (c *Chronos) GetCache() *redis.Client { - return (c.handlers["cache"]).(*redis.Client) -} - -func (c *Chronos) GetDatabase() *pgxpool.Pool { - return (c.handlers["database"]).(*pgxpool.Pool) -} diff --git a/src/internal/chronos/cache_permissions_job.go b/src/internal/cli/scheduler/cache_permissions_job.go similarity index 88% rename from src/internal/chronos/cache_permissions_job.go rename to src/internal/cli/scheduler/cache_permissions_job.go index 6331e3a..5d17609 100644 --- a/src/internal/chronos/cache_permissions_job.go +++ b/src/internal/cli/scheduler/cache_permissions_job.go @@ -1,4 +1,4 @@ -package chronos +package scheduler import ( "fmt" @@ -9,10 +9,10 @@ import ( ) type CachePermissionsJob struct { - sch *Chronos + sch *Scheduler } -func NewCachePermissionsJob(sch *Chronos) CachePermissionsJob { +func NewCachePermissionsJob(sch *Scheduler) CachePermissionsJob { return CachePermissionsJob{sch: sch} } diff --git a/src/internal/cli/scheduler/scheduler.go b/src/internal/cli/scheduler/scheduler.go new file mode 100644 index 0000000..66b39d2 --- /dev/null +++ b/src/internal/cli/scheduler/scheduler.go @@ -0,0 +1,52 @@ +package scheduler + +import ( // REFACTOR IT LIKE A SERVER WAS + "log" + "time" + + "git.ego.freeddns.org/egommerce/identity-service/app" + + // "github.com/go-redis/redis/v8" + // "github.com/jackc/pgx/v5/pgxpool" + "github.com/onatm/clockwerk" +) + +type Scheduler struct { + handlers map[string]any +} + +func New(c *app.Config) *Scheduler { + return &Scheduler{ + handlers: make(map[string]any), + } +} + +func (c *Scheduler) Start() error { + job := NewCachePermissionsJob(c) + sch := clockwerk.New() + sch.Every(30 * time.Minute).Do(job) + sch.Start() + + return nil +} + +// func (c *Scheduler) RegisterHandler(name string, fn func() any) { +// c.handlers[name] = fn() +// } + +func (c *Scheduler) OnShutdown() { + log.Println("Chronos is going down...") + + // c.GetDatabase().Close() + // c.GetCache().Close() +} + +// Plugin helper funcitons - refactor needed cause funcs are duplcated in server.go +// TODO: move functions below to some common place +// func (c *Scheduler) GetCache() *redis.Client { +// return (c.handlers["cache"]).(*redis.Client) +// } + +// func (c *Scheduler) GetDatabase() *pgxpool.Pool { +// return (c.handlers["database"]).(*pgxpool.Pool) +// } diff --git a/src/internal/http/access_handler.go b/src/internal/http/access_handler.go new file mode 100644 index 0000000..dea39b2 --- /dev/null +++ b/src/internal/http/access_handler.go @@ -0,0 +1,34 @@ +package http + +import ( + commonDTO "git.ego.freeddns.org/egommerce/api-entities/common/dto" + identityDTO "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" + + "github.com/go-redis/redis/v8" + "github.com/gofiber/fiber/v2" + "github.com/jackc/pgx/v5/pgxpool" +) + +func AccessHandlerFn(db *pgxpool.Pool, cache *redis.Client) fiber.Handler { + return func(c *fiber.Ctx) error { + userRepo := repository.NewUserRepository(db) + roleRepo := repository.NewRoleRepository(db) + urlRepo := repository.NewURLAccessRepository(db) + authSrv := service.NewAuthService(userRepo, cache) + guardSrv := service.NewGuardService(authSrv, cache, userRepo, roleRepo, urlRepo) + + url, srvName := c.Query("q"), c.Query("srv") + header := new(identityDTO.AuthorizationHeaderDTO) + c.ReqHeaderParser(header) + + if err := ui.NewAccessActionUI(guardSrv).Execute(header, url, srvName); err != nil { + return c.Status(fiber.StatusNotFound).JSON(&commonDTO.ErrorResponseDTO{Error: err.Error()}) + } + + return c.SendStatus(fiber.StatusNoContent) + } +} diff --git a/src/internal/http/health_handler.go b/src/internal/http/health_handler.go new file mode 100644 index 0000000..c9a2e95 --- /dev/null +++ b/src/internal/http/health_handler.go @@ -0,0 +1,33 @@ +package http + +import ( + "context" + "net/http" + + "github.com/go-redis/redis/v8" + "github.com/gofiber/fiber/v2" + "github.com/jackc/pgx/v5/pgxpool" +) + +type HealthResponse struct { + Status string `json:"status,omitempty"` +} + +func HealthHandlerFn(db *pgxpool.Pool, cache *redis.Client) fiber.Handler { + return func(c *fiber.Ctx) error { + // Only 404 indicate service as not-healthy + err := db.Ping(context.Background()) + if err != nil { + return c.SendStatus(http.StatusNotFound) + } + + err = cache.Ping(context.Background()).Err() + if err != nil { + return c.SendStatus(http.StatusNotFound) + } + + return c.JSON(&HealthResponse{ + Status: "OK", + }) + } +} diff --git a/src/internal/http/login_handler.go b/src/internal/http/login_handler.go new file mode 100644 index 0000000..9c83593 --- /dev/null +++ b/src/internal/http/login_handler.go @@ -0,0 +1,35 @@ +package http + +import ( + "github.com/go-redis/redis/v8" + "github.com/gofiber/fiber/v2" + "github.com/jackc/pgx/v5/pgxpool" + + commonDTO "git.ego.freeddns.org/egommerce/api-entities/common/dto" + identityDTO "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" +) + +func LoginHandlerFn(db *pgxpool.Pool, cache *redis.Client) fiber.Handler { + return func(c *fiber.Ctx) error { + req := new(identityDTO.AuthLoginRequestDTO) + if err := c.BodyParser(req); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(&commonDTO.ErrorResponseDTO{Error: "error parsing input"}) + // return srv.Error(c, fiber.StatusBadRequest, "error parsing input") + } + + userRepo := repository.NewUserRepository(db) + authSrv := service.NewAuthService(userRepo, cache) + + 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 c.Status(fiber.StatusBadRequest).JSON(commonDTO.ErrorResponseDTO{Error: err.Error()}) + // return srv.Error(c, fiber.StatusBadRequest, err.Error()) + } + + return c.JSON(&identityDTO.AuthLoginResponseDTO{Token: token}) + } +} diff --git a/src/internal/http/refresh_handler.go b/src/internal/http/refresh_handler.go new file mode 100644 index 0000000..91fd938 --- /dev/null +++ b/src/internal/http/refresh_handler.go @@ -0,0 +1,35 @@ +package http + +import ( + commonDTO "git.ego.freeddns.org/egommerce/api-entities/common/dto" + identityDTO "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" + + "github.com/go-redis/redis/v8" + "github.com/gofiber/fiber/v2" + "github.com/jackc/pgx/v5/pgxpool" +) + +func RefreshHandlerFn(db *pgxpool.Pool, cache *redis.Client) fiber.Handler { + return func(c *fiber.Ctx) error { + header := new(identityDTO.AuthorizationHeaderDTO) + if err := c.ReqHeaderParser(header); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(commonDTO.ErrorResponseDTO{Error: "Error parsing headers"}) + // return srv.Error(c, fiber.StatusBadRequest, "Error parsing headers") + } + + repo := repository.NewUserRepository(db) + authSrv := service.NewAuthService(repo, cache) + + token, err := ui.NewRefreshTokenActionUI(authSrv).Execute(header) + if err != nil { + return c.Status(fiber.StatusBadRequest).JSON(&commonDTO.ErrorResponseDTO{Error: err.Error()}) + // return srv.Error(c, fiber.StatusBadRequest, err.Error()) + } + + return c.JSON(&identityDTO.AuthRefreshTokenResponseDTO{Token: token}) + } +} diff --git a/src/internal/http/register_handler.go b/src/internal/http/register_handler.go new file mode 100644 index 0000000..7e40681 --- /dev/null +++ b/src/internal/http/register_handler.go @@ -0,0 +1,33 @@ +package http + +import ( + commonDTO "git.ego.freeddns.org/egommerce/api-entities/common/dto" + identityDTO "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/ui" + + "github.com/go-redis/redis/v8" + "github.com/gofiber/fiber/v2" + "github.com/jackc/pgx/v5/pgxpool" +) + +func RegisterHandlerFn(db *pgxpool.Pool, cache *redis.Client) fiber.Handler { + return func(c *fiber.Ctx) error { + data := new(identityDTO.AuthRegisterRequestDTO) + if err := c.BodyParser(data); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(commonDTO.ErrorResponseDTO{Error: "Error parsing input"}) + // return srv.Error(c, fiber.StatusBadRequest, "Error parsing input") + } + + repo := repository.NewUserRepository(db) + + id, err := ui.NewRegisterActionUI(repo, cache).Execute(data) + if err != nil { + return c.Status(fiber.StatusBadRequest).JSON(commonDTO.ErrorResponseDTO{Error: err.Error()}) + // return srv.Error(c, fiber.StatusBadRequest, err.Error()) + } + + return c.JSON(&identityDTO.AuthRegisterResponseDTO{ID: id}) + } +} diff --git a/src/internal/server/access_handler.go b/src/internal/server/access_handler.go deleted file mode 100644 index 64911e6..0000000 --- a/src/internal/server/access_handler.go +++ /dev/null @@ -1,28 +0,0 @@ -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" - "github.com/gofiber/fiber/v2" -) - -func (s *Server) AccessHandlerFn(c *fiber.Ctx) error { - userRepo := repository.NewUserRepository(s.GetDatabase()) - roleRepo := repository.NewRoleRepository(s.GetDatabase()) - urlRepo := repository.NewURLAccessRepository(s.GetDatabase()) - authSrv := service.NewAuthService(userRepo, s.GetCache()) - guardSrv := service.NewGuardService(authSrv, s.GetCache(), userRepo, roleRepo, urlRepo) - - url, srvName := c.Query("q"), c.Query("srv") - header := new(dto.AuthorizationHeaderDTO) - c.ReqHeaderParser(header) - - if err := ui.NewAccessActionUI(guardSrv).Execute(header, url, srvName); err != nil { - return s.Error(c, fiber.StatusNotFound, err.Error()) - } - - return c.SendStatus(fiber.StatusNoContent) -} diff --git a/src/internal/server/health_handler.go b/src/internal/server/health_handler.go deleted file mode 100644 index 136c41d..0000000 --- a/src/internal/server/health_handler.go +++ /dev/null @@ -1,29 +0,0 @@ -package server - -import ( - "context" - "net/http" - - "github.com/gofiber/fiber/v2" -) - -type HealthResponse struct { - Status string `json:"status,omitempty"` -} - -func (s *Server) HealthHandler(c *fiber.Ctx) error { - // Only 404 indicate service as not-healthy - err := s.GetDatabase().Ping(context.Background()) - if err != nil { - return c.SendStatus(http.StatusNotFound) - } - - err = s.GetCache().Ping(context.Background()).Err() - if err != nil { - return c.SendStatus(http.StatusNotFound) - } - - return c.JSON(&HealthResponse{ - Status: "OK", - }) -} diff --git a/src/internal/server/login_handler.go b/src/internal/server/login_handler.go deleted file mode 100644 index ba03013..0000000 --- a/src/internal/server/login_handler.go +++ /dev/null @@ -1,27 +0,0 @@ -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" - - "github.com/gofiber/fiber/v2" -) - -func (s *Server) LoginHandlerFn(c *fiber.Ctx) error { - 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(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()) - } - - return c.JSON(&dto.AuthLoginResponseDTO{Token: token}) -} diff --git a/src/internal/server/middlewares.go b/src/internal/server/middlewares.go deleted file mode 100644 index 2dd4f23..0000000 --- a/src/internal/server/middlewares.go +++ /dev/null @@ -1,52 +0,0 @@ -package server - -import ( - "log" - - cnf "git.ego.freeddns.org/egommerce/go-api-pkg/config" - jwt "github.com/gofiber/contrib/jwt" - "github.com/gofiber/fiber/v2" - "github.com/google/uuid" -) - -// "github.com/gofiber/fiber/v2" -// "github.com/gofiber/fiber/v2/middleware/cors" - -func SetupMiddleware(s *Server) { - s.Use(LoggingMiddleware()) - s.Use(XRequestIDMiddleware()) -} - -func LoggingMiddleware() func(c *fiber.Ctx) error { - return func(c *fiber.Ctx) error { - log.Printf("Request: %s, remote: %s, via: %s", - c.Request().URI().String(), - c.Context().RemoteIP().String(), - string(c.Context().UserAgent()), - ) - - return c.Next() - } -} - -func XRequestIDMiddleware() func(c *fiber.Ctx) error { - return func(c *fiber.Ctx) error { - c.Set("X-Request-ID", uuid.New().String()) - - return c.Next() - } -} - -func JWTProtected(s *Server) func(c *fiber.Ctx) error { - secret := []byte(cnf.GetEnv("JWT_ACCESS_TOKEN_SECRET_KEY", "FallbackAccessTokenSecret")) - - return func(c *fiber.Ctx) error { - return jwt.New(jwt.Config{ - SigningKey: jwt.SigningKey{Key: secret}, - ContextKey: "jwt", - ErrorHandler: func(c *fiber.Ctx, err error) error { - return s.Error(c, fiber.StatusUnauthorized, "unauthorized") - }, - })(c) - } -} diff --git a/src/internal/server/refresh_handler.go b/src/internal/server/refresh_handler.go deleted file mode 100644 index f6526b6..0000000 --- a/src/internal/server/refresh_handler.go +++ /dev/null @@ -1,27 +0,0 @@ -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" - - "github.com/gofiber/fiber/v2" -) - -func (s *Server) RefreshHandlerFn(c *fiber.Ctx) error { - header := new(dto.AuthorizationHeaderDTO) - if err := c.ReqHeaderParser(header); err != nil { - return s.Error(c, fiber.StatusBadRequest, "Error parsing headers") - } - - repo := repository.NewUserRepository(s.GetDatabase()) - authSrv := service.NewAuthService(repo, s.GetCache()) - - token, err := ui.NewRefreshTokenActionUI(authSrv).Execute(header) - if err != nil { - return s.Error(c, fiber.StatusBadRequest, err.Error()) - } - - return c.JSON(&dto.AuthRefreshTokenResponseDTO{Token: token}) -} diff --git a/src/internal/server/register_handler.go b/src/internal/server/register_handler.go deleted file mode 100644 index debc2f8..0000000 --- a/src/internal/server/register_handler.go +++ /dev/null @@ -1,25 +0,0 @@ -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/ui" - - "github.com/gofiber/fiber/v2" -) - -func (s *Server) RegisterHandlerFn(c *fiber.Ctx) error { - data := new(dto.AuthRegisterRequestDTO) - if err := c.BodyParser(data); err != nil { - return s.Error(c, fiber.StatusBadRequest, "Error parsing input") - } - - repo := repository.NewUserRepository(s.GetDatabase()) - - id, err := ui.NewRegisterActionUI(repo, s.GetCache()).Execute(data) - if err != nil { - return s.Error(c, fiber.StatusBadRequest, err.Error()) - } - - return c.JSON(&dto.AuthRegisterResponseDTO{ID: id}) -} diff --git a/src/internal/server/router.go b/src/internal/server/router.go deleted file mode 100644 index ae59d79..0000000 --- a/src/internal/server/router.go +++ /dev/null @@ -1,27 +0,0 @@ -package server - -import ( - "github.com/gofiber/fiber/v2/middleware/cors" -) - -var ( - defaultCORS = cors.New(cors.Config{ - AllowOrigins: "*", - // AllowCredentials: true, - AllowMethods: "GET, POST, PATCH, PUT, DELETE, OPTIONS", - AllowHeaders: "Accept, Authorization, Content-Type, Vary, X-Request-Id", - }) -) - -func SetupRouter(s *Server) { - s.Options("*", defaultCORS) - s.Use(defaultCORS) - - s.Get("/health", s.HealthHandler) - - s.Group("/v1"). - Post("/login", s.LoginHandlerFn). - Post("/refresh", s.RefreshHandlerFn). // TODO: add JWTProtected() and get token from Auth Bearer Header not from the Body - Post("/register", s.RegisterHandlerFn). - Get("/access", JWTProtected(s), s.AccessHandlerFn) -} diff --git a/src/internal/server/server.go b/src/internal/server/server.go deleted file mode 100644 index 5b4d08b..0000000 --- a/src/internal/server/server.go +++ /dev/null @@ -1,95 +0,0 @@ -package server - -import ( - "crypto/tls" - "log" - "net" - "time" - - "github.com/go-redis/redis/v8" - "github.com/gofiber/fiber/v2" - "github.com/jackc/pgx/v5/pgxpool" - - dto "git.ego.freeddns.org/egommerce/api-entities/common/dto" - - "git.ego.freeddns.org/egommerce/identity-service/common" -) - -type ( - Server struct { - *fiber.App - - ID string - addr string // e.g. "127.0.0.1:443" - handlers map[string]any - } - HeaderRequestID struct { - RequestID string `reqHeader:"x-request-id"` - } -) - -func New(c *common.Config) *Server { - return &Server{ - ID: c.ID, - App: fiber.New(fiber.Config{ - AppName: c.ID, - ServerHeader: c.Name + ":" + c.ID, - ReadTimeout: c.ReadTimeout * time.Millisecond, - WriteTimeout: c.WriteTimeout * time.Millisecond, - IdleTimeout: c.IdleTimeout * time.Millisecond, - }), - addr: c.NetAddr, - handlers: make(map[string]any), - } -} - -func (s *Server) Start() error { - SetupMiddleware(s) - SetupRouter(s) - - crt, err := tls.LoadX509KeyPair("certs/identity-svc.crt", "certs/identity-svc.key") - if err != nil { - log.Fatal(err) - } - - tlsCnf := &tls.Config{Certificates: []tls.Certificate{crt}} - ln, _ := net.Listen("tcp", s.addr) - ln = tls.NewListener(ln, tlsCnf) - - return s.Listener(ln) -} - -func (s *Server) RegisterHandler(name string, fn func() any) { - s.handlers[name] = fn() -} - -func (s *Server) OnShutdown() { - log.Printf("Server %s is going down...", s.ID) - - s.GetDatabase().Close() - s.GetCache().Close() - - s.Shutdown() -} - -func (s *Server) GetRequestID(c *fiber.Ctx) (string, error) { - var hdr = new(HeaderRequestID) - if err := c.ReqHeaderParser(hdr); err != nil { - return "", err - } - - return hdr.RequestID, nil -} - -func (s *Server) Error(c *fiber.Ctx, code int, msg string) error { - return c.Status(code).JSON(dto.ErrorResponseDTO{Error: msg}) -} - -// Plugin helper funcitons - refactor needed cause funcs are duplcated in chronos.go -func (s *Server) GetCache() *redis.Client { - return (s.handlers["cache"]).(*redis.Client) -} - -func (s *Server) GetDatabase() *pgxpool.Pool { - return (s.handlers["database"]).(*pgxpool.Pool) -} diff --git a/src/internal/ui/access_action.go b/src/internal/ui/access_action.go deleted file mode 100644 index d3a41fc..0000000 --- a/src/internal/ui/access_action.go +++ /dev/null @@ -1,24 +0,0 @@ -package ui - -import ( - dto "git.ego.freeddns.org/egommerce/api-entities/identity/dto" - - "git.ego.freeddns.org/egommerce/identity-service/internal/service" -) - -type AccessActionUI struct { - guard *service.GuardService -} - -func NewAccessActionUI(guard *service.GuardService) *AccessActionUI { - return &AccessActionUI{guard: guard} -} - -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 - } - - return nil -} diff --git a/src/internal/ui/check_user_permissions_action.go b/src/internal/ui/check_user_permissions_action.go new file mode 100644 index 0000000..0937db3 --- /dev/null +++ b/src/internal/ui/check_user_permissions_action.go @@ -0,0 +1,24 @@ +package ui + +import ( + identityDTO "git.ego.freeddns.org/egommerce/api-entities/identity/dto" + + "git.ego.freeddns.org/egommerce/identity-service/internal/service" +) + +type CheckUserPermissionsUI struct { + guard *service.GuardService +} + +func NewAccessActionUI(guard *service.GuardService) *CheckUserPermissionsUI { + return &CheckUserPermissionsUI{guard: guard} +} + +func (ui *CheckUserPermissionsUI) Execute(data *identityDTO.AuthorizationHeaderDTO, url, srvName string) error { // TODO: rename to CheckAccess + err := ui.guard.CheckUserPermissions(data, url, srvName) + if err != nil { + return err + } + + return nil +} diff --git a/src/internal/ui/login_action.go b/src/internal/ui/login_action.go index 896638b..7e6d468 100644 --- a/src/internal/ui/login_action.go +++ b/src/internal/ui/login_action.go @@ -1,7 +1,7 @@ package ui import ( - dto "git.ego.freeddns.org/egommerce/api-entities/identity/dto" + identityDTO "git.ego.freeddns.org/egommerce/api-entities/identity/dto" "git.ego.freeddns.org/egommerce/identity-service/internal/service" ) @@ -15,7 +15,7 @@ func NewLoginActionUI(authSrv *service.AuthService) *LoginActionUI { } } -func (ui *LoginActionUI) Execute(data *dto.AuthLoginRequestDTO) (string, error) { +func (ui *LoginActionUI) Execute(data *identityDTO.AuthLoginRequestDTO) (string, error) { token, err := ui.authSrv.Login(data.Username, data.Password) if err != nil { // TODO: handle other response status codes -- add struct to decorate error with code and message diff --git a/src/internal/ui/refresh_action.go b/src/internal/ui/refresh_action.go index e60151b..66afc3b 100644 --- a/src/internal/ui/refresh_action.go +++ b/src/internal/ui/refresh_action.go @@ -1,7 +1,7 @@ package ui import ( - dto "git.ego.freeddns.org/egommerce/api-entities/identity/dto" + identityDTO "git.ego.freeddns.org/egommerce/api-entities/identity/dto" "git.ego.freeddns.org/egommerce/identity-service/internal/service" ) @@ -15,7 +15,7 @@ func NewRefreshTokenActionUI(auth *service.AuthService) *RefreshTokenActionUI { } } -func (ui *RefreshTokenActionUI) Execute(header *dto.AuthorizationHeaderDTO) (string, error) { +func (ui *RefreshTokenActionUI) Execute(header *identityDTO.AuthorizationHeaderDTO) (string, error) { token, _ := ui.auth.GetTokenFromAuthorizationHeader(header) newToken, err := ui.auth.RefreshToken(token) if err != nil { diff --git a/src/internal/ui/register_action.go b/src/internal/ui/register_action.go index 4357fe1..a682c95 100644 --- a/src/internal/ui/register_action.go +++ b/src/internal/ui/register_action.go @@ -1,7 +1,7 @@ package ui import ( - dto "git.ego.freeddns.org/egommerce/api-entities/identity/dto" + identityDTO "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" @@ -18,7 +18,7 @@ func NewRegisterActionUI(repo *repository.UserRepository, cache *redis.Client) * } } -func (ui *RegisterActionUI) Execute(data *dto.AuthRegisterRequestDTO) (string, error) { +func (ui *RegisterActionUI) Execute(data *identityDTO.AuthRegisterRequestDTO) (string, error) { id, err := ui.authSrv.Register(data.Email, data.Username, data.Password) if err != nil { return "", err