diff --git a/internal/use-case/main-use-case/user/case.go b/internal/use-case/main-use-case/user/case.go index 0f901af9..c125afd0 100644 --- a/internal/use-case/main-use-case/user/case.go +++ b/internal/use-case/main-use-case/user/case.go @@ -1,7 +1,6 @@ package user import ( - "fmt" e "simrs-vx/internal/domain/main-entities/user" "strconv" @@ -30,22 +29,12 @@ func Create(input e.CreateDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "create") err := dg.I.Transaction(func(tx *gorm.DB) error { - for i := range createPreMw { - mwName := fmt.Sprintf("createPreMw[%d]", i) + executor := newMiddlewareExecutor(&event, tx) + executor.setMwtype(pu.MWTPre) - pl.SetLogInfo(&event, data, "started", mwName) - - if err := createPreMw[i](&input, &data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + // Execute pre-middleware + if err := executor.ExecuteCreateMiddleware(createPreMw, &input, &data); err != nil { + return err } pl.SetLogInfo(&event, data, "started", "DBCreate") @@ -62,19 +51,10 @@ func Create(input e.CreateDto) (*d.Data, error) { pl.SetLogInfo(&event, nil, "complete") - for i := range createPostMw { - mwName := fmt.Sprintf("createPostMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - if err := createPostMw[i](&input, &data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } + executor.setMwtype(pu.MWTPost) + // Execute post-middleware + if err := executor.ExecuteCreateMiddleware(createPostMw, &input, &data); err != nil { + return err } pl.SetLogInfo(&event, nil, "complete") @@ -111,22 +91,12 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readList") err = dg.I.Transaction(func(tx *gorm.DB) error { - for i := range readListPreMw { - mwName := fmt.Sprintf("readListPreMw[%d]", i) + executor := newMiddlewareExecutor(&event, tx) + executor.setMwtype(pu.MWTPre) - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readListPreMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + // Execute pre-middleware + if err := executor.ExecuteReadListMiddleware(readListPreMw, &input, data); err != nil { + return err } pl.SetLogInfo(&event, input, "started", "DBReadList") @@ -143,22 +113,10 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { pl.SetLogInfo(&event, nil, "complete") - for i := range readListPostMw { - mwName := fmt.Sprintf("readListPostMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readListPostMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + executor.setMwtype(pu.MWTPost) + // Execute post-middleware + if err := executor.ExecuteReadListMiddleware(readListPostMw, &input, data); err != nil { + return err } return nil @@ -194,22 +152,12 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readDetail") err = dg.I.Transaction(func(tx *gorm.DB) error { - for i := range readDetailPreMw { - mwName := fmt.Sprintf("readDetailPreMw[%d]", i) + executor := newMiddlewareExecutor(&event, tx) + executor.setMwtype(pu.MWTPre) - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readDetailPreMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + // Execute pre-middleware + if err := executor.ExecuteReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { + return err } pl.SetLogInfo(&event, input, "started", "DBReadDetail") @@ -218,22 +166,10 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { return processedErr } - for i := range readDetailPostMw { - mwName := fmt.Sprintf("readDetailPostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := readDetailPostMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + executor.setMwtype(pu.MWTPost) + // Execute post-middleware + if err := executor.ExecuteReadDetailMiddleware(readDetailPostMw, &input, data); err != nil { + return err } return nil @@ -287,22 +223,12 @@ func Update(input e.UpdateDto) (*d.Data, error) { pl.SetLogInfo(&event, nil, "complete") - for i := range updatePreMw { - mwName := fmt.Sprintf("updatePreMw[%d]", i) + executor := newMiddlewareExecutor(&event, tx) + executor.setMwtype(pu.MWTPre) - pl.SetLogInfo(&event, data, "started", mwName) - - if err := updatePreMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + // Execute pre-middleware + if err := executor.ExecuteUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err } pl.SetLogInfo(&event, data, "started", "DBUpdate") @@ -318,22 +244,10 @@ func Update(input e.UpdateDto) (*d.Data, error) { pl.SetLogInfo(&event, nil, "complete") - for i := range updatePostMw { - mwName := fmt.Sprintf("updatePostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := updatePostMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + executor.setMwtype(pu.MWTPost) + // Execute post-middleware + if err := executor.ExecuteUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err } return nil @@ -374,22 +288,12 @@ func Delete(input e.DeleteDto) (*d.Data, error) { return processedErr } - for i := range deletePreMw { - mwName := fmt.Sprintf("deletePreMw[%d]", i) + executor := newMiddlewareExecutor(&event, tx) + executor.setMwtype(pu.MWTPre) - pl.SetLogInfo(&event, data, "started", mwName) - - if err := deletePreMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + // Execute pre-middleware + if err := executor.ExecuteDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err } pl.SetLogInfo(&event, data, "started", "DBDelete") @@ -405,22 +309,10 @@ func Delete(input e.DeleteDto) (*d.Data, error) { pl.SetLogInfo(&event, nil, "complete") - for i := range deletePostMw { - mwName := fmt.Sprintf("deletePostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := deletePostMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + executor.setMwtype(pu.MWTPost) + // Execute post-middleware + if err := executor.ExecuteDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err } return nil diff --git a/internal/use-case/main-use-case/user/helper.go b/internal/use-case/main-use-case/user/helper.go index 1d334fb7..7fa1ec34 100644 --- a/internal/use-case/main-use-case/user/helper.go +++ b/internal/use-case/main-use-case/user/helper.go @@ -5,9 +5,13 @@ Any functions that are used internally by the use-case package user import ( + "fmt" e "simrs-vx/internal/domain/main-entities/user" + pl "simrs-vx/pkg/logger" p "simrs-vx/pkg/password" + + "gorm.io/gorm" ) func setCreate(src e.CreateDto, dst *e.User) error { @@ -29,3 +33,103 @@ func setUpdate(src e.UpdateDto, dst *e.User) error { return nil } + +// executeCreateMiddleware executes create middleware (pre or post) +func executeCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.User, tx *gorm.DB, event *pl.Event, mwType string) error { + for i := range middlewares { + mwName := fmt.Sprintf("%s[%d]", mwType, i) + + pl.SetLogInfo(event, data, "started", mwName) + + if err := middlewares[i](input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: getMiddlewareErrorCode(mwType), + Detail: fmt.Sprintf("%s middleware %s failed", getMiddlewareTypeLabel(mwType), mwName), + Raw: err, + } + return pl.SetLogError(*event, data) + } + + pl.SetLogInfo(event, nil, "complete") + } + return nil +} + +// executeReadListMiddleware executes read list middleware (pre or post) +func executeReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.User, tx *gorm.DB, event *pl.Event, mwType string) error { + for i := range middlewares { + mwName := fmt.Sprintf("%s[%d]", mwType, i) + + pl.SetLogInfo(event, input, "started", mwName) + + if err := middlewares[i](input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: getMiddlewareErrorCode(mwType), + Detail: fmt.Sprintf("%s middleware %s failed", getMiddlewareTypeLabel(mwType), mwName), + Raw: err, + } + return pl.SetLogError(*event, input) + } + + pl.SetLogInfo(event, nil, "complete") + } + return nil +} + +// executeReadDetailMiddleware executes read detail middleware (pre or post) +func executeReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.User, tx *gorm.DB, event *pl.Event, mwType string) error { + for i := range middlewares { + mwName := fmt.Sprintf("%s[%d]", mwType, i) + + // Use data for logging if available, otherwise use input + logData := interface{}(input) + if data != nil { + logData = data + } + + pl.SetLogInfo(event, logData, "started", mwName) + + if err := middlewares[i](input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: getMiddlewareErrorCode(mwType), + Detail: fmt.Sprintf("%s middleware %s failed", getMiddlewareTypeLabel(mwType), mwName), + Raw: err, + } + return pl.SetLogError(*event, logData) + } + + pl.SetLogInfo(event, nil, "complete") + } + return nil +} + +// Helper functions to determine error codes and labels based on middleware type +func getMiddlewareErrorCode(mwType string) string { + if containsString(mwType, "Pre") { + return "MW_PRE_FAILED" + } + return "MW_POST_FAILED" +} + +func getMiddlewareTypeLabel(mwType string) string { + if containsString(mwType, "Pre") { + return "Pre" + } + return "Post" +} + +func containsString(str, substr string) bool { + return len(str) >= len(substr) && str[len(str)-len(substr):] != substr && + (len(str) == len(substr) || str[len(str)-len(substr)-1:len(str)-len(substr)] != substr) && + func() bool { + for i := 0; i <= len(str)-len(substr); i++ { + if str[i:i+len(substr)] == substr { + return true + } + } + return false + }() +} diff --git a/internal/use-case/main-use-case/user/middleware.go b/internal/use-case/main-use-case/user/middleware.go new file mode 100644 index 00000000..208468b6 --- /dev/null +++ b/internal/use-case/main-use-case/user/middleware.go @@ -0,0 +1,159 @@ +package user + +// pm "simrs-vx/internal/use-case/plugin/modifier" + +import ( + "fmt" + e "simrs-vx/internal/domain/main-entities/user" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +// func init() { +// createPreMw = append(createPreMw, pm.ModifInput) +// createPreMw = append(createPreMw, pm.CheckData) +// } + +type middlewareExecutor struct { + Event *pl.Event + Tx *gorm.DB + MwType pu.MWType +} + +// NewMiddlewareExecutor creates a new middleware executor +func newMiddlewareExecutor(event *pl.Event, tx *gorm.DB) *middlewareExecutor { + return &middlewareExecutor{ + Event: event, + Tx: tx, + } +} + +// ExecuteCreateMiddleware executes create middleware +func (me *middlewareExecutor) ExecuteCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.User) error { + for i, middleware := range middlewares { + mwName := fmt.Sprintf("%s[%d]", me.MwType, i) + + pl.SetLogInfo(me.Event, data, "started", mwName) + + if err := middleware(input, data, me.Tx); err != nil { + me.Event.Status = "failed" + me.Event.ErrInfo = pl.ErrorInfo{ + Code: pu.GetMiddlewareErrorCode(me.MwType), + Detail: fmt.Sprintf("%s middleware %s failed", me.MwType, mwName), + Raw: err, + } + return pl.SetLogError(*me.Event, data) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareExecutor) ExecuteReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.User) error { + for i, middleware := range middlewares { + mwName := fmt.Sprintf("%s[%d]", me.MwType, i) + + pl.SetLogInfo(me.Event, input, "started", mwName) + + if err := middleware(input, data, me.Tx); err != nil { + me.Event.Status = "failed" + me.Event.ErrInfo = pl.ErrorInfo{ + Code: pu.GetMiddlewareErrorCode(me.MwType), + Detail: fmt.Sprintf("%s middleware %s failed", me.MwType, mwName), + Raw: err, + } + return pl.SetLogError(*me.Event, input) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareExecutor) ExecuteReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.User) error { + for i, middleware := range middlewares { + mwName := fmt.Sprintf("%s[%d]", me.MwType, i) + + // Use data for logging if available, otherwise use input + logData := interface{}(input) + if data != nil { + logData = data + } + + pl.SetLogInfo(me.Event, logData, "started", mwName) + + if err := middleware(input, data, me.Tx); err != nil { + me.Event.Status = "failed" + me.Event.ErrInfo = pl.ErrorInfo{ + Code: pu.GetMiddlewareErrorCode(me.MwType), + Detail: fmt.Sprintf("%s middleware %s failed", me.MwType, mwName), + Raw: err, + } + return pl.SetLogError(*me.Event, logData) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareExecutor) ExecuteUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.User) error { + for i, middleware := range middlewares { + mwName := fmt.Sprintf("%s[%d]", me.MwType, i) + + // Use data for logging if available, otherwise use input + logData := interface{}(input) + if data != nil { + logData = data + } + + pl.SetLogInfo(me.Event, logData, "started", mwName) + + if err := middleware(input, data, me.Tx); err != nil { + me.Event.Status = "failed" + me.Event.ErrInfo = pl.ErrorInfo{ + Code: pu.GetMiddlewareErrorCode(me.MwType), + Detail: fmt.Sprintf("%s middleware %s failed", me.MwType, mwName), + Raw: err, + } + return pl.SetLogError(*me.Event, logData) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareExecutor) ExecuteDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.User) error { + for i, middleware := range middlewares { + mwName := fmt.Sprintf("%s[%d]", me.MwType, i) + + // Use data for logging if available, otherwise use input + logData := interface{}(input) + if data != nil { + logData = data + } + + pl.SetLogInfo(me.Event, logData, "started", mwName) + + if err := middleware(input, data, me.Tx); err != nil { + me.Event.Status = "failed" + me.Event.ErrInfo = pl.ErrorInfo{ + Code: pu.GetMiddlewareErrorCode(me.MwType), + Detail: fmt.Sprintf("%s middleware %s failed", me.MwType, mwName), + Raw: err, + } + return pl.SetLogError(*me.Event, logData) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareExecutor) setMwtype(mwType pu.MWType) { + me.MwType = mwType +} diff --git a/pkg/use-case-helper/tycovar.go b/pkg/use-case-helper/tycovar.go new file mode 100644 index 00000000..c515b158 --- /dev/null +++ b/pkg/use-case-helper/tycovar.go @@ -0,0 +1,8 @@ +package usecasehelper + +type MWType string + +const ( + MWTPre MWType = "Pre" + MWTPost MWType = "Post" +) diff --git a/pkg/use-case-helper/use-case-helper.go b/pkg/use-case-helper/use-case-helper.go index 20550048..999bc732 100644 --- a/pkg/use-case-helper/use-case-helper.go +++ b/pkg/use-case-helper/use-case-helper.go @@ -3,6 +3,7 @@ package usecasehelper import ( "errors" "fmt" + "strings" pl "simrs-vx/pkg/logger" @@ -46,3 +47,10 @@ func HandleReadError(err error, event *pl.Event, itemType string, id interface{} return pl.SetLogError(*event, nil) } + +func GetMiddlewareErrorCode(mwType MWType) string { + if strings.Contains(string(mwType), "Pre") { + return "MW_PRE_FAILED" + } + return "MW_POST_FAILED" +}