diff --git a/.env.example b/.env.example index 5101925..9851533 100644 --- a/.env.example +++ b/.env.example @@ -29,3 +29,4 @@ INTRANET_BASE_URL = https://pg-stage-intranet.joshsoftware.com SENDGRID_API_KEY=sendgrid_api_key SENDER_EMAIL=sendgrid_email +DEVELOPER_KEY = developer_key \ No newline at end of file diff --git a/.gitignore b/.gitignore index e95eeb1..5127325 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,5 @@ go.work.sum .env .vscode -serviceAccountKey.json \ No newline at end of file +serviceAccountKey.json +logs/* diff --git a/assets/silverBadge.png b/assets/silverBadge.png index 6dacd2c..af83817 100644 Binary files a/assets/silverBadge.png and b/assets/silverBadge.png differ diff --git a/cmd/main.go b/cmd/main.go index 2810cd9..e504ba7 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -17,6 +17,7 @@ import ( "github.com/joshsoftware/peerly-backend/internal/app" "github.com/joshsoftware/peerly-backend/internal/app/cronjob" "github.com/joshsoftware/peerly-backend/internal/pkg/config" + log "github.com/joshsoftware/peerly-backend/internal/pkg/logger" "github.com/joshsoftware/peerly-backend/internal/repository" script "github.com/joshsoftware/peerly-backend/scripts" "github.com/rs/cors" @@ -94,13 +95,18 @@ func startApp() (err error) { // Context for main function ctx := context.Background() - logger.Info("Starting Peerly Application...") - defer logger.Info("Shutting Down Peerly Application...") + lg,err := log.SetupLogger() + if err != nil{ + logger.Error("logger setup failed ",err.Error()) + return err + } + log.Info(ctx,"Starting Peerly Application...") + defer log.Info(ctx,"Shutting Down Peerly Application...") //initialize database dbInstance, err := repository.InitializeDatabase() if err != nil { - logger.WithField("err", err.Error()).Error("Database init failed") - return + log.Error(ctx,"Database init failed") + return err } //cors @@ -117,17 +123,25 @@ func startApp() (err error) { // Initializing Cron Job scheduler, err := gocron.NewScheduler() if err != nil { - logger.Error(ctx, "scheduler creation failed with error: %s", err.Error()) - return + log.Error(ctx, "scheduler creation failed with error: %s", err.Error()) + return err } cronjob.InitializeJobs(services.AppreciationService, services.UserService, scheduler) - defer scheduler.Shutdown() + defer func() { + if err := scheduler.Shutdown(); err != nil { + log.Error(ctx, "Scheduler shutdown failed: %s", err.Error()) + } + }() //initialize router router := api.NewRouter(services) - // init web server - server := negroni.Classic() + // Negroni logger setup + negroniLogger := negroni.NewLogger() + negroniLogger.ALogger = lg + + // Initialize web server + server := negroni.New(negroniLogger) server.Use(c) server.UseHandler(router) diff --git a/deploy.rb b/deploy.rb index c0caab7..3cb15fe 100644 --- a/deploy.rb +++ b/deploy.rb @@ -22,7 +22,7 @@ task :production do set :deploy_to, '/www/peerly-backend' set :domain, ENV['PEERLY_PRODUCTIONS_IP'] - set :branch, 'Deployment' + set :branch, 'main' end task :setup do diff --git a/go.mod b/go.mod index 08d79bf..59a601e 100644 --- a/go.mod +++ b/go.mod @@ -97,5 +97,6 @@ require ( google.golang.org/grpc v1.62.1 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index c389ed7..58bab3e 100644 --- a/go.sum +++ b/go.sum @@ -331,6 +331,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/internal/api/appreciation.go b/internal/api/appreciation.go index 4023f84..19a7bef 100644 --- a/internal/api/appreciation.go +++ b/internal/api/appreciation.go @@ -9,8 +9,8 @@ import ( "github.com/joshsoftware/peerly-backend/internal/app/appreciation" "github.com/joshsoftware/peerly-backend/internal/pkg/apperrors" "github.com/joshsoftware/peerly-backend/internal/pkg/dto" + log "github.com/joshsoftware/peerly-backend/internal/pkg/logger" "github.com/joshsoftware/peerly-backend/internal/pkg/utils" - logger "github.com/sirupsen/logrus" ) func createAppreciationHandler(appreciationSvc appreciation.Service) http.HandlerFunc { @@ -18,45 +18,52 @@ func createAppreciationHandler(appreciationSvc appreciation.Service) http.Handle var appreciation dto.Appreciation err := json.NewDecoder(req.Body).Decode(&appreciation) if err != nil { - logger.Errorf("Error while decoding request data : %v", err) + log.Errorf(req.Context(),"Error while decoding request data : %v", err) err = apperrors.JSONParsingErrorReq dto.ErrorRepsonse(rw, err) return } + log.Info(req.Context(),"createAppreciationHandler: request: ",req) err = appreciation.ValidateCreateAppreciation() if err != nil { - logger.Errorf("Error while validating request data : %v", err) + log.Errorf(req.Context(),"Error while validating request data : %v", err) dto.ErrorRepsonse(rw, err) return } resp, err := appreciationSvc.CreateAppreciation(req.Context(), appreciation) if err != nil { - logger.Errorf("err : %v", err) + log.Errorf(req.Context(),"createAppreciationHandler: err : %v", err) dto.ErrorRepsonse(rw, err) return } + log.Debug(req.Context(),"createAppreciationHandler: response: ",resp) + log.Info(req.Context(),"Appreciation created successfully") dto.SuccessRepsonse(rw, http.StatusCreated, "Appreciation created successfully", resp) }) } func getAppreciationByIDHandler(appreciationSvc appreciation.Service) http.HandlerFunc { return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { - vars := mux.Vars(req) apprID, err := strconv.Atoi(vars["id"]) if err != nil { + log.Errorf(req.Context(),"Error while decoding appreciation id : %v", err) dto.ErrorRepsonse(rw, err) return } - + + log.Info(req.Context(),"getAppreciationByIDHandler: request: ",req) resp, err := appreciationSvc.GetAppreciationById(req.Context(), int32(apprID)) if err != nil { - logger.Errorf("err : %v", err) + log.Errorf(req.Context(),"getAppreciationByIDHandler: err : %v", err) dto.ErrorRepsonse(rw, err) return } + + log.Debug(req.Context(),"getAppreciationByIDHandler: request: ",resp) + log.Info(req.Context(),"Appreciation data got successfully") dto.SuccessRepsonse(rw, http.StatusOK, "Appreciation data got successfully", resp) }) } @@ -64,7 +71,6 @@ func getAppreciationByIDHandler(appreciationSvc appreciation.Service) http.Handl // getAppreciationsHandler handles HTTP requests for appreciations func listAppreciationsHandler(appreciationSvc appreciation.Service) http.HandlerFunc { return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { - var filter dto.AppreciationFilter filter.Name = req.URL.Query().Get("name") @@ -76,13 +82,15 @@ func listAppreciationsHandler(appreciationSvc appreciation.Service) http.Handler filter.Limit = limit filter.Page = page filter.Self = utils.GetSelfParam(req) - + log.Info(req.Context(),"listAppreciationsHandler: request: ",req) appreciations, err := appreciationSvc.ListAppreciations(req.Context(), filter) if err != nil { - logger.Errorf("err : %v", err) + log.Errorf(req.Context(),"listAppreciationsHandler: err : %v", err) dto.ErrorRepsonse(rw, err) return } + log.Debug(req.Context(),"listAppreciationsHandler: response: ",appreciations) + log.Info(req.Context(),"Appreciations data got successfully") dto.SuccessRepsonse(rw, http.StatusOK, "Appreciations data got successfully ", appreciations) }) } @@ -92,17 +100,20 @@ func deleteAppreciationHandler(appreciationSvc appreciation.Service) http.Handle vars := mux.Vars(req) apprId, err := strconv.Atoi(vars["id"]) if err != nil { - logger.Errorf("Error while decoding request param data : %v", err) + log.Errorf(req.Context(),"Error while decoding request param data : %v", err) dto.ErrorRepsonse(rw, apperrors.BadRequest) return } + log.Info(req.Context(),"deleteAppreciationHandler: request: ",req) err = appreciationSvc.DeleteAppreciation(req.Context(), int32(apprId)) if err != nil { - logger.Errorf("err : %v", err) + log.Errorf(req.Context(),"deleteAppreciationHandler: err : %v", err) dto.ErrorRepsonse(rw, err) return } + log.Debug(req.Context(),"deleteAppreciationHandler: resp: ",err) + log.Info(req.Context(),"Appreciation invalidate successfully") dto.SuccessRepsonse(rw, http.StatusOK, "Appreciation invalidate successfully", nil) }) } diff --git a/internal/api/badges.go b/internal/api/badges.go index f344029..e6473e1 100644 --- a/internal/api/badges.go +++ b/internal/api/badges.go @@ -8,7 +8,7 @@ import ( "github.com/joshsoftware/peerly-backend/internal/app/badges" "github.com/joshsoftware/peerly-backend/internal/pkg/apperrors" "github.com/joshsoftware/peerly-backend/internal/pkg/dto" - logger "github.com/sirupsen/logrus" + logger "github.com/joshsoftware/peerly-backend/internal/pkg/logger" ) func listBadgesHandler(badgeSvc badges.Service) http.HandlerFunc { @@ -30,7 +30,7 @@ func editBadgesHandler(badgeSvc badges.Service) http.HandlerFunc { var reqData dto.UpdateBadgeReq err := json.NewDecoder(req.Body).Decode(&reqData) if err != nil { - logger.Errorf("error while decoding request data, err: %s", err.Error()) + logger.Errorf(req.Context(), "error while decoding request data, err: %s", err.Error()) err = apperrors.JSONParsingErrorReq dto.ErrorRepsonse(rw, err) return diff --git a/internal/api/coreValues.go b/internal/api/coreValues.go index 4574e27..add8482 100644 --- a/internal/api/coreValues.go +++ b/internal/api/coreValues.go @@ -8,7 +8,7 @@ import ( corevalues "github.com/joshsoftware/peerly-backend/internal/app/coreValues" "github.com/joshsoftware/peerly-backend/internal/pkg/apperrors" "github.com/joshsoftware/peerly-backend/internal/pkg/dto" - logger "github.com/sirupsen/logrus" + logger "github.com/joshsoftware/peerly-backend/internal/pkg/logger" ) func listCoreValuesHandler(coreValueSvc corevalues.Service) http.HandlerFunc { @@ -46,7 +46,7 @@ func createCoreValueHandler(coreValueSvc corevalues.Service) http.HandlerFunc { var coreValue dto.CreateCoreValueReq err := json.NewDecoder(req.Body).Decode(&coreValue) if err != nil { - logger.Errorf("error while decoding request data, err: %s", err.Error()) + logger.Errorf(req.Context(), "error while decoding request data, err: %s", err.Error()) err = apperrors.JSONParsingErrorReq dto.ErrorRepsonse(rw, err) return @@ -72,7 +72,7 @@ func updateCoreValueHandler(coreValueSvc corevalues.Service) http.HandlerFunc { var updateReq dto.UpdateQueryRequest err := json.NewDecoder(req.Body).Decode(&updateReq) if err != nil { - logger.Errorf("error while decoding request data, err: %s", err.Error()) + logger.Errorf(req.Context(), "error while decoding request data, err: %s", err.Error()) err = apperrors.JSONParsingErrorReq dto.ErrorRepsonse(rw, err) return diff --git a/internal/api/grades.go b/internal/api/grades.go index de77801..739369c 100644 --- a/internal/api/grades.go +++ b/internal/api/grades.go @@ -8,7 +8,7 @@ import ( "github.com/joshsoftware/peerly-backend/internal/app/grades" "github.com/joshsoftware/peerly-backend/internal/pkg/apperrors" "github.com/joshsoftware/peerly-backend/internal/pkg/dto" - logger "github.com/sirupsen/logrus" + logger "github.com/joshsoftware/peerly-backend/internal/pkg/logger" ) func listGradesHandler(gradeSvc grades.Service) http.HandlerFunc { @@ -30,7 +30,7 @@ func editGradesHandler(gradeSvc grades.Service) http.HandlerFunc { var reqData dto.UpdateGradeReq err := json.NewDecoder(req.Body).Decode(&reqData) if err != nil { - logger.Errorf("error while decoding request data, err: %s", err.Error()) + logger.Errorf(ctx, "error while decoding request data, err: %s", err.Error()) err = apperrors.JSONParsingErrorReq dto.ErrorRepsonse(rw, err) return diff --git a/internal/api/log.go b/internal/api/log.go new file mode 100644 index 0000000..42a5aec --- /dev/null +++ b/internal/api/log.go @@ -0,0 +1,43 @@ +package api + +import ( + "encoding/json" + "fmt" + "net/http" + + "github.com/joshsoftware/peerly-backend/internal/pkg/apperrors" + "github.com/joshsoftware/peerly-backend/internal/pkg/config" + "github.com/joshsoftware/peerly-backend/internal/pkg/dto" + log "github.com/joshsoftware/peerly-backend/internal/pkg/logger" + "github.com/sirupsen/logrus" +) + + +func loggerHandler(rw http.ResponseWriter, req *http.Request) { + + log.Debug(req.Context(),"loggerHandler: req: ",req) + var changeLogRequest dto.ChangeLogLevelRequest + err := json.NewDecoder(req.Body).Decode(&changeLogRequest) + if err != nil { + log.Errorf(req.Context(),"Error while decoding request data : %v", err) + err = apperrors.JSONParsingErrorReq + dto.ErrorRepsonse(rw, err) + return + } + + if config.DeveloperKey() != changeLogRequest.DeveloperKey { + dto.ErrorRepsonse(rw,apperrors.UnauthorizedDeveloper) + return + } + + log.Info(req.Context(), "loggerHandler") + if changeLogRequest.LogLevel == "DebugLevel" { + log.Logger.SetLevel(logrus.DebugLevel) + }else if changeLogRequest.LogLevel == "InfoLevel" { + log.Logger.SetLevel(logrus.InfoLevel) + }else { + dto.ErrorRepsonse(rw, apperrors.InvalidLoggerLevel) + return + } + dto.SuccessRepsonse(rw, http.StatusOK, "Success", fmt.Sprintf("log level changed to %s", changeLogRequest.LogLevel)) +} diff --git a/internal/api/organizationconfig.go b/internal/api/organizationconfig.go index 0232996..3c2e7f7 100644 --- a/internal/api/organizationconfig.go +++ b/internal/api/organizationconfig.go @@ -7,22 +7,22 @@ import ( "github.com/joshsoftware/peerly-backend/internal/app/organizationConfig" "github.com/joshsoftware/peerly-backend/internal/pkg/apperrors" "github.com/joshsoftware/peerly-backend/internal/pkg/dto" - - logger "github.com/sirupsen/logrus" + logger "github.com/joshsoftware/peerly-backend/internal/pkg/logger" ) func getOrganizationConfigHandler(orgSvc organizationConfig.Service) http.HandlerFunc { return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { - + logger.Debug(req.Context(),"getOrganizationConfigHandler: req: ",req) orgConfig, err := orgSvc.GetOrganizationConfig(req.Context()) if err != nil { - logger.Errorf("Error while fetching organization: %v",err) + logger.Errorf(req.Context(),"Error while fetching organization: %v",err) dto.ErrorRepsonse(rw, err) return } - + logger.Debug(req.Context(),"getOrganizationConfigHandler: resp: ",orgConfig) + logger.Info(req.Context(),"organization config fetched successfully") dto.SuccessRepsonse(rw, http.StatusOK, "organization config fetched successfully",orgConfig) }) } @@ -31,28 +31,30 @@ func getOrganizationConfigHandler(orgSvc organizationConfig.Service) http.Handle func createOrganizationConfigHandler(orgSvc organizationConfig.Service) http.HandlerFunc { return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + logger.Debug(req.Context(),"createOrganizationConfigHandler: request: ",req) var orgConfig dto.OrganizationConfig err := json.NewDecoder(req.Body).Decode(&orgConfig) if err != nil { - logger.Errorf("Error while decoding organization config data: %v",err) + logger.Errorf(req.Context(),"Error while decoding organization config data: %v",err) dto.ErrorRepsonse(rw, apperrors.JSONParsingErrorReq) return } err = orgConfig.OrgValidate() if err != nil { - logger.Errorf("Error in validating request : %v",err) + logger.Errorf(req.Context(),"Error in validating request : %v",err) dto.ErrorRepsonse(rw, err) return } createdOrganizationConfig, err := orgSvc.CreateOrganizationConfig(req.Context(), orgConfig) if err != nil { - logger.Errorf("Error in creating organization config: %v",err) + logger.Errorf(req.Context(),"Error in creating organization config: %v",err) dto.ErrorRepsonse(rw, err) return } - + logger.Debug(req.Context(),"createOrganizationConfigHandler: resp: ",createdOrganizationConfig) + logger.Info(req.Context(),"Organization Config Created Successfully") dto.SuccessRepsonse(rw, http.StatusCreated, "Organization Config Created Successfully" ,createdOrganizationConfig) }) } @@ -63,26 +65,29 @@ func updateOrganizationConfigHandler(orgSvc organizationConfig.Service) http.Han var organizationConfig dto.OrganizationConfig err := json.NewDecoder(req.Body).Decode(&organizationConfig) if err != nil { - logger.Errorf("Error while decoding organization data: %v",err) + logger.Errorf(req.Context(),"Error while decoding organization data: %v",err) dto.ErrorRepsonse(rw, apperrors.JSONParsingErrorReq) return } + logger.Info(req.Context(),"updateOrganizationConfigHandler: request: ",req) organizationConfig.ID = 1 err = organizationConfig.OrgUpdateValidate() if err != nil { - logger.Errorf("Error in validating request : %v",err) + logger.Errorf(req.Context(),"Error in validating request : %v",err) dto.ErrorRepsonse(rw, err) return } updatedOrganization, err := orgSvc.UpdateOrganizationConfig(req.Context(), organizationConfig) if err != nil { - logger.Errorf("Error while updating organization: %v",err) + logger.Errorf(req.Context(),"Error while updating organization: %v",err) dto.ErrorRepsonse(rw, err) return } + logger.Debug(req.Context(),"updateOrganizationConfigHandler: resp: ",updatedOrganization) + logger.Info(req.Context(),"Organization Config Updated Successfully" ) dto.SuccessRepsonse(rw, http.StatusOK, "Organization Config Updated Successfully" ,updatedOrganization) }) diff --git a/internal/api/ping.go b/internal/api/ping.go index cad8479..1f0f25c 100644 --- a/internal/api/ping.go +++ b/internal/api/ping.go @@ -4,8 +4,11 @@ import ( "net/http" "github.com/joshsoftware/peerly-backend/internal/pkg/dto" + log "github.com/joshsoftware/peerly-backend/internal/pkg/logger" ) func pingHandler(rw http.ResponseWriter, req *http.Request) { - dto.SuccessRepsonse(rw, http.StatusOK, "Success", "testing") + log.Debug(req.Context(),"debug ping") + log.Info(req.Context(),"ping") + dto.SuccessRepsonse(rw, http.StatusOK, "Success", "pong") } diff --git a/internal/api/reportAppreciation.go b/internal/api/reportAppreciation.go index 2ec1601..e05cf23 100644 --- a/internal/api/reportAppreciation.go +++ b/internal/api/reportAppreciation.go @@ -9,7 +9,7 @@ import ( reportappreciations "github.com/joshsoftware/peerly-backend/internal/app/reportAppreciations" "github.com/joshsoftware/peerly-backend/internal/pkg/apperrors" "github.com/joshsoftware/peerly-backend/internal/pkg/dto" - logger "github.com/sirupsen/logrus" + logger "github.com/joshsoftware/peerly-backend/internal/pkg/logger" ) func reportAppreciationHandler(reportAppreciationSvc reportappreciations.Service) http.HandlerFunc { @@ -23,7 +23,7 @@ func reportAppreciationHandler(reportAppreciationSvc reportappreciations.Service appreciationId, err := strconv.ParseInt(vars["id"], 10, 64) if err != nil { - logger.WithField("err", err.Error()).Error("Error while parsing appreciation id from url") + logger.Errorf(req.Context(), "error while parsing appreciation id from url, err: %v", err) err = apperrors.InternalServerError return @@ -31,7 +31,7 @@ func reportAppreciationHandler(reportAppreciationSvc reportappreciations.Service var reqData dto.ReportAppreciationReq err = json.NewDecoder(req.Body).Decode(&reqData) if err != nil { - logger.WithField("err", err.Error()).Error("Error while decoding request data") + logger.Errorf(req.Context(), "err while decoding request data, err: %v", err) dto.ErrorRepsonse(rw, err) return } @@ -68,14 +68,14 @@ func moderateAppreciation(reportAppreciationSvc reportappreciations.Service) htt } resolutionId, err := strconv.ParseInt(vars["id"], 10, 64) if err != nil { - logger.Errorf("error while parsing id, err: %s", err.Error()) + logger.Errorf(req.Context(), "error while parsing id, err: %s", err.Error()) err = apperrors.InternalServerError return } var reqData dto.ModerationReq err = json.NewDecoder(req.Body).Decode(&reqData) if err != nil { - logger.Errorf("error while decoding request data, err:%s", err.Error()) + logger.Errorf(req.Context(), "error while decoding request data, err:%s", err.Error()) dto.ErrorRepsonse(rw, err) return } @@ -99,14 +99,14 @@ func resolveAppreciation(reportAppreciationSvc reportappreciations.Service) http } resolutionId, err := strconv.ParseInt(vars["id"], 10, 64) if err != nil { - logger.Errorf("error while parsing id, err: %s", err.Error()) + logger.Errorf(req.Context(), "error while parsing id, err: %s", err.Error()) err = apperrors.InternalServerError return } var reqData dto.ModerationReq err = json.NewDecoder(req.Body).Decode(&reqData) if err != nil { - logger.Errorf("error while decoding request data, err:%s", err.Error()) + logger.Errorf(req.Context(), "error while decoding request data, err:%s", err.Error()) dto.ErrorRepsonse(rw, err) return } diff --git a/internal/api/reward.go b/internal/api/reward.go index 26d2044..52073a8 100644 --- a/internal/api/reward.go +++ b/internal/api/reward.go @@ -9,7 +9,7 @@ import ( "github.com/joshsoftware/peerly-backend/internal/app/reward" "github.com/joshsoftware/peerly-backend/internal/pkg/apperrors" "github.com/joshsoftware/peerly-backend/internal/pkg/dto" - logger "github.com/sirupsen/logrus" + log "github.com/joshsoftware/peerly-backend/internal/pkg/logger" ) @@ -22,25 +22,32 @@ func giveRewardHandler(rewardSvc reward.Service) http.HandlerFunc { return } + log.Info(req.Context(),"giveRewardHandler: request: ",req) + var reward dto.Reward err = json.NewDecoder(req.Body).Decode(&reward) if err != nil { - logger.Error("Error decoding request data:", err.Error()) + log.Error(req.Context(),"Error decoding request data:", err.Error()) dto.ErrorRepsonse(rw, apperrors.JSONParsingErrorReq) return } if reward.Point <1 || reward.Point >5 { + log.Error(req.Context(),"Invalid reward point") dto.ErrorRepsonse(rw,apperrors.InvalidRewardPoint) return } reward.AppreciationId = int64(apprId) resp, err := rewardSvc.GiveReward(req.Context(),reward) if err != nil { + log.Error(req.Context(),"resp err: ",err) dto.ErrorRepsonse(rw, err) return } + + log.Debug(req.Context(),"giveRewardHandler: resp: ",resp) + log.Info(req.Context(),"Reward given successfully") dto.SuccessRepsonse(rw, http.StatusCreated, "Reward given successfully", resp) }) } diff --git a/internal/api/router.go b/internal/api/router.go index e7c5d3b..125710a 100644 --- a/internal/api/router.go +++ b/internal/api/router.go @@ -22,18 +22,24 @@ func NewRouter(deps app.Dependencies) *mux.Router { router := mux.NewRouter() peerlySubrouter := router.PathPrefix("/peerly").Subrouter() + // Add the RequestIDMiddleware to the subrouter + peerlySubrouter.Use(middleware.RequestIDMiddleware) + peerlySubrouter.HandleFunc("/ping", pingHandler).Methods(http.MethodGet) + + peerlySubrouter.HandleFunc("/set_logger_level", loggerHandler).Methods(http.MethodPatch) + // Version 1 API management v1 := fmt.Sprintf("application/vnd.%s.v1", config.AppName()) //corevalues - peerlySubrouter.Handle("/core_values/{id:[0-9]+}", middleware.JwtAuthMiddleware(getCoreValueHandler(deps.CoreValueService), []string{constants.UserRole, constants.AdminRole})).Methods(http.MethodGet).Headers(versionHeader, v1) + peerlySubrouter.Handle("/core_values/{id:[0-9]+}", middleware.JwtAuthMiddleware(getCoreValueHandler(deps.CoreValueService), constants.User)).Methods(http.MethodGet).Headers(versionHeader, v1) - peerlySubrouter.Handle("/core_values", middleware.JwtAuthMiddleware(listCoreValuesHandler(deps.CoreValueService), []string{constants.UserRole, constants.AdminRole})).Methods(http.MethodGet).Headers(versionHeader, v1) + peerlySubrouter.Handle("/core_values", middleware.JwtAuthMiddleware(listCoreValuesHandler(deps.CoreValueService), constants.User)).Methods(http.MethodGet).Headers(versionHeader, v1) - peerlySubrouter.Handle("/core_values", middleware.JwtAuthMiddleware(createCoreValueHandler(deps.CoreValueService), []string{constants.AdminRole})).Methods(http.MethodPost).Headers(versionHeader, v1) + peerlySubrouter.Handle("/core_values", middleware.JwtAuthMiddleware(createCoreValueHandler(deps.CoreValueService), constants.Admin)).Methods(http.MethodPost).Headers(versionHeader, v1) - peerlySubrouter.Handle("/core_values/{id:[0-9]+}", middleware.JwtAuthMiddleware(updateCoreValueHandler(deps.CoreValueService), []string{constants.AdminRole})).Methods(http.MethodPut).Headers(versionHeader, v1) + peerlySubrouter.Handle("/core_values/{id:[0-9]+}", middleware.JwtAuthMiddleware(updateCoreValueHandler(deps.CoreValueService), constants.Admin)).Methods(http.MethodPut).Headers(versionHeader, v1) //users @@ -45,62 +51,60 @@ func NewRouter(deps app.Dependencies) *mux.Router { peerlySubrouter.Handle("/intranet/users", listIntranetUsersHandler(deps.UserService)).Methods(http.MethodGet) - peerlySubrouter.Handle("/users", middleware.JwtAuthMiddleware(listUsersHandler(deps.UserService), []string{constants.UserRole, constants.AdminRole})).Methods(http.MethodGet).Headers(versionHeader, v1) + peerlySubrouter.Handle("/users", middleware.JwtAuthMiddleware(listUsersHandler(deps.UserService), constants.User)).Methods(http.MethodGet).Headers(versionHeader, v1) - peerlySubrouter.Handle("/user_profile", middleware.JwtAuthMiddleware(getUserByIdHandler(deps.UserService), []string{constants.UserRole, constants.AdminRole})).Methods(http.MethodGet).Headers(versionHeader, v1) + peerlySubrouter.Handle("/user_profile", middleware.JwtAuthMiddleware(getUserByIdHandler(deps.UserService), constants.User)).Methods(http.MethodGet).Headers(versionHeader, v1) - peerlySubrouter.Handle("/users/active", middleware.JwtAuthMiddleware(getActiveUserListHandler(deps.UserService), []string{constants.UserRole, constants.AdminRole})).Methods(http.MethodGet) + peerlySubrouter.Handle("/users/active", middleware.JwtAuthMiddleware(getActiveUserListHandler(deps.UserService), constants.User)).Methods(http.MethodGet) - peerlySubrouter.Handle("/users/top10", middleware.JwtAuthMiddleware(getTop10UserHandler(deps.UserService), []string{constants.UserRole, constants.AdminRole})).Methods(http.MethodGet).Headers(versionHeader, v1) + peerlySubrouter.Handle("/users/top10", middleware.JwtAuthMiddleware(getTop10UserHandler(deps.UserService), constants.User)).Methods(http.MethodGet).Headers(versionHeader, v1) - peerlySubrouter.Handle("/admin/notification", middleware.JwtAuthMiddleware(adminNotificationHandler(deps.UserService), []string{constants.AdminRole})).Methods(http.MethodPost).Headers(versionHeader, v1) + peerlySubrouter.Handle("/admin/notification", middleware.JwtAuthMiddleware(adminNotificationHandler(deps.UserService), constants.Admin)).Methods(http.MethodPost).Headers(versionHeader, v1) - peerlySubrouter.Handle("/admin/appreciation_report", middleware.JwtAuthMiddleware(appreciationReportHandler(deps.UserService, deps.AppreciationService), []string{constants.AdminRole})).Methods(http.MethodGet) + peerlySubrouter.Handle("/admin/appreciation_report", middleware.JwtAuthMiddleware(appreciationReportHandler(deps.UserService, deps.AppreciationService), constants.Admin)).Methods(http.MethodGet) - peerlySubrouter.Handle("/admin/reported_appreciation_report", middleware.JwtAuthMiddleware(reportedAppreciationReportHandler(deps.UserService, deps.ReportAppreciationService), []string{constants.AdminRole})).Methods(http.MethodGet) + peerlySubrouter.Handle("/admin/reported_appreciation_report", middleware.JwtAuthMiddleware(reportedAppreciationReportHandler(deps.UserService, deps.ReportAppreciationService), constants.Admin)).Methods(http.MethodGet) //appreciations - peerlySubrouter.Handle("/appreciations/{id:[0-9]+}", middleware.JwtAuthMiddleware(getAppreciationByIDHandler(deps.AppreciationService), []string{constants.UserRole, constants.AdminRole})).Methods(http.MethodGet).Headers(versionHeader, v1) + peerlySubrouter.Handle("/appreciations/{id:[0-9]+}", middleware.JwtAuthMiddleware(getAppreciationByIDHandler(deps.AppreciationService), constants.User)).Methods(http.MethodGet).Headers(versionHeader, v1) - peerlySubrouter.Handle("/appreciations", middleware.JwtAuthMiddleware(listAppreciationsHandler(deps.AppreciationService), []string{constants.UserRole, constants.AdminRole})).Methods(http.MethodGet).Headers(versionHeader, v1) + peerlySubrouter.Handle("/appreciations", middleware.JwtAuthMiddleware(listAppreciationsHandler(deps.AppreciationService), constants.User)).Methods(http.MethodGet).Headers(versionHeader, v1) - peerlySubrouter.Handle("/appreciations/{id:[0-9]+}", middleware.JwtAuthMiddleware(deleteAppreciationHandler(deps.AppreciationService), []string{constants.AdminRole})).Methods(http.MethodDelete).Headers(versionHeader, v1) + peerlySubrouter.Handle("/appreciations/{id:[0-9]+}", middleware.JwtAuthMiddleware(deleteAppreciationHandler(deps.AppreciationService), constants.Admin)).Methods(http.MethodDelete).Headers(versionHeader, v1) - peerlySubrouter.Handle("/appreciations", middleware.JwtAuthMiddleware(createAppreciationHandler(deps.AppreciationService), []string{constants.UserRole, constants.AdminRole})).Methods(http.MethodPost).Headers(versionHeader, v1) + peerlySubrouter.Handle("/appreciations", middleware.JwtAuthMiddleware(createAppreciationHandler(deps.AppreciationService), constants.User)).Methods(http.MethodPost).Headers(versionHeader, v1) //report appreciation - peerlySubrouter.Handle("/report_appreciation/{id:[0-9]+}", middleware.JwtAuthMiddleware(reportAppreciationHandler(deps.ReportAppreciationService), []string{constants.UserRole, constants.AdminRole})).Methods(http.MethodPost).Headers(versionHeader, v1) + peerlySubrouter.Handle("/report_appreciation/{id:[0-9]+}", middleware.JwtAuthMiddleware(reportAppreciationHandler(deps.ReportAppreciationService), constants.User)).Methods(http.MethodPost).Headers(versionHeader, v1) - peerlySubrouter.Handle("/report_appreciations", middleware.JwtAuthMiddleware(listReportedAppreciations(deps.ReportAppreciationService), []string{constants.UserRole, constants.AdminRole})).Methods(http.MethodGet).Headers(versionHeader, v1) + peerlySubrouter.Handle("/report_appreciations", middleware.JwtAuthMiddleware(listReportedAppreciations(deps.ReportAppreciationService), constants.Admin)).Methods(http.MethodGet).Headers(versionHeader, v1) - peerlySubrouter.Handle("/moderate_appreciation/{id:[0-9]+}", middleware.JwtAuthMiddleware(moderateAppreciation(deps.ReportAppreciationService), []string{constants.AdminRole})).Methods(http.MethodPut).Headers(versionHeader, v1) + peerlySubrouter.Handle("/moderate_appreciation/{id:[0-9]+}", middleware.JwtAuthMiddleware(moderateAppreciation(deps.ReportAppreciationService), constants.Admin)).Methods(http.MethodPut).Headers(versionHeader, v1) - peerlySubrouter.Handle("/resolve_appreciation/{id:[0-9]+}", middleware.JwtAuthMiddleware(resolveAppreciation(deps.ReportAppreciationService), []string{constants.AdminRole})).Methods(http.MethodPut).Headers(versionHeader, v1) + peerlySubrouter.Handle("/resolve_appreciation/{id:[0-9]+}", middleware.JwtAuthMiddleware(resolveAppreciation(deps.ReportAppreciationService), constants.Admin)).Methods(http.MethodPut).Headers(versionHeader, v1) //grades - peerlySubrouter.Handle("/grades", middleware.JwtAuthMiddleware(listGradesHandler(deps.GradeService), []string{constants.UserRole, constants.AdminRole})).Methods(http.MethodGet).Headers(versionHeader, v1) + peerlySubrouter.Handle("/grades", middleware.JwtAuthMiddleware(listGradesHandler(deps.GradeService), constants.User)).Methods(http.MethodGet).Headers(versionHeader, v1) - peerlySubrouter.Handle("/grades/{id:[0-9]+}", middleware.JwtAuthMiddleware(editGradesHandler(deps.GradeService), []string{constants.AdminRole})).Methods(http.MethodPatch).Headers(versionHeader, v1) + peerlySubrouter.Handle("/grades/{id:[0-9]+}", middleware.JwtAuthMiddleware(editGradesHandler(deps.GradeService), constants.Admin)).Methods(http.MethodPatch).Headers(versionHeader, v1) // reward appreciation - peerlySubrouter.Handle("/reward/{id:[0-9]+}", middleware.JwtAuthMiddleware(giveRewardHandler(deps.RewardService), []string{constants.UserRole, constants.AdminRole})).Methods(http.MethodPost).Headers(versionHeader, v1) + peerlySubrouter.Handle("/reward/{id:[0-9]+}", middleware.JwtAuthMiddleware(giveRewardHandler(deps.RewardService), constants.User)).Methods(http.MethodPost).Headers(versionHeader, v1) // organization config - peerlySubrouter.Handle("/organizationconfig", middleware.JwtAuthMiddleware(getOrganizationConfigHandler(deps.OrganizationConfigService), []string{constants.AdminRole})).Methods(http.MethodGet).Headers(versionHeader, v1) + peerlySubrouter.Handle("/organizationconfig", middleware.JwtAuthMiddleware(getOrganizationConfigHandler(deps.OrganizationConfigService), constants.User)).Methods(http.MethodGet).Headers(versionHeader, v1) //organization config data inserted by seed file // peerlySubrouter.Handle("/organizationconfig", middleware.JwtAuthMiddleware(createOrganizationConfigHandler(deps.OrganizationConfigService),[]string{constants.UserRole})).Methods(http.MethodPost).Headers(versionHeader, v1) - peerlySubrouter.Handle("/organizationconfig", middleware.JwtAuthMiddleware(updateOrganizationConfigHandler(deps.OrganizationConfigService), []string{constants.AdminRole})).Methods(http.MethodPut).Headers(versionHeader, v1) - - peerlySubrouter.Handle("/organizationconfig", middleware.JwtAuthMiddleware(updateOrganizationConfigHandler(deps.OrganizationConfigService), []string{constants.AdminRole})).Methods(http.MethodPut).Headers(versionHeader, v1) + peerlySubrouter.Handle("/organizationconfig", middleware.JwtAuthMiddleware(updateOrganizationConfigHandler(deps.OrganizationConfigService), constants.Admin)).Methods(http.MethodPut).Headers(versionHeader, v1) //badges - peerlySubrouter.Handle("/badges", middleware.JwtAuthMiddleware(listBadgesHandler(deps.BadgeService), []string{constants.UserRole, constants.AdminRole})).Methods(http.MethodGet).Headers(versionHeader, v1) + peerlySubrouter.Handle("/badges", middleware.JwtAuthMiddleware(listBadgesHandler(deps.BadgeService), constants.User)).Methods(http.MethodGet).Headers(versionHeader, v1) - peerlySubrouter.Handle("/badges/{id:[0-9]+}", middleware.JwtAuthMiddleware(editBadgesHandler(deps.BadgeService), []string{constants.AdminRole})).Methods(http.MethodPatch).Headers(versionHeader, v1) + peerlySubrouter.Handle("/badges/{id:[0-9]+}", middleware.JwtAuthMiddleware(editBadgesHandler(deps.BadgeService), constants.Admin)).Methods(http.MethodPatch).Headers(versionHeader, v1) // No version requirement for /ping peerlySubrouter.HandleFunc("/ping", pingHandler).Methods(http.MethodGet) diff --git a/internal/api/user.go b/internal/api/user.go index 34db4e5..34fafa5 100644 --- a/internal/api/user.go +++ b/internal/api/user.go @@ -13,7 +13,8 @@ import ( "github.com/joshsoftware/peerly-backend/internal/pkg/apperrors" "github.com/joshsoftware/peerly-backend/internal/pkg/constants" "github.com/joshsoftware/peerly-backend/internal/pkg/dto" - logger "github.com/sirupsen/logrus" + log "github.com/joshsoftware/peerly-backend/internal/pkg/logger" + logger "github.com/joshsoftware/peerly-backend/internal/pkg/logger" ) func loginUser(userSvc user.Service) http.HandlerFunc { @@ -69,7 +70,7 @@ func loginAdmin(userSvc user.Service) http.HandlerFunc { var reqData dto.AdminLoginReq err := json.NewDecoder(req.Body).Decode(&reqData) if err != nil { - logger.Errorf("error while decoding request data. err: %s", err.Error()) + logger.Errorf(req.Context(), "error while decoding request data. err: %v", err) err = apperrors.JSONParsingErrorReq dto.ErrorRepsonse(rw, err) return @@ -93,9 +94,11 @@ func listIntranetUsersHandler(userSvc user.Service) http.HandlerFunc { return } + ctx := req.Context() + page := req.URL.Query().Get("page") if page == "" { - logger.Error("page query parameter is required") + logger.Error(ctx, "page query parameter is required") err := apperrors.PageParamNotFound dto.ErrorRepsonse(rw, err) return @@ -103,14 +106,12 @@ func listIntranetUsersHandler(userSvc user.Service) http.HandlerFunc { pageInt, err := strconv.ParseInt(page, 10, 64) if err != nil { - logger.Errorf("error page string to int64 conversion. err:%s ", err.Error()) + logger.Errorf(ctx, "error page string to int64 conversion. err:%s ", err.Error()) err = apperrors.InternalServerError dto.ErrorRepsonse(rw, err) return } - ctx := req.Context() - validateResp, err := userSvc.ValidatePeerly(ctx, authToken) if err != nil { dto.ErrorRepsonse(rw, err) @@ -134,10 +135,13 @@ func listIntranetUsersHandler(userSvc user.Service) http.HandlerFunc { func registerUser(userSvc user.Service) http.HandlerFunc { return func(rw http.ResponseWriter, req *http.Request) { + + ctx := req.Context() + var user dto.IntranetUserData err := json.NewDecoder(req.Body).Decode(&user) if err != nil { - logger.Errorf("error while decoding request data. err: %s", err.Error()) + logger.Errorf(ctx, "error while decoding request data. err: %s", err.Error()) err = apperrors.JSONParsingErrorReq dto.ErrorRepsonse(rw, err) return @@ -149,8 +153,6 @@ func registerUser(userSvc user.Service) http.HandlerFunc { return } - ctx := req.Context() - resp, err := userSvc.RegisterUser(ctx, user) if err != nil { dto.ErrorRepsonse(rw, err) @@ -169,9 +171,11 @@ func listUsersHandler(userSvc user.Service) http.HandlerFunc { dto.ErrorRepsonse(rw, err) return } + + ctx := req.Context() pageInt, err := strconv.ParseInt(page, 10, 64) if err != nil { - logger.Errorf("error in page string to int64 conversion, err:%s", err.Error()) + logger.Errorf(ctx, "error in page string to int64 conversion, err:%s", err.Error()) err = apperrors.InternalServerError dto.ErrorRepsonse(rw, err) } @@ -188,7 +192,7 @@ func listUsersHandler(userSvc user.Service) http.HandlerFunc { } else { perPageInt, err = strconv.ParseInt(perPage, 10, 64) if err != nil { - logger.Errorf("error in page size string to int64 conversion, err:%s", err.Error()) + logger.Errorf(ctx, "error in page size string to int64 conversion, err:%s", err.Error()) err = apperrors.InternalServerError dto.ErrorRepsonse(rw, err) } @@ -224,35 +228,42 @@ func listUsersHandler(userSvc user.Service) http.HandlerFunc { func getActiveUserListHandler(userSvc user.Service) http.HandlerFunc { return func(rw http.ResponseWriter, req *http.Request) { + log.Info(req.Context(), "getActiveUserListHandler: req: ", req) resp, err := userSvc.GetActiveUserList(req.Context()) if err != nil { dto.ErrorRepsonse(rw, err) return } + log.Debug(req.Context(), "getActiveUserListHandler: resp: ", resp) + log.Info(req.Context(),"Active Users list") dto.SuccessRepsonse(rw, http.StatusOK, "Active Users list", resp) } } func getUserByIdHandler(userSvc user.Service) http.HandlerFunc { return func(rw http.ResponseWriter, req *http.Request) { + log.Info(req.Context(),"getUserByIdHandler: request: ",req) resp, err := userSvc.GetUserById(req.Context()) if err != nil { + log.Errorf(req.Context(),"getUserByIdHandler: err: %v",err) dto.ErrorRepsonse(rw, err) return } + log.Info(req.Context(),) dto.SuccessRepsonse(rw, 200, "User fetched successfully", resp) - } } func getTop10UserHandler(userSvc user.Service) http.HandlerFunc { return func(rw http.ResponseWriter, req *http.Request) { + log.Info(req.Context(),"getTop10UserHandler: request: ",req) resp, err := userSvc.GetTop10Users(req.Context()) if err != nil { dto.ErrorRepsonse(rw, err) return } + log.Info(req.Context(),"Top 10 users fetched successfully") dto.SuccessRepsonse(rw, 200, "Top 10 users fetched successfully", resp) } } @@ -262,7 +273,7 @@ func adminNotificationHandler(userSvc user.Service) http.HandlerFunc { var notificationReq dto.AdminNotificationReq err := json.NewDecoder(req.Body).Decode(¬ificationReq) if err != nil { - logger.Errorf("error while decoding request data. err: %s", err.Error()) + logger.Errorf(req.Context(), "error while decoding request data. err: %s", err.Error()) err = apperrors.JSONParsingErrorReq dto.ErrorRepsonse(rw, err) return @@ -305,7 +316,6 @@ func appreciationReportHandler(userSvc user.Service, appreciationSvc appreciatio } } - func reportedAppreciationReportHandler(userSvc user.Service, reportAppreciationSvc reportappreciations.Service) http.HandlerFunc { return func(rw http.ResponseWriter, req *http.Request) { diff --git a/internal/app/appreciation/mocks/Service.go b/internal/app/appreciation/mocks/Service.go index b7daca4..2e6043b 100644 --- a/internal/app/appreciation/mocks/Service.go +++ b/internal/app/appreciation/mocks/Service.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.43.2. DO NOT EDIT. +// Code generated by mockery v1.0.0. DO NOT EDIT. package mocks @@ -7,6 +7,8 @@ import ( dto "github.com/joshsoftware/peerly-backend/internal/pkg/dto" mock "github.com/stretchr/testify/mock" + + repository "github.com/joshsoftware/peerly-backend/internal/repository" ) // Service is an autogenerated mock type for the Service type @@ -18,21 +20,14 @@ type Service struct { func (_m *Service) CreateAppreciation(ctx context.Context, _a1 dto.Appreciation) (dto.Appreciation, error) { ret := _m.Called(ctx, _a1) - if len(ret) == 0 { - panic("no return value specified for CreateAppreciation") - } - var r0 dto.Appreciation - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, dto.Appreciation) (dto.Appreciation, error)); ok { - return rf(ctx, _a1) - } if rf, ok := ret.Get(0).(func(context.Context, dto.Appreciation) dto.Appreciation); ok { r0 = rf(ctx, _a1) } else { r0 = ret.Get(0).(dto.Appreciation) } + var r1 error if rf, ok := ret.Get(1).(func(context.Context, dto.Appreciation) error); ok { r1 = rf(ctx, _a1) } else { @@ -46,10 +41,6 @@ func (_m *Service) CreateAppreciation(ctx context.Context, _a1 dto.Appreciation) func (_m *Service) DeleteAppreciation(ctx context.Context, apprId int32) error { ret := _m.Called(ctx, apprId) - if len(ret) == 0 { - panic("no return value specified for DeleteAppreciation") - } - var r0 error if rf, ok := ret.Get(0).(func(context.Context, int32) error); ok { r0 = rf(ctx, apprId) @@ -64,21 +55,14 @@ func (_m *Service) DeleteAppreciation(ctx context.Context, apprId int32) error { func (_m *Service) GetAppreciationById(ctx context.Context, appreciationId int32) (dto.AppreciationResponse, error) { ret := _m.Called(ctx, appreciationId) - if len(ret) == 0 { - panic("no return value specified for GetAppreciationById") - } - var r0 dto.AppreciationResponse - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, int32) (dto.AppreciationResponse, error)); ok { - return rf(ctx, appreciationId) - } if rf, ok := ret.Get(0).(func(context.Context, int32) dto.AppreciationResponse); ok { r0 = rf(ctx, appreciationId) } else { r0 = ret.Get(0).(dto.AppreciationResponse) } + var r1 error if rf, ok := ret.Get(1).(func(context.Context, int32) error); ok { r1 = rf(ctx, appreciationId) } else { @@ -92,21 +76,14 @@ func (_m *Service) GetAppreciationById(ctx context.Context, appreciationId int32 func (_m *Service) ListAppreciations(ctx context.Context, filter dto.AppreciationFilter) (dto.ListAppreciationsResponse, error) { ret := _m.Called(ctx, filter) - if len(ret) == 0 { - panic("no return value specified for ListAppreciations") - } - var r0 dto.ListAppreciationsResponse - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, dto.AppreciationFilter) (dto.ListAppreciationsResponse, error)); ok { - return rf(ctx, filter) - } if rf, ok := ret.Get(0).(func(context.Context, dto.AppreciationFilter) dto.ListAppreciationsResponse); ok { r0 = rf(ctx, filter) } else { r0 = ret.Get(0).(dto.ListAppreciationsResponse) } + var r1 error if rf, ok := ret.Get(1).(func(context.Context, dto.AppreciationFilter) error); ok { r1 = rf(ctx, filter) } else { @@ -116,26 +93,42 @@ func (_m *Service) ListAppreciations(ctx context.Context, filter dto.Appreciatio return r0, r1 } -// sendAppreciationEmail provides a mock function with given fields: to, sub, maildata -func (_m *Service) sendAppreciationEmail(to string, sub string, maildata string) error { - ret := _m.Called(to, sub, maildata) +// UpdateAppreciation provides a mock function with given fields: ctx +func (_m *Service) UpdateAppreciation(ctx context.Context) (bool, error) { + ret := _m.Called(ctx) - if len(ret) == 0 { - panic("no return value specified for sendAppreciationEmail") + var r0 bool + if rf, ok := ret.Get(0).(func(context.Context) bool); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(bool) } - var r0 error - if rf, ok := ret.Get(0).(func(string, string, string) error); ok { - r0 = rf(to, sub, maildata) + var r1 error + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) } else { - r0 = ret.Error(0) + r1 = ret.Error(1) } - return r0 + return r0, r1 +} + +// sendAppreciationNotificationToAll provides a mock function with given fields: ctx, appr +func (_m *Service) sendAppreciationNotificationToAll(ctx context.Context, appr repository.AppreciationResponse) { + _m.Called(ctx, appr) +} + +// sendAppreciationNotificationToReceiver provides a mock function with given fields: ctx, appr +func (_m *Service) sendAppreciationNotificationToReceiver(ctx context.Context, appr repository.AppreciationResponse) { + _m.Called(ctx, appr) +} + +// sendEmailForBadgeAllocation provides a mock function with given fields: userBadgeDetails +func (_m *Service) sendEmailForBadgeAllocation(userBadgeDetails []repository.UserBadgeDetails) { + _m.Called(userBadgeDetails) } -// NewService creates a new instance of Service. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. func NewService(t interface { mock.TestingT Cleanup(func()) diff --git a/internal/app/appreciation/service.go b/internal/app/appreciation/service.go index bedbc91..9bef084 100644 --- a/internal/app/appreciation/service.go +++ b/internal/app/appreciation/service.go @@ -8,11 +8,13 @@ import ( "github.com/joshsoftware/peerly-backend/internal/app/notification" user "github.com/joshsoftware/peerly-backend/internal/app/users" "github.com/joshsoftware/peerly-backend/internal/pkg/apperrors" + "github.com/joshsoftware/peerly-backend/internal/pkg/config" "github.com/joshsoftware/peerly-backend/internal/pkg/constants" "github.com/joshsoftware/peerly-backend/internal/pkg/dto" "github.com/joshsoftware/peerly-backend/internal/pkg/utils" "github.com/joshsoftware/peerly-backend/internal/repository" - logger "github.com/sirupsen/logrus" + + logger "github.com/joshsoftware/peerly-backend/internal/pkg/logger" ) type service struct { @@ -28,9 +30,6 @@ type Service interface { ListAppreciations(ctx context.Context, filter dto.AppreciationFilter) (dto.ListAppreciationsResponse, error) DeleteAppreciation(ctx context.Context, apprId int32) error UpdateAppreciation(ctx context.Context) (bool, error) - sendAppreciationNotificationToReceiver(ctx context.Context, appr repository.AppreciationResponse) - sendAppreciationNotificationToAll(ctx context.Context, appr repository.AppreciationResponse) - sendEmailForBadgeAllocation(userBadgeDetails []repository.UserBadgeDetails) } func NewService(appreciationRepo repository.AppreciationStorer, coreValuesRepo repository.CoreValueStorer, userRepo repository.UserStorer) Service { @@ -45,30 +44,34 @@ func (apprSvc *service) CreateAppreciation(ctx context.Context, appreciation dto //add quarter appreciation.Quarter = utils.GetQuarter() + logger.Debug(ctx,"service: CreateAppreciation: appreciation: ",appreciation) //add sender data := ctx.Value(constants.UserId) sender, ok := data.(int64) if !ok { - logger.Error("err in parsing userid from token") + logger.Error(ctx,"service: err in parsing userid from token") return dto.Appreciation{}, apperrors.InternalServer } //check is receiver present in database chk, err := apprSvc.appreciationRepo.IsUserPresent(ctx, nil, appreciation.Receiver) if err != nil { - logger.Errorf("err: %v", err) + logger.Errorf(ctx,"err: %v", err) return dto.Appreciation{}, err } if !chk { + logger.Errorf(ctx,"User not found (user_id): %v",appreciation.Receiver) return dto.Appreciation{}, apperrors.UserNotFound } appreciation.Sender = sender + logger.Debug(ctx,"service: appreciation: ",appreciation) //initializing database transaction tx, err := apprSvc.appreciationRepo.BeginTx(ctx) if err != nil { + logger.Errorf(ctx,"err: %v",err) return dto.Appreciation{}, err } @@ -76,7 +79,7 @@ func (apprSvc *service) CreateAppreciation(ctx context.Context, appreciation dto rvr := recover() defer func() { if rvr != nil { - logger.Info(ctx, "Transaction aborted because of panic: %v, Propagating panic further", rvr) + logger.Infof(ctx, "Transaction aborted because of panic: %v, Propagating panic further", rvr) panic(rvr) } }() @@ -84,7 +87,7 @@ func (apprSvc *service) CreateAppreciation(ctx context.Context, appreciation dto txErr := apprSvc.appreciationRepo.HandleTransaction(ctx, tx, err == nil && rvr == nil) if txErr != nil { err = txErr - logger.Info(ctx, "error in creating transaction, err: %s", txErr.Error()) + logger.Infof(ctx, "error in handle transaction, err: %s", txErr.Error()) return } }() @@ -92,45 +95,47 @@ func (apprSvc *service) CreateAppreciation(ctx context.Context, appreciation dto //check is corevalue present in database _, err = apprSvc.corevaluesRespo.GetCoreValue(ctx, int64(appreciation.CoreValueID)) if err != nil { - logger.Errorf("err: %v", err) + logger.Errorf(ctx,"service: err: %v", err) return dto.Appreciation{}, err } // check self appreciation if appreciation.Receiver == sender { + logger.Errorf(ctx,"Self Appreciation Error: %v \n Userid: %d",apperrors.SelfAppreciationError,appreciation.Receiver) return dto.Appreciation{}, apperrors.SelfAppreciationError } appr, err := apprSvc.appreciationRepo.CreateAppreciation(ctx, tx, appreciation) if err != nil { - logger.Errorf("err: %v", err) + logger.Errorf(ctx,"err: %v", err) return dto.Appreciation{}, err } res := mapAppreciationDBToDTO(appr) apprInfo, err := apprSvc.appreciationRepo.GetAppreciationById(ctx, tx, int32(res.ID)) if err != nil { - logger.Errorf("err: %v", err) + logger.Errorf(ctx,"err: %v", err) return res, nil } + logger.Debug(ctx,"service: createAppreciation result: ",res) quaterTimeStamp := user.GetQuarterStartUnixTime() reqGetUserById := dto.GetUserByIdReq{ UserId: sender, QuaterTimeStamp: quaterTimeStamp, } - senderInfo,err := apprSvc.userRepo.GetUserById(ctx,reqGetUserById) - if err != nil{ - logger.Info("error in getting create appreciation sender info") + senderInfo, err := apprSvc.userRepo.GetUserById(ctx, reqGetUserById) + if err != nil { + logger.Info(ctx,"error in getting create appreciation sender info") } reqGetUserById.UserId = appreciation.Receiver - receiverInfo,err := apprSvc.userRepo.GetUserById(ctx,reqGetUserById) - if err != nil{ - logger.Info("error in getting create appreciation sender info") + receiverInfo, err := apprSvc.userRepo.GetUserById(ctx, reqGetUserById) + if err != nil { + logger.Info(ctx,"error in getting create appreciation sender info") } - err = sendAppreciationEmail(apprInfo,senderInfo.Email,receiverInfo.Email) + err = sendAppreciationEmail(apprInfo, senderInfo.Email, receiverInfo.Email) apprSvc.sendAppreciationNotificationToReceiver(ctx, apprInfo) apprSvc.sendAppreciationNotificationToAll(ctx, apprInfo) return res, nil @@ -138,32 +143,37 @@ func (apprSvc *service) CreateAppreciation(ctx context.Context, appreciation dto func (apprSvc *service) GetAppreciationById(ctx context.Context, appreciationId int32) (dto.AppreciationResponse, error) { + logger.Debug(ctx,"service: appreciationId: ",appreciationId) resAppr, err := apprSvc.appreciationRepo.GetAppreciationById(ctx, nil, appreciationId) if err != nil { - logger.Errorf("err: %v", err) + logger.Errorf(ctx,"err: %v", err) return dto.AppreciationResponse{}, err } - + logger.Debug(ctx,"service: resAppr: ",resAppr) return mapRepoGetAppreciationInfoToDTOGetAppreciationInfo(resAppr), nil } func (apprSvc *service) ListAppreciations(ctx context.Context, filter dto.AppreciationFilter) (dto.ListAppreciationsResponse, error) { + logger.Debug(ctx,"service: filter: ",filter) infos, pagination, err := apprSvc.appreciationRepo.ListAppreciations(ctx, nil, filter) if err != nil { - logger.Errorf("err: %v", err) + logger.Errorf(ctx,"err: %v", err) return dto.ListAppreciationsResponse{}, err } + logger.Debug(ctx,"service: infos: ",infos," pagination: ",pagination) responses := make([]dto.AppreciationResponse, 0) for _, info := range infos { responses = append(responses, mapRepoGetAppreciationInfoToDTOGetAppreciationInfo(info)) } paginationResp := dtoPagination(pagination) + logger.Debug(ctx," apprSvc: ",responses," paginationResp: ",paginationResp) return dto.ListAppreciationsResponse{Appreciations: responses, MetaData: paginationResp}, nil } func (apprSvc *service) DeleteAppreciation(ctx context.Context, apprId int32) error { + logger.Debug(ctx,"service: apprId: ",apprId) return apprSvc.appreciationRepo.DeleteAppreciation(ctx, nil, apprId) } @@ -173,6 +183,7 @@ func (apprSvc *service) UpdateAppreciation(ctx context.Context) (bool, error) { tx, err := apprSvc.appreciationRepo.BeginTx(ctx) if err != nil { + logger.Errorf(ctx,"error in begin transaction: %v",err) return false, err } @@ -180,7 +191,7 @@ func (apprSvc *service) UpdateAppreciation(ctx context.Context) (bool, error) { rvr := recover() defer func() { if rvr != nil { - logger.Info(ctx, "Transaction aborted because of panic: %v, Propagating panic further", rvr) + logger.Infof(ctx, "Transaction aborted because of panic: %v, Propagating panic further", rvr) panic(rvr) } }() @@ -188,7 +199,7 @@ func (apprSvc *service) UpdateAppreciation(ctx context.Context) (bool, error) { txErr := apprSvc.appreciationRepo.HandleTransaction(ctx, tx, err == nil && rvr == nil) if txErr != nil { err = txErr - logger.Info(ctx, "error in creating transaction, err: %s", txErr.Error()) + logger.Infof(ctx, "error in handle transaction, err: %s", txErr.Error()) return } }() @@ -196,16 +207,17 @@ func (apprSvc *service) UpdateAppreciation(ctx context.Context) (bool, error) { _, err = apprSvc.appreciationRepo.UpdateAppreciationTotalRewardsOfYesterday(ctx, tx) if err != nil { - logger.Error("err: ", err.Error()) + logger.Errorf(ctx,"err: %v", err) return false, err } + logger.Debug(ctx,"service: UpdateAppreciationTotalRewardsOfYesterday completed") userBadgeDetails, err := apprSvc.appreciationRepo.UpdateUserBadgesBasedOnTotalRewards(ctx, tx) if err != nil { - logger.Error("err: ", err.Error()) + logger.Error(ctx,"err: ", err.Error()) return false, err } - + logger.Debug(ctx,"service: UpdateAppreciation: ",userBadgeDetails) apprSvc.sendEmailForBadgeAllocation(userBadgeDetails) return true, nil } @@ -214,40 +226,51 @@ func sendAppreciationEmail(emailData repository.AppreciationResponse,senderEmail templateData := struct { SenderName string - ReceiverName string + ReceiverName string Description string CoreValueName string CoreValueBackgroundColor string + ReceiverIconImageURL string + SenderIconImageURL string }{ SenderName: fmt.Sprint(emailData.SenderFirstName, " ", emailData.SenderLastName), - ReceiverName: fmt.Sprint(emailData.ReceiverFirstName, " ", emailData.ReceiverLastName), + ReceiverName: fmt.Sprint(emailData.ReceiverFirstName, " ", emailData.ReceiverLastName), Description: emailData.Description, CoreValueName: emailData.CoreValueName, CoreValueBackgroundColor: utils.GetCoreValueBackgroundColor(emailData.CoreValueName), + ReceiverIconImageURL: fmt.Sprint(config.PeerlyBaseUrl()+constants.ClosedEnvelopeIconImagePath), + SenderIconImageURL: fmt.Sprint(config.PeerlyBaseUrl()+constants.OpenEnvelopeIconImagePath), } - logger.Info("appreciation sender email: -----------> ",senderEmail) - logger.Info("appreciation receiver email: -----------> ",receiverEmail) - mailReq := email.NewMail([]string{receiverEmail}, []string{}, []string{}, fmt.Sprintf("Kudos! You've Been Praised by %s %s! 🎉 ",emailData.SenderFirstName,emailData.SenderLastName)) - err := mailReq.ParseTemplate("./internal/app/email/templates/receiverAppreciation.html", templateData) + tos := []string{receiverEmail} + ccs := []string{} + bccs := []string{} + sub := fmt.Sprintf("Kudos! You've Been Praised by %s %s! 🎉 ",emailData.SenderFirstName,emailData.SenderLastName) + body,err := email.ParseTemplate("./internal/app/email/templates/receiverAppreciation.html", templateData) if err != nil { - logger.Errorf("err in creating html file : %v", err) + logger.Errorf(context.Background(),"err in creating receiverAppreciation.html file : %v", err) return err } + mailReq := email.NewMail(tos, ccs, bccs, sub,body) err = mailReq.Send() if err != nil { - logger.Errorf("err: %v", err) + logger.Errorf(context.Background(),"err: %v", err) return err } - mailReq = email.NewMail([]string{senderEmail}, []string{}, []string{}, fmt.Sprintf("Your appreciation to %s %s has been sent! 🙌",emailData.ReceiverFirstName,emailData.ReceiverLastName)) - err = mailReq.ParseTemplate("./internal/app/email/templates/senderAppreciation.html", templateData) + + tos = []string{senderEmail} + ccs = []string{} + bccs = []string{} + sub = fmt.Sprintf("Your appreciation to %s %s has been sent! 🙌",emailData.ReceiverFirstName,emailData.ReceiverLastName) + body,err = email.ParseTemplate("./internal/app/email/templates/senderAppreciation.html", templateData) if err != nil { - logger.Errorf("err: %v",err) + logger.Errorf(context.Background(),"err in creating senderAppreciation.html file : %v", err) return err } + mailReq = email.NewMail(tos, ccs, bccs, sub,body) err = mailReq.Send() if err != nil { - logger.Errorf("err: %v", err) + logger.Errorf(context.Background(),"err: %v", err) return err } return nil @@ -255,17 +278,20 @@ func sendAppreciationEmail(emailData repository.AppreciationResponse,senderEmail func (apprSvc *service) sendAppreciationNotificationToReceiver(ctx context.Context, appr repository.AppreciationResponse) { + logger.Debug(ctx,"service: apprResponse: ",appr) notificationTokens, err := apprSvc.userRepo.ListDeviceTokensByUserID(ctx, appr.ReceiverID) if err != nil { - logger.Errorf("err in getting device tokens: %v", err) + logger.Errorf(ctx,"err in getting device tokens: %v", err) return } + logger.Debug(ctx,"apprSvc: notificationTokens: ",notificationTokens) msg := notification.Message{ Title: "Appreciation incoming!", Body: fmt.Sprintf("You've been appreciated by %s %s! Well done and keep up the JOSH!", appr.SenderFirstName, appr.SenderLastName), } + logger.Infof(ctx,"message: %v",msg) for _, notificationToken := range notificationTokens { msg.SendNotificationToNotificationToken(notificationToken) } @@ -274,29 +300,31 @@ func (apprSvc *service) sendAppreciationNotificationToReceiver(ctx context.Conte func (apprSvc *service) sendAppreciationNotificationToAll(ctx context.Context, appr repository.AppreciationResponse) { + logger.Debug(ctx," apprSvc: appr: ",appr) msg := notification.Message{ Title: "Appreciation", Body: fmt.Sprintf(" %s %s appreciated %s %s", appr.SenderFirstName, appr.SenderLastName, appr.ReceiverFirstName, appr.ReceiverLastName), } + logger.Infof(ctx,"message: %v",msg) msg.SendNotificationToTopic("peerly") } func (apprSvc *service) sendEmailForBadgeAllocation(userBadgeDetails []repository.UserBadgeDetails) { - logger.Info("user Badge Details:---------------->\n ", userBadgeDetails) + logger.Debug(context.Background(),"service: user Badge Details: ", userBadgeDetails) for _, userBadgeDetail := range userBadgeDetails { // Determine the BadgeImageUrl based on the BadgeName var badgeImageUrl string switch userBadgeDetail.BadgeName.String { case "Bronze": - badgeImageUrl = "bronzeBadge" + badgeImageUrl = fmt.Sprint(config.PeerlyBaseUrl()+constants.BronzeBadgeIconImagePath) case "Silver": - badgeImageUrl = "silverBadge" + badgeImageUrl = fmt.Sprint(config.PeerlyBaseUrl()+constants.SilverBadgeIconImagePath) case "Gold": - badgeImageUrl = "goldBadge" + badgeImageUrl = fmt.Sprint(config.PeerlyBaseUrl()+constants.GoldBadgeIconImagePath) case "Platinum": - badgeImageUrl = "platinumBadge" + badgeImageUrl = fmt.Sprint(config.PeerlyBaseUrl()+constants.PlatinumIconImagePath) } // repository.UserBadgeDetails @@ -311,18 +339,24 @@ func (apprSvc *service) sendEmailForBadgeAllocation(userBadgeDetails []repositor BadgeImageName: badgeImageUrl, AppreciationPoints: userBadgeDetail.BadgePoints, } - logger.Info("badge data: ", templateData) - mailReq := email.NewMail([]string{userBadgeDetail.Email}, []string{}, []string{}, fmt.Sprintf("You've Bagged the %s for Crushing %d Points! 🏆",userBadgeDetail.BadgeName.String, userBadgeDetail.BadgePoints)) - err := mailReq.ParseTemplate("./internal/app/email/templates/badge.html", templateData) + logger.Info(context.Background(),"badge data: ", templateData) + + tos := []string{userBadgeDetail.Email} + ccs := []string{} + bccs := []string{} + sub := fmt.Sprintf("You've Bagged the %s for Crushing %d Points! 🏆",userBadgeDetail.BadgeName.String, userBadgeDetail.BadgePoints) + body, err := email.ParseTemplate("./internal/app/email/templates/badge.html", templateData) if err != nil { - logger.Errorf("err in creating html file : %v", err) + logger.Errorf(context.Background(),"err in creating badge.html file : %v", err) return } + + mailReq := email.NewMail(tos, ccs, bccs, sub,body) err = mailReq.Send() if err != nil { - logger.Errorf("err: %v", err) + logger.Errorf(context.Background(),"service: err: %v", err) return } + logger.Infof(context.Background(),"service: mail request: %v",mailReq) } - return } diff --git a/internal/app/appreciation/service_test.go b/internal/app/appreciation/service_test.go index 5a3a28a..bbd0526 100644 --- a/internal/app/appreciation/service_test.go +++ b/internal/app/appreciation/service_test.go @@ -18,7 +18,8 @@ import ( func TestCreateAppreciation(t *testing.T) { appreciationRepo := mocks.NewAppreciationStorer(t) corevalueRepo := mocks.NewCoreValueStorer(t) - service := NewService(appreciationRepo, corevalueRepo) + userRepo := mocks.NewUserStorer(t) + service := NewService(appreciationRepo, corevalueRepo, userRepo) tests := []struct { name string @@ -41,11 +42,11 @@ func TestCreateAppreciation(t *testing.T) { apprMock.On("IsUserPresent", mock.Anything, nil, int64(2)).Return(true, nil).Once() apprMock.On("BeginTx", mock.Anything).Return(tx, nil).Once() coreValueRepo.On("GetCoreValue", mock.Anything, int64(1)).Return(repository.CoreValue{ - ID: 1, - Name:"Trust", - Description:"We foster trust by being transparent,reliable, and accountable in all our actions", - ParentCoreValueID:sql.NullInt64{Int64:int64(0),Valid: true}, - }, nil).Once() + ID: 1, + Name: "Trust", + Description: "We foster trust by being transparent,reliable, and accountable in all our actions", + ParentCoreValueID: sql.NullInt64{Int64: int64(0), Valid: true}, + }, nil).Once() apprMock.On("CreateAppreciation", mock.Anything, tx, mock.Anything).Return(repository.Appreciation{ID: 1}, nil).Once() apprMock.On("HandleTransaction", mock.Anything, tx, true).Return(nil).Once() }, @@ -110,7 +111,9 @@ func TestCreateAppreciation(t *testing.T) { func TestGetAppreciationById(t *testing.T) { appreciationRepo := mocks.NewAppreciationStorer(t) - service := NewService(appreciationRepo, nil) + coreVaueRepo := mocks.NewCoreValueStorer(t) + userRepo := mocks.NewUserStorer(t) + service := NewService(appreciationRepo, coreVaueRepo, userRepo) tests := []struct { name string @@ -210,7 +213,9 @@ func TestGetAppreciationById(t *testing.T) { func TestValidateAppreciation(t *testing.T) { appreciationRepo := mocks.NewAppreciationStorer(t) - service := NewService(appreciationRepo, nil) + coreVaueRepo := mocks.NewCoreValueStorer(t) + userRepo := mocks.NewUserStorer(t) + service := NewService(appreciationRepo, coreVaueRepo, userRepo) tests := []struct { name string diff --git a/internal/app/badges/service.go b/internal/app/badges/service.go index c096e44..5b36325 100644 --- a/internal/app/badges/service.go +++ b/internal/app/badges/service.go @@ -8,9 +8,9 @@ import ( "github.com/joshsoftware/peerly-backend/internal/pkg/apperrors" "github.com/joshsoftware/peerly-backend/internal/pkg/constants" "github.com/joshsoftware/peerly-backend/internal/pkg/dto" + logger "github.com/joshsoftware/peerly-backend/internal/pkg/logger" "github.com/joshsoftware/peerly-backend/internal/pkg/utils" "github.com/joshsoftware/peerly-backend/internal/repository" - logger "github.com/sirupsen/logrus" ) type service struct { @@ -38,7 +38,7 @@ func (bs *service) ListBadges(ctx context.Context) ([]dto.Badge, error) { dbResp, err := bs.badgesRepo.ListBadges(ctx) if err != nil { - logger.Error(err.Error()) + logger.Error(ctx, err.Error()) err = apperrors.InternalServerError return nil, err } @@ -75,7 +75,7 @@ func (gs *service) EditBadge(ctx context.Context, id string, rewardPoints int64) var reqData dto.UpdateBadgeReq reqData.Id = badgeId if rewardPoints < 0 { - logger.Errorf("badge reward points cannot be negative, reward points: %d", rewardPoints) + logger.Errorf(ctx, "badge reward points cannot be negative, reward points: %d", rewardPoints) err = apperrors.NegativeBadgePoints return } @@ -83,14 +83,14 @@ func (gs *service) EditBadge(ctx context.Context, id string, rewardPoints int64) userId := ctx.Value(constants.UserId) data, ok := userId.(int64) if !ok { - logger.Error("Error in typecasting user id") + logger.Error(context.Background(),"Error in typecasting user id") err = apperrors.InternalServerError return } reqData.UserId = data err = gs.badgesRepo.EditBadge(ctx, reqData) if err != nil { - logger.Error(err.Error()) + logger.Error(ctx, err.Error()) err = apperrors.InternalServerError return } diff --git a/internal/app/coreValues/service.go b/internal/app/coreValues/service.go index 6f2f2aa..ae4b0cc 100644 --- a/internal/app/coreValues/service.go +++ b/internal/app/coreValues/service.go @@ -5,9 +5,9 @@ import ( "github.com/joshsoftware/peerly-backend/internal/pkg/apperrors" "github.com/joshsoftware/peerly-backend/internal/pkg/dto" + logger "github.com/joshsoftware/peerly-backend/internal/pkg/logger" "github.com/joshsoftware/peerly-backend/internal/pkg/utils" "github.com/joshsoftware/peerly-backend/internal/repository" - logger "github.com/sirupsen/logrus" ) type service struct { @@ -31,8 +31,9 @@ func (cs *service) ListCoreValues(ctx context.Context) (resp []dto.CoreValue, er dbResp, err := cs.coreValuesRepo.ListCoreValues(ctx) if err != nil { - logger.Error(err.Error()) + logger.Error(ctx, err.Error()) err = apperrors.InternalServerError + return } for _, value := range dbResp { @@ -65,7 +66,7 @@ func (cs *service) CreateCoreValue(ctx context.Context, coreValue dto.CreateCore isUnique, err := cs.coreValuesRepo.CheckUniqueCoreVal(ctx, coreValue.Name) if err != nil { - logger.Error(err.Error()) + logger.Error(ctx, err.Error()) err = apperrors.InternalServerError return } @@ -81,7 +82,7 @@ func (cs *service) CreateCoreValue(ctx context.Context, coreValue dto.CreateCore dbResp, err := cs.coreValuesRepo.CreateCoreValue(ctx, coreValue) if err != nil { - logger.Error(err.Error()) + logger.Error(ctx, err.Error()) err = apperrors.InternalServerError return } @@ -115,7 +116,7 @@ func (cs *service) UpdateCoreValue(ctx context.Context, coreValueID string, reqD isUnique, err := cs.coreValuesRepo.CheckUniqueCoreVal(ctx, reqData.Name) if err != nil { - logger.Error(err.Error()) + logger.Error(ctx, err.Error()) err = apperrors.InternalServerError return } @@ -128,7 +129,7 @@ func (cs *service) UpdateCoreValue(ctx context.Context, coreValueID string, reqD dbResp, err := cs.coreValuesRepo.UpdateCoreValue(ctx, reqData) if err != nil { - logger.Error(err.Error()) + logger.Error(ctx, err.Error()) err = apperrors.InternalServerError return @@ -142,12 +143,12 @@ func (cs *service) UpdateCoreValue(ctx context.Context, coreValueID string, reqD func (cs *service) validateParentCoreValue(ctx context.Context, coreValueID int64) (ok bool) { coreValue, err := cs.coreValuesRepo.GetCoreValue(ctx, coreValueID) if err != nil { - logger.Errorf("parent core value id not present, err: %s", err.Error()) + logger.Errorf(ctx, "parent core value id not present, err: %s", err.Error()) return } if coreValue.ParentCoreValueID.Valid { - logger.Error("Invalid parent core value id") + logger.Error(ctx, "Invalid parent core value id") return } diff --git a/internal/app/cronjob/cronJob.go b/internal/app/cronjob/cronJob.go index 139dd43..bd0f47b 100644 --- a/internal/app/cronjob/cronJob.go +++ b/internal/app/cronjob/cronJob.go @@ -5,8 +5,9 @@ import ( "time" "github.com/go-co-op/gocron/v2" - logger "github.com/sirupsen/logrus" + logger "github.com/joshsoftware/peerly-backend/internal/pkg/logger" ) + type Job interface { // Schedules the cron job Schedule() @@ -29,9 +30,9 @@ func (cron *CronJob) Execute(task func(context.Context)) { ctx := context.Background() startTime := time.Now() - logger.Info("cron job Started at %s", startTime.Format("2006-01-02 15:04:05")) + logger.Infof(ctx,"cron job Started at %s", startTime.Format("2006-01-02 15:04:05")) defer func() { - logger.Info("cron job done %s, took: %v", cron.name, time.Since(startTime)) + logger.Infof(ctx,"cron job done %s, took: %v", cron.name, time.Since(startTime)) }() // Channel to check if signal task is completed diff --git a/internal/app/cronjob/monthlyUpdateData.go b/internal/app/cronjob/monthlyUpdateData.go index c164743..9e51ae9 100644 --- a/internal/app/cronjob/monthlyUpdateData.go +++ b/internal/app/cronjob/monthlyUpdateData.go @@ -2,20 +2,20 @@ package cronjob import ( "context" + "github.com/go-co-op/gocron/v2" "github.com/joshsoftware/peerly-backend/internal/app/notification" user "github.com/joshsoftware/peerly-backend/internal/app/users" - "time" - - logger "github.com/sirupsen/logrus" + "github.com/joshsoftware/peerly-backend/internal/pkg/constants" + logger "github.com/joshsoftware/peerly-backend/internal/pkg/logger" ) const MONTHLY_JOB = "MONTHLY_JOB" const MONTHLY_CRON_JOB_INTERVAL_MONTHS = 1 var MonthlyJobTiming = JobTime{ - hours: 0, - minutes: 0, + hours: 23, + minutes: 59, seconds: 0, } @@ -36,39 +36,13 @@ func NewMontlyJob(userSvc user.Service, scheduler gocron.Scheduler) Job { func (cron *MonthlyJob) Schedule() { var err error - - // Load the location for Asia/Kolkata - location, err := time.LoadLocation("Asia/Kolkata") - if err != nil { - logger.Warn(context.TODO(), "error loading location: %+v", err.Error()) - return - } - - // Get the current date in Asia/Kolkata - currentTimeInKolkata := time.Now().In(location) - - // Create a new time for today's date with MonthlyJobTiming hours, minutes, and seconds - jobTimeInKolkata := time.Date( - currentTimeInKolkata.Year(), // Year: current year - currentTimeInKolkata.Month(), // Month: current month - currentTimeInKolkata.Day(), // Day: today's date - int(MonthlyJobTiming.hours), // Hour: from MonthlyJobTiming - int(MonthlyJobTiming.minutes), // Minute: from MonthlyJobTiming - int(MonthlyJobTiming.seconds), // Second: from MonthlyJobTiming - 0, // Nanosecond: 0 - location, // Timezone: Asia/Kolkata - ) - - // Convert to UTC - jobTimeInUTC := jobTimeInKolkata.UTC() - cron.job, err = cron.scheduler.NewJob( gocron.MonthlyJob(MONTHLY_CRON_JOB_INTERVAL_MONTHS, gocron.NewDaysOfTheMonth(-1), gocron.NewAtTimes( gocron.NewAtTime( - uint(jobTimeInUTC.Hour()), - uint(jobTimeInUTC.Minute()), - uint(jobTimeInUTC.Second()), + MonthlyJobTiming.hours, + MonthlyJobTiming.minutes, + MonthlyJobTiming.seconds, ), )), gocron.NewTask(cron.Execute, cron.Task), @@ -76,17 +50,20 @@ func (cron *MonthlyJob) Schedule() { ) cron.scheduler.Start() if err != nil { - logger.Warn(context.TODO(), "error occurred while scheduling %s, message %+v", cron.name, err.Error()) + logger.Warn(context.Background(), "error occurred while scheduling %s, message %+v", cron.name, err.Error()) } } func (cron *MonthlyJob) Task(ctx context.Context) { + ctx = context.WithValue(ctx, constants.RequestID, "monthlyUpdate") logger.Info(ctx, "in monthly job task") for i := 0; i < 3; i++ { - logger.Info("cron job attempt:", i+1) + logger.Info(ctx,"cron job attempt:", i+1) err := cron.userService.UpdateRewardQuota(ctx) + logger.Error(ctx,"err: ",err) if err == nil { sendRewardQuotaRefilledNotificationToAll() + logger.Info(ctx,"cronjob: monthly task completed") break } } @@ -98,5 +75,7 @@ func sendRewardQuotaRefilledNotificationToAll() { Title: "🚀 Reward Quota Reset! ", Body: "Quota for Rewards Renewed. Time to Shower Your Peers with Kudos! 🎁", } + + logger.Debug(context.Background(),"msg:",msg) msg.SendNotificationToTopic("peerly") } diff --git a/internal/app/cronjob/updateDailyData.go b/internal/app/cronjob/updateDailyData.go index 6dd7424..9913178 100644 --- a/internal/app/cronjob/updateDailyData.go +++ b/internal/app/cronjob/updateDailyData.go @@ -2,10 +2,12 @@ package cronjob import ( "context" - "time" + "fmt" + "github.com/go-co-op/gocron/v2" apprSvc "github.com/joshsoftware/peerly-backend/internal/app/appreciation" - logger "github.com/sirupsen/logrus" + "github.com/joshsoftware/peerly-backend/internal/pkg/constants" + logger "github.com/joshsoftware/peerly-backend/internal/pkg/logger" ) const DAILY_JOB = "DAILY_JOB" @@ -36,40 +38,15 @@ func NewDailyJob( } func (cron *DailyJob) Schedule() { - var err error - // Load the location for Asia/Kolkata - location, err := time.LoadLocation("Asia/Kolkata") - if err != nil { - logger.Warn(context.TODO(), "error loading location: %+v", err.Error()) - return - } - - // Get the current date in Asia/Kolkata - currentTimeInKolkata := time.Now().In(location) - - // Create a new time for today's date with MonthlyJobTiming hours, minutes, and seconds - jobTimeInKolkata := time.Date( - currentTimeInKolkata.Year(), // Year: current year - currentTimeInKolkata.Month(), // Month: current month - currentTimeInKolkata.Day(), // Day: today's date - int(MonthlyJobTiming.hours), // Hour: from MonthlyJobTiming - int(MonthlyJobTiming.minutes), // Minute: from MonthlyJobTiming - int(MonthlyJobTiming.seconds), // Second: from MonthlyJobTiming - 0, // Nanosecond: 0 - location, // Timezone: Asia/Kolkata - ) - // Convert to UTC - jobTimeInUTC := jobTimeInKolkata.UTC() - cron.job, err = cron.scheduler.NewJob( gocron.DailyJob( SAY_HELLO_DAILY_CRON_JOB_INTERVAL_DAYS, gocron.NewAtTimes( gocron.NewAtTime( - uint(jobTimeInUTC.Hour()), - uint(jobTimeInUTC.Minute()), - uint(jobTimeInUTC.Second()), + SayHelloDailyJobTiming.hours, + SayHelloDailyJobTiming.minutes, + SayHelloDailyJobTiming.seconds, ), ), ), @@ -79,16 +56,19 @@ func (cron *DailyJob) Schedule() { cron.scheduler.Start() if err != nil { - logger.Warn(context.TODO(), "error occurred while scheduling %s, message %+v", cron.name, err.Error()) + logger.Warn(context.TODO(), fmt.Sprintf("error occurred while scheduling %s, message %+v", cron.name, err.Error())) } } - func (cron *DailyJob) Task(ctx context.Context) { + ctx = context.WithValue(ctx, constants.RequestID, "dailyUpdate") logger.Info(ctx, "in daily job task") - for i := 0; i < 3; i++ { - logger.Info("cron job attempt:", i+1) - isSuccess, err := cron.appreciationService.UpdateAppreciation(ctx) - if err == nil && isSuccess { + for i:=0;i<3;i++{ + logger.Info(ctx,"cron job attempt:",i+1) + isSuccess,err := cron.appreciationService.UpdateAppreciation(ctx) + + logger.Info(ctx," isSuccess: ",isSuccess," err: ",err) + if err==nil && isSuccess{ + logger.Info(ctx,"cronjob: UpdateDaily data completed") break } } diff --git a/internal/app/email/helper.go b/internal/app/email/helper.go new file mode 100644 index 0000000..b38272e --- /dev/null +++ b/internal/app/email/helper.go @@ -0,0 +1,17 @@ +package email + +import ( + "bytes" + "html/template" +) +func ParseTemplate(templateFileName string, data interface{})(string, error) { + t, err := template.ParseFiles(templateFileName) + if err != nil { + return "",err + } + buf := new(bytes.Buffer) + if err = t.Execute(buf, data); err != nil { + return "",err + } + return buf.String(),nil +} \ No newline at end of file diff --git a/internal/app/email/service.go b/internal/app/email/service.go index 6ad2975..151d09d 100644 --- a/internal/app/email/service.go +++ b/internal/app/email/service.go @@ -1,20 +1,19 @@ package email import ( - "bytes" + "context" "fmt" - "html/template" + "github.com/joshsoftware/peerly-backend/internal/pkg/apperrors" "github.com/joshsoftware/peerly-backend/internal/pkg/config" + logger "github.com/joshsoftware/peerly-backend/internal/pkg/logger" "github.com/sendgrid/sendgrid-go" "github.com/sendgrid/sendgrid-go/helpers/mail" - logger "github.com/sirupsen/logrus" ) // MailService represents the interface for our mail service. type MailService interface { Send() error - ParseTemplate(templateFileName string, data interface{}) error } // Mail represents a email request @@ -23,26 +22,26 @@ type Mail struct { to []string subject string body string - CC []string - BCC []string + cc []string + bcc []string } func (ms *Mail) Send() error { - senderEmail := config.ReadEnvString("SENDER_EMAIL") - if senderEmail == "" { - logger.Error("SENDER_EMAIL environment variable is not set") - return fmt.Errorf("sender email not configured") - } + logger.Info(context.Background(), " Mail: ", ms) sendGridAPIKey := config.ReadEnvString("SENDGRID_API_KEY") if sendGridAPIKey == "" { - logger.Error("SENDGRID_API_KEY environment variable is not set") + logger.Error(context.Background(), "SENDGRID_API_KEY environment variable is not set") return fmt.Errorf("sendgrid API key not configured") } - logger.Info("from_------------->, ",senderEmail) - fromEmail := mail.NewEmail("Peerly", senderEmail) + err := ms.validateMail() + if err != nil { + logger.Errorf(context.Background(),"err: error in mail validation: %v",err) + return err + } + fromEmail := mail.NewEmail("Peerly", ms.from) content := mail.NewContent("text/html", ms.body) // create new *SGMailV3 @@ -52,21 +51,21 @@ func (ms *Mail) Send() error { personalization := mail.NewPersonalization() - for _,email := range ms.to{ + for _, email := range ms.to { toEmail := mail.NewEmail("to", email) personalization.AddTos(toEmail) } - for _,email := range ms.CC{ + for _, email := range ms.cc { ccEmail := mail.NewEmail("cc", email) personalization.AddCCs(ccEmail) } - for _,email := range ms.BCC{ + for _, email := range ms.bcc { bccEmail := mail.NewEmail("bcc", email) personalization.AddBCCs(bccEmail) } - + personalization.Subject = ms.subject m.AddPersonalizations(personalization) @@ -74,39 +73,43 @@ func (ms *Mail) Send() error { response, err := client.Send(m) if err != nil { - logger.Error("unable to send mail", "error", err) + logger.Error(context.Background(), "unable to send mail", "error", err) return err } - logger.Info("Email request sent successfully!") - logger.Infof("Response status code: %v", response.StatusCode) - logger.Infof("Response body: %v", response.Body) - logger.Infof("Response headers: %v", response.Headers) + logger.Infof(context.Background(),"email sent successfully to %v ",ms.to) + logger.Debug(context.Background(), "Email response: %v ",response) return nil } -func (r *Mail) ParseTemplate(templateFileName string, data interface{}) error { - t, err := template.ParseFiles(templateFileName) - if err != nil { - return err - } - buf := new(bytes.Buffer) - if err = t.Execute(buf, data); err != nil { - return err - } - r.body = buf.String() - logger.Info("--------------------->") - logger.Info(r.body) - logger.Info("--------------------->") - return nil + +func (ms *Mail) validateMail() error { + if len(ms.to) == 0 { + return apperrors.InvalidTos + } + + if len(ms.from) == 0 { + return apperrors.InvalidFrom + } + + if len(ms.body) == 0 { + return apperrors.InvalidBody + } + + if len(ms.subject) == 0 { + return apperrors.InvalidSub + } + + return nil } // NewMail returns a new mail request. -func NewMail(to []string, cc []string, bcc []string, subject string) MailService { +func NewMail(to []string, cc []string, bcc []string, subject string, body string) MailService { return &Mail{ from: config.ReadEnvString("SENDER_EMAIL"), to: to, - CC: cc, - BCC: bcc, + cc: cc, + bcc: bcc, subject: subject, + body: body, } } diff --git a/internal/app/email/templates/badge.html b/internal/app/email/templates/badge.html index 9d50d96..b894a29 100644 --- a/internal/app/email/templates/badge.html +++ b/internal/app/email/templates/badge.html @@ -16,7 +16,7 @@

Peerly

- Badge Image + Badge Image

Hi {{.EmployeeName}}

Congratulations!
You have achieved the {{.BadgeName}} badge for
accumulating {{.AppreciationPoints}} points.

diff --git a/internal/app/email/templates/deleteAppreciation.html b/internal/app/email/templates/deleteAppreciation.html index 2730ba4..67cf6aa 100644 --- a/internal/app/email/templates/deleteAppreciation.html +++ b/internal/app/email/templates/deleteAppreciation.html @@ -25,7 +25,7 @@ style="background-color: #F5F8FF; padding: 40px 20px; text-align: center; color: #000000;">

Peerly

- appreciation

diff --git a/internal/app/email/templates/receiverAppreciation.html b/internal/app/email/templates/receiverAppreciation.html index 515f2b2..1c134b6 100644 --- a/internal/app/email/templates/receiverAppreciation.html +++ b/internal/app/email/templates/receiverAppreciation.html @@ -16,7 +16,7 @@

Peerly

- appreciation + appreciation

Bravo!
You have received a deserved
word of appreciation.
Keep inspiring those around you!

{{.SenderName}} appreciated you
Core Value
diff --git a/internal/app/email/templates/reportAppreciation.html b/internal/app/email/templates/reportAppreciation.html index 1cb16c2..975acec 100644 --- a/internal/app/email/templates/reportAppreciation.html +++ b/internal/app/email/templates/reportAppreciation.html @@ -16,7 +16,7 @@

Peerly

- Feedback Icon + Feedback Icon

Your feedback is important for us,thank you
for reporting.
Our team will look into this and necessary
action will be taken soon.

Hi {{.SenderName}} diff --git a/internal/app/email/templates/senderAppreciation.html b/internal/app/email/templates/senderAppreciation.html index 2170f0c..335f723 100644 --- a/internal/app/email/templates/senderAppreciation.html +++ b/internal/app/email/templates/senderAppreciation.html @@ -16,7 +16,7 @@

Peerly

- Thank You + Thank You

Hi {{.SenderName}}

You've successfully sent appreciation to {{.ReceiverName}}.

Core Value
diff --git a/internal/app/grades/service.go b/internal/app/grades/service.go index 5011801..1329a32 100644 --- a/internal/app/grades/service.go +++ b/internal/app/grades/service.go @@ -8,9 +8,9 @@ import ( "github.com/joshsoftware/peerly-backend/internal/pkg/apperrors" "github.com/joshsoftware/peerly-backend/internal/pkg/constants" "github.com/joshsoftware/peerly-backend/internal/pkg/dto" + logger "github.com/joshsoftware/peerly-backend/internal/pkg/logger" "github.com/joshsoftware/peerly-backend/internal/pkg/utils" "github.com/joshsoftware/peerly-backend/internal/repository" - logger "github.com/sirupsen/logrus" ) type service struct { @@ -34,7 +34,7 @@ func (gs *service) ListGrades(ctx context.Context) (resp []dto.Grade, err error) dbResp, err := gs.gradesRepo.ListGrades(ctx) if err != nil { - logger.Error(err.Error()) + logger.Error(ctx, err.Error()) err = apperrors.InternalServerError } @@ -69,7 +69,7 @@ func (gs *service) EditGrade(ctx context.Context, id string, points int64) (err var reqData dto.UpdateGradeReq reqData.Id = gradeId if points < 0 { - logger.Errorf("grade points cannot be negative, grade points: %d", points) + logger.Errorf(ctx, "grade points cannot be negative, grade points: %d", points) err = apperrors.NegativeGradePoints return } @@ -77,14 +77,14 @@ func (gs *service) EditGrade(ctx context.Context, id string, points int64) (err userId := ctx.Value(constants.UserId) data, ok := userId.(int64) if !ok { - logger.Error("Error in typecasting user id") + logger.Error(ctx,"Error in typecasting user id") err = apperrors.InternalServerError return } reqData.UpdatedBy = data err = gs.gradesRepo.EditGrade(ctx, reqData) if err != nil { - logger.Error(err.Error()) + logger.Error(ctx, err.Error()) err = apperrors.InternalServerError return } diff --git a/internal/app/notification/service.go b/internal/app/notification/service.go index 8d75634..9b9a2e7 100644 --- a/internal/app/notification/service.go +++ b/internal/app/notification/service.go @@ -6,32 +6,33 @@ import ( firebase "firebase.google.com/go" "firebase.google.com/go/messaging" "github.com/joshsoftware/peerly-backend/internal/pkg/apperrors" - logger "github.com/sirupsen/logrus" + "github.com/joshsoftware/peerly-backend/internal/pkg/constants" + logger "github.com/joshsoftware/peerly-backend/internal/pkg/logger" "google.golang.org/api/option" ) type NotificationService interface { SendNotificationToNotificationToken(notificationToken string) (err error) SendNotificationToTopic(topic string) (err error) - // SendNotificationToNotificationTokens(userId int64) } type Message struct { - Title string `json:"title,omitempty"` - Body string `json:"body,omitempty"` - ImageURL string `json:"image,omitempty"` + Title string `json:"title,omitempty"` + Body string `json:"body,omitempty"` + ImageURL string `json:"image,omitempty"` + Data map[string]string `json:"data,omitempty"` } func (notificationSvc *Message) SendNotificationToNotificationToken(notificationToken string) (err error) { // Path to your service account key file - serviceAccountKey := "serviceAccountKey.json" + serviceAccountKey := constants.ServiceAccountKey // Initialize the Firebase app opt := option.WithCredentialsFile(serviceAccountKey) app, err := firebase.NewApp(context.Background(), nil, opt) if err != nil { - logger.Errorf("Error initializing app: %v", err) + logger.Errorf(context.Background(), "Error initializing app: %v", err) err = apperrors.InternalServerError return } @@ -39,10 +40,12 @@ func (notificationSvc *Message) SendNotificationToNotificationToken(notification // Obtain a messaging client from the Firebase app client, err := app.Messaging(context.Background()) if err != nil { - logger.Errorf("Error getting Messaging client: %v", err) + logger.Errorf(context.Background(), "Error getting Messaging client: %v", err) err = apperrors.InternalServerError return } + + logger.Debug(context.Background(), " notificationSvc: ", notificationSvc) // Create a message to send message := &messaging.Message{ Notification: &messaging.Notification{ @@ -50,16 +53,19 @@ func (notificationSvc *Message) SendNotificationToNotificationToken(notification Body: notificationSvc.Body, }, Token: notificationToken, + Data: notificationSvc.Data, } // Send the message response, err := client.Send(context.Background(), message) + logger.Debug(context.Background(), " response: ", response) + logger.Debug(context.Background(), " err: ", err) if err != nil { - logger.Errorf("Error sending message: %v", err) + logger.Errorf(context.Background(), "Error sending message: %v", err) err = apperrors.InternalServerError return } - logger.Infof("Successfully sent message: %v", response) + logger.Infof(context.Background(), "Successfully sent message: %v", response) return } @@ -72,7 +78,7 @@ func (notificationSvc *Message) SendNotificationToTopic(topic string) (err error opt := option.WithCredentialsFile(serviceAccountKey) app, err := firebase.NewApp(context.Background(), nil, opt) if err != nil { - logger.Errorf("error initializing app: %v", err) + logger.Errorf(context.Background(), "error initializing app: %v", err) err = apperrors.InternalServerError return } @@ -80,11 +86,12 @@ func (notificationSvc *Message) SendNotificationToTopic(topic string) (err error // Obtain a messaging client from the Firebase app client, err := app.Messaging(context.Background()) if err != nil { - logger.Errorf("error getting Messaging client: %v", err) + logger.Errorf(context.Background(), "error getting Messaging client: %v", err) err = apperrors.InternalServerError return } + logger.Debug(context.Background(), " notificationSvc: ", notificationSvc) // Create a message to send message := &messaging.Message{ Notification: &messaging.Notification{ @@ -92,54 +99,18 @@ func (notificationSvc *Message) SendNotificationToTopic(topic string) (err error Body: notificationSvc.Body, }, Topic: topic, + Data: notificationSvc.Data, } // Send the message response, err := client.Send(context.Background(), message) if err != nil { - logger.Errorf("error sending message: %v", err) + logger.Errorf(context.Background(), "error sending message: %v", err) err = apperrors.InternalServerError return } - logger.Infof("Successfully sent message: %v", response) + logger.Infof(context.Background(), "Successfully sent message: %v", response) return } - -// func (notificationSvc *Message) SendNotificationToNotificationTokens(userId int64) { - -// // Path to your service account key file -// serviceAccountKey := "serviceAccountKey.json" - -// // Initialize the Firebase app -// opt := option.WithCredentialsFile(serviceAccountKey) -// app, err := firebase.NewApp(context.Background(), nil, opt) -// if err != nil { -// logger.Errorf("Error initializing app: %v", err) -// return -// } - -// // Obtain a messaging client from the Firebase app -// client, err := app.Messaging(context.Background()) -// if err != nil { -// logger.Errorf("Error getting Messaging client: %v", err) -// return -// } -// // Create a message to send -// message := &messaging.Message{ -// Notification: &messaging.Notification{ -// Title: notificationSvc.Title, -// Body: notificationSvc.Body, -// }, -// Token: notificationToken, -// } - -// // Send the message -// response, err := client.Send(context.Background(), message) -// if err != nil { -// logger.Errorf("Error sending message: %v", err) -// return -// } -// logger.Infof("Successfully sent message: %v", response) -// } diff --git a/internal/app/organizationConfig/service.go b/internal/app/organizationConfig/service.go index 3afdbe3..b21451c 100644 --- a/internal/app/organizationConfig/service.go +++ b/internal/app/organizationConfig/service.go @@ -7,7 +7,8 @@ import ( "github.com/joshsoftware/peerly-backend/internal/pkg/dto" "github.com/joshsoftware/peerly-backend/internal/repository" "github.com/joshsoftware/peerly-backend/internal/pkg/constants" - logger "github.com/sirupsen/logrus" + logger "github.com/joshsoftware/peerly-backend/internal/pkg/logger" + ) type service struct { @@ -29,11 +30,13 @@ func NewService(organizationConfigRepo repository.OrganizationConfigStorer) Serv func (orgSvc *service) GetOrganizationConfig(ctx context.Context) (dto.OrganizationConfig, error) { + logger.Debug(ctx,"orgSvc: GetOrganizationConfig") organization, err := orgSvc.OrganizationConfigRepo.GetOrganizationConfig(ctx,nil) if err != nil { - logger.Errorf("err: %v",err) + logger.Errorf(context.Background(),"err: %v",err) return dto.OrganizationConfig{}, err } + logger.Debug(ctx,"orgSvc: GetOrganizationConfig: organization: ",organization) org := organizationConfigToDTO(organization) return org, nil @@ -42,15 +45,17 @@ func (orgSvc *service) GetOrganizationConfig(ctx context.Context) (dto.Organizat func (orgSvc *service) CreateOrganizationConfig(ctx context.Context, organizationConfig dto.OrganizationConfig) (dto.OrganizationConfig, error) { + logger.Debug(ctx," orgSvc: CreateOrganizationConfig: organizationConfig: ",organizationConfig) data := ctx.Value(constants.UserId) userID, ok := data.(int64) if !ok { - logger.Error("err in parsing userid from token") + logger.Error(context.Background(),"orgsvc: err in parsing userid from token") return dto.OrganizationConfig{},apperrors.InternalServer } organizationConfig.CreatedBy = userID organizationConfig.UpdatedBy = userID + logger.Debug(ctx,"orgSvc: organizationConfig: ",organizationConfig) _ ,err := orgSvc.OrganizationConfigRepo.GetOrganizationConfig(ctx,nil); if err != apperrors.OrganizationConfigNotFound { return dto.OrganizationConfig{},apperrors.OrganizationConfigAlreadyPresent @@ -58,35 +63,40 @@ func (orgSvc *service) CreateOrganizationConfig(ctx context.Context, organizatio createdOrganizationConfig, err := orgSvc.OrganizationConfigRepo.CreateOrganizationConfig(ctx,nil, organizationConfig) if err != nil { - logger.Errorf("err: %v",err) + logger.Errorf(ctx,"err: %v",err) return dto.OrganizationConfig{}, err } + logger.Debug(ctx," createdOrganizationConfig: ",createdOrganizationConfig) org := organizationConfigToDTO(createdOrganizationConfig) return org, nil } func (orgSvc *service) UpdateOrganizationConfig(ctx context.Context, organizationConfig dto.OrganizationConfig) (dto.OrganizationConfig, error) { + logger.Debug(ctx," orgSvc: UpdateOrganizationConfig: organizationConfig: ",organizationConfig) data := ctx.Value(constants.UserId) userID, ok := data.(int64) if !ok { - logger.Error("err in parsing userid from token") + logger.Error(ctx,"err in parsing userid from token") return dto.OrganizationConfig{},apperrors.InternalServer } organizationConfig.UpdatedBy = userID _ ,err := orgSvc.OrganizationConfigRepo.GetOrganizationConfig(ctx,nil); if err != nil { - logger.Errorf("err: %v",err) + logger.Errorf(ctx,"err: %v",err) return dto.OrganizationConfig{},err } + logger.Debug(ctx," orgSvc: UpdateOrganizationConfig: organizationConfig: ",organizationConfig) updatedOrganization, err := orgSvc.OrganizationConfigRepo.UpdateOrganizationConfig(ctx,nil, organizationConfig) if err != nil { - logger.Errorf("err: %v",err) + logger.Errorf(ctx,"orgSvc: err: %v",err) return dto.OrganizationConfig{}, err } + org := organizationConfigToDTO(updatedOrganization) + logger.Debug(ctx,"orgSvc: updated organization: ",org) return org, nil } diff --git a/internal/app/reportAppreciations/service.go b/internal/app/reportAppreciations/service.go index f172008..e424dfc 100644 --- a/internal/app/reportAppreciations/service.go +++ b/internal/app/reportAppreciations/service.go @@ -7,10 +7,11 @@ import ( "github.com/joshsoftware/peerly-backend/internal/app/email" "github.com/joshsoftware/peerly-backend/internal/pkg/apperrors" + "github.com/joshsoftware/peerly-backend/internal/pkg/config" "github.com/joshsoftware/peerly-backend/internal/pkg/constants" "github.com/joshsoftware/peerly-backend/internal/pkg/dto" + logger "github.com/joshsoftware/peerly-backend/internal/pkg/logger" "github.com/joshsoftware/peerly-backend/internal/repository" - logger "github.com/sirupsen/logrus" ) type service struct { @@ -40,7 +41,7 @@ func (rs *service) ReportAppreciation(ctx context.Context, reqData dto.ReportApp fmt.Printf("reporterId: %T", reporterId) data, ok := reporterId.(int64) if !ok { - logger.Error("Error in typecasting reporter id") + logger.Error(ctx, "Error in typecasting reporter id") err = apperrors.InternalServerError return } @@ -117,7 +118,7 @@ func (rs *service) ListReportedAppreciations(ctx context.Context) (dto.ListRepor appreciations, err := rs.reportAppreciationRepo.ListReportedAppreciations(ctx) if err != nil { - logger.Error(err.Error()) + logger.Error(ctx, err.Error()) err = apperrors.InternalServerError return resp, err } @@ -181,7 +182,7 @@ func (rs *service) DeleteAppreciation(ctx context.Context, reqData dto.Moderatio fmt.Printf("moderatorId: %T", moderatorId) data, ok := moderatorId.(int64) if !ok { - logger.Error("Error in typecasting moderator id") + logger.Error(ctx, "Error in typecasting moderator id") err = apperrors.InternalServerError return } @@ -195,7 +196,7 @@ func (rs *service) DeleteAppreciation(ctx context.Context, reqData dto.Moderatio reqData.AppreciationId = appreciation.Appreciation_id err = rs.reportAppreciationRepo.DeleteAppreciation(ctx, reqData) if err != nil { - logger.Error(err.Error()) + logger.Error(ctx, err.Error()) err = apperrors.InternalServerError return } @@ -231,12 +232,13 @@ func (rs *service) DeleteAppreciation(ctx context.Context, reqData dto.Moderatio } templateData := dto.DeleteAppreciationMail{ - ModeratorComment: reqData.ModeratorComment, - AppreciationBy: sender.FirstName + " " + sender.LastName, - AppreciationTo: receiver.FirstName + " " + receiver.LastName, - ReportingComment: appreciation.ReportingComment, - AppreciationDesc: appreciation.AppreciationDesc, - Date: appreciation.CreatedAt, + ModeratorComment: reqData.ModeratorComment, + AppreciationBy: sender.FirstName + " " + sender.LastName, + AppreciationTo: receiver.FirstName + " " + receiver.LastName, + ReportingComment: appreciation.ReportingComment, + AppreciationDesc: appreciation.AppreciationDesc, + Date: appreciation.CreatedAt, + ReportIconImageURL: fmt.Sprint(config.PeerlyBaseUrl() + constants.CheckIconImagePath), } fmt.Println("Reporter mail: ", reporter.Email) @@ -287,36 +289,46 @@ func mapDbAppreciationsToSvcAppreciations(dbApp repository.ListReportedAppreciat func sendReportEmail(senderEmail string, senderFirstName string, senderLastName string, apprSenderFirstName string, apprSenderLastName string, apprReceiverFirstName string, apprReceiverLastName string, reportingComment string) error { + ctx := context.Background() + ctx = context.WithValue(ctx, constants.RequestID, "reportEmail") templateData := struct { SenderName string ReportingComment string AppreciationSenderName string AppreciationReceiverName string + ReportIconImageURL string }{ SenderName: fmt.Sprint(senderFirstName, " ", senderLastName), ReportingComment: reportingComment, AppreciationSenderName: fmt.Sprint(apprSenderFirstName, " ", apprSenderLastName), AppreciationReceiverName: fmt.Sprint(apprReceiverFirstName, " ", apprReceiverLastName), + ReportIconImageURL: fmt.Sprint(config.PeerlyBaseUrl() + constants.CheckIconImagePath), } - logger.Info("report sender email: ---------> ",senderEmail) - mailReq := email.NewMail([]string{senderEmail}, []string{"dl_peerly.support@joshsoftware.com"}, []string{}, "🙏 Thanks for Your Feedback! We’re On It! 🔧") - mailReq.ParseTemplate("./internal/app/email/templates/reportAppreciation.html", templateData) - err := mailReq.Send() + tos := []string{senderEmail} + ccs := []string{constants.HRDLGroup} + bccs := []string{} + sub := "🙏 Thanks for Your Feedback! We’re On It! 🔧" + body, err := email.ParseTemplate("./internal/app/email/templates/reportAppreciation.html", templateData) if err != nil { - logger.Errorf("err: %v", err) + logger.Errorf(context.Background(),"err in creating reportAppreciation.html file : %v", err) + return err + } + mailReq := email.NewMail(tos,ccs ,bccs,sub,body ) + err = mailReq.Send() + if err != nil { + logger.Errorf(ctx, "err: %v", err) return err } return nil } - func (rs *service) ResolveAppreciation(ctx context.Context, reqData dto.ModerationReq) (err error) { moderatorId := ctx.Value(constants.UserId) fmt.Printf("moderatorId: %T", moderatorId) data, ok := moderatorId.(int64) if !ok { - logger.Error("Error in typecasting moderator id") + logger.Error(ctx, "Error in typecasting moderator id") err = apperrors.InternalServerError return } @@ -329,7 +341,7 @@ func (rs *service) ResolveAppreciation(ctx context.Context, reqData dto.Moderati reqData.AppreciationId = appreciation.Appreciation_id err = rs.reportAppreciationRepo.ResolveAppreciation(ctx, reqData) if err != nil { - logger.Error(err.Error()) + logger.Error(ctx, err.Error()) err = apperrors.InternalServerError return } @@ -379,30 +391,58 @@ func (rs *service) ResolveAppreciation(ctx context.Context, reqData dto.Moderati func sendDeleteEmail(reporterEmail string, senderEmail string, receiverEmail string, templateData dto.DeleteAppreciationMail) error { - logger.Info("reporter email: ---------> ", reporterEmail) - mailReq := email.NewMail([]string{reporterEmail}, []string{}, []string{}, "Results of reported appreciation") - mailReq.ParseTemplate("./internal/app/email/templates/deleteAppreciation.html", templateData) - err := mailReq.Send() + ctx := context.Background() + ctx = context.WithValue(ctx, constants.RequestID, "deleteEmail") + logger.Info(ctx, "reporter email: ---------> ", reporterEmail) + tos := []string{reporterEmail} + ccs := []string{} + bccs := []string{} + sub := "Results of reported appreciation" + body, err := email.ParseTemplate("./internal/app/email/templates/deleteAppreciation.html", templateData) + if err != nil { + logger.Errorf(context.Background(),"err in creating deleteAppreciation.html file : %v", err) + return err + } + mailReq := email.NewMail(tos,ccs ,bccs,sub ,body ) + err = mailReq.Send() if err != nil { - logger.Errorf("err: %v", err) + logger.Errorf(context.Background(), "err: %v", err) return err } - logger.Info("sender email: ---------> ", reporterEmail) - mailReq = email.NewMail([]string{senderEmail}, []string{}, []string{}, "Results of reported appreciation") - mailReq.ParseTemplate("./internal/app/email/templates/senderDeleteEmail.html", templateData) + logger.Info(ctx, "sender email: ---------> ", reporterEmail) + + tos = []string{senderEmail} + ccs = []string{} + bccs = []string{} + sub = "Results of reported appreciation" + body,err = email.ParseTemplate("./internal/app/email/templates/senderDeleteEmail.html", templateData) + if err != nil { + logger.Errorf(context.Background(),"err in creating senderDeleteEmail.html file : %v", err) + return err + } + mailReq = email.NewMail(tos,ccs ,bccs,sub,body ) err = mailReq.Send() if err != nil { - logger.Errorf("err: %v", err) + logger.Errorf(ctx, "err: %v", err) return err } - logger.Info("receiver email: ---------> ", reporterEmail) - mailReq = email.NewMail([]string{receiverEmail}, []string{}, []string{}, "Results of reported appreciation") - mailReq.ParseTemplate("./internal/app/email/templates/receiverDeleteEmail.html", templateData) + logger.Info(ctx, "receiver email: ---------> ", reporterEmail) + + tos = []string{receiverEmail} + ccs = []string{} + bccs = []string{} + sub = "Results of reported appreciation" + body,err = email.ParseTemplate("./internal/app/email/templates/receiverDeleteEmail.html", templateData) + if err != nil { + logger.Errorf(context.Background(),"err in creating receiverDeleteEmail.html file : %v", err) + return err + } + mailReq = email.NewMail(tos,ccs,bccs, sub,body ) err = mailReq.Send() if err != nil { - logger.Errorf("err: %v", err) + logger.Errorf(ctx, "err: %v", err) return err } @@ -411,12 +451,20 @@ func sendDeleteEmail(reporterEmail string, senderEmail string, receiverEmail str func sendResolveEmail(senderEmail string, templateData dto.ResolveAppreciationMail) error { - logger.Info("report sender email: ---------> ", senderEmail) - mailReq := email.NewMail([]string{senderEmail}, []string{}, []string{}, "Results of reported appreciation") - mailReq.ParseTemplate("./internal/app/email/templates/resolveAppreciation.html", templateData) - err := mailReq.Send() + logger.Info(context.Background(), "report sender email: ---------> ", senderEmail) + tos := []string{senderEmail} + ccs := []string{} + bccs := []string{} + sub := "Results of reported appreciation" + body ,err := email.ParseTemplate("./internal/app/email/templates/resolveAppreciation.html", templateData) + if err != nil { + logger.Errorf(context.Background(),"err in creating resolveAppreciation.html file : %v", err) + return err + } + mailReq := email.NewMail(tos, ccs, bccs, sub,body) + err = mailReq.Send() if err != nil { - logger.Errorf("err: %v", err) + logger.Errorf(context.Background(), "err: %v", err) return err } return nil diff --git a/internal/app/reportAppreciations/service_test.go b/internal/app/reportAppreciations/service_test.go index dc8c324..8df71d4 100644 --- a/internal/app/reportAppreciations/service_test.go +++ b/internal/app/reportAppreciations/service_test.go @@ -15,7 +15,8 @@ import ( func TestReportAppreciation(t *testing.T) { reportAppreciationRepo := mocks.NewReportAppreciationStorer(t) userRepo := mocks.NewUserStorer(t) - service := NewService(reportAppreciationRepo, userRepo) + appreciationRepo := mocks.NewAppreciationStorer(t) + service := NewService(reportAppreciationRepo, userRepo, appreciationRepo) tests := []struct { name string @@ -140,7 +141,8 @@ func TestReportAppreciation(t *testing.T) { func TestListReportedAppreciations(t *testing.T) { reportAppreciationRepo := mocks.NewReportAppreciationStorer(t) userRepo := mocks.NewUserStorer(t) - service := NewService(reportAppreciationRepo, userRepo) + appreciationRepo := mocks.NewAppreciationStorer(t) + service := NewService(reportAppreciationRepo, userRepo, appreciationRepo) tests := []struct { name string diff --git a/internal/app/reward/service.go b/internal/app/reward/service.go index 90b222e..7c4c90d 100644 --- a/internal/app/reward/service.go +++ b/internal/app/reward/service.go @@ -2,14 +2,15 @@ package reward import ( "context" + "strconv" "github.com/joshsoftware/peerly-backend/internal/app/notification" user "github.com/joshsoftware/peerly-backend/internal/app/users" "github.com/joshsoftware/peerly-backend/internal/pkg/apperrors" "github.com/joshsoftware/peerly-backend/internal/pkg/constants" "github.com/joshsoftware/peerly-backend/internal/pkg/dto" + logger "github.com/joshsoftware/peerly-backend/internal/pkg/logger" "github.com/joshsoftware/peerly-backend/internal/repository" - logger "github.com/sirupsen/logrus" ) type service struct { @@ -32,49 +33,60 @@ func NewService(rewardRepo repository.RewardStorer, appreciationRepo repository. func (rwrdSvc *service) GiveReward(ctx context.Context, rewardReq dto.Reward) (dto.Reward, error) { + logger.Debug(ctx, " rwrdSvc: GiveReward: ", rewardReq) //add sender data := ctx.Value(constants.UserId) sender, ok := data.(int64) if !ok { - logger.Error("err in parsing userid from token") + logger.Error(ctx,"rwrdSvc: err in parsing userid from token") return dto.Reward{}, apperrors.InternalServer } rewardReq.SenderId = sender appr, err := rwrdSvc.appreciationRepo.GetAppreciationById(ctx, nil, int32(rewardReq.AppreciationId)) if err != nil { + logger.Errorf(ctx,"rwrdSvc: gerAppreciationById err : %v",err) return dto.Reward{}, err } + logger.Debug(ctx,"rwrdSvc: appr: ",appr) if appr.SenderID == sender { + logger.Error(ctx,"rwrdSvc: SelfAppreciationRewardError") return dto.Reward{}, apperrors.SelfAppreciationRewardError } if appr.ReceiverID == sender { + logger.Error(ctx,"rwrdSvc: SelfRewardError") return dto.Reward{}, apperrors.SelfRewardError } userChk, err := rwrdSvc.rewardRepo.UserHasRewardQuota(ctx, nil, rewardReq.SenderId, rewardReq.Point) if err != nil { + logger.Errorf(ctx,"rwrdSvc: UserHasRewardQuota: err: %v",err) return dto.Reward{}, err } + logger.Debug(ctx," userChk: ",userChk) if !userChk { + logger.Error(ctx,"rwrdSvc: RewardQuotaIsNotSufficient") return dto.Reward{}, apperrors.RewardQuotaIsNotSufficient } rwrdChk, err := rwrdSvc.rewardRepo.IsUserRewardForAppreciationPresent(ctx, nil, rewardReq.AppreciationId, rewardReq.SenderId) if err != nil { + logger.Errorf(ctx,"rwrdSvc: IsUserRewardForAppreciationPresent: err: %v",err) return dto.Reward{}, err } - + if rwrdChk { + logger.Error(ctx," rwrdChk: RewardAlreadyPresent") return dto.Reward{}, apperrors.RewardAlreadyPresent } //initializing database transaction tx, err := rwrdSvc.rewardRepo.BeginTx(ctx) if err != nil { + logger.Error(ctx,"rwrdSvc: error in BeginTx") return dto.Reward{}, err } @@ -82,7 +94,7 @@ func (rwrdSvc *service) GiveReward(ctx context.Context, rewardReq dto.Reward) (d rvr := recover() defer func() { if rvr != nil { - logger.Info(ctx, "Transaction aborted because of panic: %v, Propagating panic further", rvr) + logger.Infof(ctx, "Transaction aborted because of panic: %v, Propagating panic further", rvr) panic(rvr) } }() @@ -90,12 +102,13 @@ func (rwrdSvc *service) GiveReward(ctx context.Context, rewardReq dto.Reward) (d txErr := rwrdSvc.appreciationRepo.HandleTransaction(ctx, tx, err == nil && rvr == nil) if txErr != nil { err = txErr - logger.Info(ctx, "error in creating transaction, err: %s", txErr.Error()) + logger.Infof(ctx, "error in creating transaction, err: %s", txErr.Error()) return } }() repoRewardRes, err := rwrdSvc.rewardRepo.GiveReward(ctx, tx, rewardReq) if err != nil { + logger.Errorf(ctx,"rwrdSvc: GiveReward: err: %v",err) return dto.Reward{}, err } @@ -103,71 +116,77 @@ func (rwrdSvc *service) GiveReward(ctx context.Context, rewardReq dto.Reward) (d deduceChk, err := rwrdSvc.rewardRepo.DeduceRewardQuotaOfUser(ctx, tx, rewardReq.SenderId, int(rewardReq.Point)) if err != nil { + logger.Errorf(ctx,"rwrdSvc: DeduceRewardQuotaOfUser: err: %v",err) return dto.Reward{}, err } if !deduceChk { + logger.Error(ctx,"rwrdSvc: DeduceRewardQuotaOfUser") return dto.Reward{}, apperrors.InternalServer } - - var reward dto.Reward reward.Id = repoRewardRes.Id reward.AppreciationId = repoRewardRes.AppreciationId reward.SenderId = repoRewardRes.SenderId reward.Point = repoRewardRes.Point quaterTimeStamp := user.GetQuarterStartUnixTime() - + req := dto.GetUserByIdReq{ UserId: sender, QuaterTimeStamp: quaterTimeStamp, } - userInfo ,err := rwrdSvc.userRepo.GetUserById(ctx,req) + userInfo, err := rwrdSvc.userRepo.GetUserById(ctx, req) if err != nil { - logger.Errorf("err in getting user data: %v",err) + logger.Errorf(ctx, "err in getting user data: %v", err) } - rwrdSvc.sendRewardNotificationToSender(ctx,userInfo) - rwrdSvc.sendRewardNotificationToReceiver(ctx,appr.ReceiverID) + rwrdSvc.sendRewardNotificationToSender(ctx, userInfo, rewardReq.AppreciationId) + rwrdSvc.sendRewardNotificationToReceiver(ctx, appr.ReceiverID, rewardReq.AppreciationId) return reward, nil } -func GetQuarterStartUnixTime() { - panic("unimplemented") -} - -func (rwrdSvc *service) sendRewardNotificationToSender(ctx context.Context, user dto.GetUserByIdResp) { +func (rwrdSvc *service) sendRewardNotificationToSender(ctx context.Context, user dto.GetUserByIdResp, apprID int64) { + logger.Debug(ctx, " rwrdSvc: sendRewardNotificationToSender: user: ", user) notificationTokens, err := rwrdSvc.userRepo.ListDeviceTokensByUserID(ctx, user.UserId) + logger.Debug(ctx, " notificationTokens: ", notificationTokens) if err != nil { - logger.Errorf("err in getting device tokens: %v", err) - return + logger.Errorf(ctx, "err in gettinsendRewardNotificationToSenderg device tokens: %v", err) + return } + msgData := map[string]string{constants.AppreciationID: strconv.FormatInt(apprID, 10)} msg := notification.Message{ Title: "Reward Given Successfully", Body: "You have successfully given a reward! ", + Data: msgData, } + logger.Debug(ctx, " msg: ", msg) for _, notificationToken := range notificationTokens { msg.SendNotificationToNotificationToken(notificationToken) } } -func (rwrdSvc *service) sendRewardNotificationToReceiver(ctx context.Context, userID int64) { +func (rwrdSvc *service) sendRewardNotificationToReceiver(ctx context.Context, userID int64, apprID int64) { + logger.Debug(ctx, " rwrdSvc: sendRewardNotificationToReceiver") notificationTokens, err := rwrdSvc.userRepo.ListDeviceTokensByUserID(ctx, userID) + logger.Debug(ctx, " notificationTokens: ", notificationTokens) if err != nil { - logger.Errorf("err in getting device tokens: %v", err) - return + logger.Errorf(ctx, " err in getting device tokens: %v", err) + return } + msgData := map[string]string{constants.AppreciationID: strconv.FormatInt(apprID, 10)} msg := notification.Message{ Title: "Reward's incoming!", Body: "You've been awarded a reward! Well done and keep up the JOSH!", + Data: msgData, } + logger.Debug(ctx, " rwrdSvc: msg: ", msg) for _, notificationToken := range notificationTokens { msg.SendNotificationToNotificationToken(notificationToken) } diff --git a/internal/app/reward/service_test.go b/internal/app/reward/service_test.go index b6ec824..95cf11a 100644 --- a/internal/app/reward/service_test.go +++ b/internal/app/reward/service_test.go @@ -15,7 +15,6 @@ import ( "github.com/stretchr/testify/mock" ) - func TestGiveReward(t *testing.T) { tests := []struct { name string @@ -34,7 +33,7 @@ func TestGiveReward(t *testing.T) { Point: 10, }, setup: func(rwrdMock *mocks.RewardStorer, apprMock *mocks.AppreciationStorer) { - apprMock.On("GetAppreciationById", mock.Anything, nil, 1).Return(repository.AppreciationInfo{SenderId: 2, ReceiverId: 3}, nil) + apprMock.On("GetAppreciationById", mock.Anything, nil, 1).Return(repository.AppreciationResponse{SenderID: 2, ReceiverID: 3}, nil) rwrdMock.On("UserHasRewardQuota", mock.Anything, nil, int64(1), int64(10)).Return(true, nil) rwrdMock.On("IsUserRewardForAppreciationPresent", mock.Anything, nil, int64(1), int64(1)).Return(false, nil) rwrdMock.On("BeginTx", mock.Anything).Return(nil, nil) @@ -66,7 +65,7 @@ func TestGiveReward(t *testing.T) { Point: 10, }, setup: func(rwrdMock *mocks.RewardStorer, apprMock *mocks.AppreciationStorer) { - apprMock.On("GetAppreciationById", mock.Anything, nil, 1).Return(repository.AppreciationInfo{SenderId: 1, ReceiverId: 2}, nil) + apprMock.On("GetAppreciationById", mock.Anything, nil, 1).Return(repository.AppreciationResponse{SenderID: 2, ReceiverID: 3}, nil) }, isErrorExpected: true, expectedResult: dto.Reward{}, @@ -80,7 +79,7 @@ func TestGiveReward(t *testing.T) { Point: 10, }, setup: func(rwrdMock *mocks.RewardStorer, apprMock *mocks.AppreciationStorer) { - apprMock.On("GetAppreciationById", mock.Anything, nil, 1).Return(repository.AppreciationInfo{SenderId: 2, ReceiverId: 1}, nil) + apprMock.On("GetAppreciationById", mock.Anything, nil, 1).Return(repository.AppreciationResponse{SenderID: 2, ReceiverID: 3}, nil) }, isErrorExpected: true, expectedResult: dto.Reward{}, @@ -94,7 +93,7 @@ func TestGiveReward(t *testing.T) { Point: 10, }, setup: func(rwrdMock *mocks.RewardStorer, apprMock *mocks.AppreciationStorer) { - apprMock.On("GetAppreciationById", mock.Anything, nil, 1).Return(repository.AppreciationInfo{SenderId: 2, ReceiverId: 3}, nil) + apprMock.On("GetAppreciationById", mock.Anything, nil, 1).Return(repository.AppreciationResponse{SenderID: 2, ReceiverID: 3}, nil) rwrdMock.On("UserHasRewardQuota", mock.Anything, nil, int64(1), int64(10)).Return(false, nil) }, isErrorExpected: true, @@ -109,7 +108,7 @@ func TestGiveReward(t *testing.T) { Point: 10, }, setup: func(rwrdMock *mocks.RewardStorer, apprMock *mocks.AppreciationStorer) { - apprMock.On("GetAppreciationById", mock.Anything, nil, 1).Return(repository.AppreciationInfo{SenderId: 2, ReceiverId: 3}, nil) + apprMock.On("GetAppreciationById", mock.Anything, nil, 1).Return(repository.AppreciationResponse{SenderID: 2, ReceiverID: 3}, nil) rwrdMock.On("UserHasRewardQuota", mock.Anything, nil, int64(1), int64(10)).Return(true, nil) rwrdMock.On("IsUserRewardForAppreciationPresent", mock.Anything, nil, int64(1), int64(1)).Return(true, nil) }, @@ -125,7 +124,7 @@ func TestGiveReward(t *testing.T) { Point: 10, }, setup: func(rwrdMock *mocks.RewardStorer, apprMock *mocks.AppreciationStorer) { - apprMock.On("GetAppreciationById", mock.Anything, nil, 1).Return(repository.AppreciationInfo{SenderId: 2, ReceiverId: 3}, nil) + apprMock.On("GetAppreciationById", mock.Anything, nil, 1).Return(repository.AppreciationResponse{SenderID: 2, ReceiverID: 3}, nil) rwrdMock.On("UserHasRewardQuota", mock.Anything, nil, int64(1), int64(10)).Return(true, nil) rwrdMock.On("IsUserRewardForAppreciationPresent", mock.Anything, nil, int64(1), int64(1)).Return(false, nil) rwrdMock.On("BeginTx", mock.Anything).Return(nil, apperrors.InternalServer) @@ -142,7 +141,7 @@ func TestGiveReward(t *testing.T) { Point: 10, }, setup: func(rwrdMock *mocks.RewardStorer, apprMock *mocks.AppreciationStorer) { - apprMock.On("GetAppreciationById", mock.Anything, nil, 1).Return(repository.AppreciationInfo{SenderId: 2, ReceiverId: 3}, nil) + apprMock.On("GetAppreciationById", mock.Anything, nil, 1).Return(repository.AppreciationResponse{SenderID: 2, ReceiverID: 3}, nil) rwrdMock.On("UserHasRewardQuota", mock.Anything, nil, int64(1), int64(10)).Return(true, nil) rwrdMock.On("IsUserRewardForAppreciationPresent", mock.Anything, nil, int64(1), int64(1)).Return(false, nil) rwrdMock.On("BeginTx", mock.Anything).Return(nil, nil) @@ -166,8 +165,8 @@ func TestGiveReward(t *testing.T) { } service := &service{ - rewardRepo: rwrdMock, - appreciationRepo: apprMock, + rewardRepo: rwrdMock, + appreciationRepo: apprMock, } result, err := service.GiveReward(test.ctx, test.rewardReq) diff --git a/internal/app/users/mocks/Service.go b/internal/app/users/mocks/Service.go index 4c360d1..801452c 100644 --- a/internal/app/users/mocks/Service.go +++ b/internal/app/users/mocks/Service.go @@ -11,6 +11,48 @@ type Service struct { mock.Mock } +// AdminLogin provides a mock function with given fields: ctx, loginReq +func (_m *Service) AdminLogin(ctx context.Context, loginReq dto.AdminLoginReq) (dto.LoginUserResp, error) { + ret := _m.Called(ctx, loginReq) + + var r0 dto.LoginUserResp + if rf, ok := ret.Get(0).(func(context.Context, dto.AdminLoginReq) dto.LoginUserResp); ok { + r0 = rf(ctx, loginReq) + } else { + r0 = ret.Get(0).(dto.LoginUserResp) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, dto.AdminLoginReq) error); ok { + r1 = rf(ctx, loginReq) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AllAppreciationReport provides a mock function with given fields: ctx, appreciations +func (_m *Service) AllAppreciationReport(ctx context.Context, appreciations []dto.AppreciationResponse) (string, error) { + ret := _m.Called(ctx, appreciations) + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context, []dto.AppreciationResponse) string); ok { + r0 = rf(ctx, appreciations) + } else { + r0 = ret.Get(0).(string) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, []dto.AppreciationResponse) error); ok { + r1 = rf(ctx, appreciations) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GetActiveUserList provides a mock function with given fields: ctx func (_m *Service) GetActiveUserList(ctx context.Context) ([]dto.ActiveUser, error) { ret := _m.Called(ctx) @@ -164,6 +206,20 @@ func (_m *Service) LoginUser(ctx context.Context, u dto.IntranetUserData) (dto.L return r0, r1 } +// NotificationByAdmin provides a mock function with given fields: ctx, notificationReq +func (_m *Service) NotificationByAdmin(ctx context.Context, notificationReq dto.AdminNotificationReq) error { + ret := _m.Called(ctx, notificationReq) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, dto.AdminNotificationReq) error); ok { + r0 = rf(ctx, notificationReq) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // RegisterUser provides a mock function with given fields: ctx, u func (_m *Service) RegisterUser(ctx context.Context, u dto.IntranetUserData) (dto.User, error) { ret := _m.Called(ctx, u) @@ -185,6 +241,27 @@ func (_m *Service) RegisterUser(ctx context.Context, u dto.IntranetUserData) (dt return r0, r1 } +// ReportedAppreciationReport provides a mock function with given fields: ctx, appreciations +func (_m *Service) ReportedAppreciationReport(ctx context.Context, appreciations []dto.ReportedAppreciation) (string, error) { + ret := _m.Called(ctx, appreciations) + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context, []dto.ReportedAppreciation) string); ok { + r0 = rf(ctx, appreciations) + } else { + r0 = ret.Get(0).(string) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, []dto.ReportedAppreciation) error); ok { + r1 = rf(ctx, appreciations) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // UpdateRewardQuota provides a mock function with given fields: ctx func (_m *Service) UpdateRewardQuota(ctx context.Context) error { ret := _m.Called(ctx) @@ -220,6 +297,10 @@ func (_m *Service) ValidatePeerly(ctx context.Context, authToken string) (dto.Va return r0, r1 } +// sendRewardQuotaRefillEmailToAll provides a mock function with given fields: ctx +func (_m *Service) sendRewardQuotaRefillEmailToAll(ctx context.Context) { + _m.Called(ctx) +} func NewService(t interface { mock.TestingT diff --git a/internal/app/users/service.go b/internal/app/users/service.go index 8c24eda..dff918e 100644 --- a/internal/app/users/service.go +++ b/internal/app/users/service.go @@ -18,8 +18,8 @@ import ( "github.com/joshsoftware/peerly-backend/internal/pkg/config" "github.com/joshsoftware/peerly-backend/internal/pkg/constants" "github.com/joshsoftware/peerly-backend/internal/pkg/dto" + logger "github.com/joshsoftware/peerly-backend/internal/pkg/logger" "github.com/joshsoftware/peerly-backend/internal/repository" - logger "github.com/sirupsen/logrus" "golang.org/x/crypto/bcrypt" ) @@ -39,7 +39,6 @@ type Service interface { GetActiveUserList(ctx context.Context) ([]dto.ActiveUser, error) GetTop10Users(ctx context.Context) (users []dto.Top10User, err error) AdminLogin(ctx context.Context, loginReq dto.AdminLoginReq) (resp dto.LoginUserResp, err error) - // sendRewardQuotaRefillEmailToAll(ctx context.Context) NotificationByAdmin(ctx context.Context, notificationReq dto.AdminNotificationReq) (err error) AllAppreciationReport(ctx context.Context, appreciations []dto.AppreciationResponse) (tempFileName string, err error) ReportedAppreciationReport(ctx context.Context, appreciations []dto.ReportedAppreciation) (tempFileName string, err error) @@ -56,7 +55,7 @@ func (us *service) ValidatePeerly(ctx context.Context, authToken string) (data d client := &http.Client{} validationReq, err := http.NewRequest(http.MethodPost, config.IntranetBaseUrl()+constants.PeerlyValidationPath, nil) if err != nil { - logger.Errorf("error in creating new validation request err: %s", err.Error()) + logger.Errorf(ctx, "error in creating new validation request err: %s", err.Error()) err = apperrors.InternalServerError return } @@ -64,25 +63,25 @@ func (us *service) ValidatePeerly(ctx context.Context, authToken string) (data d validationReq.Header.Add(constants.ClientCode, config.IntranetClientCode()) resp, err := client.Do(validationReq) if err != nil { - logger.Errorf("error in intranet validation api. status returned: %d, err: %s", resp.StatusCode, err.Error()) + logger.Errorf(ctx, "error in intranet validation api. status returned: %d, err: %s", resp.StatusCode, err.Error()) err = apperrors.InternalServerError return } if resp.StatusCode != http.StatusOK { - logger.Errorf("error returned, status returned: %d", resp.StatusCode) + logger.Errorf(ctx, "error returned, status returned: %d", resp.StatusCode) err = apperrors.IntranetValidationFailed return } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { - logger.Errorf("error in readall parsing. err: %s", err.Error()) + logger.Errorf(ctx, "error in readall parsing. err: %s", err.Error()) err = apperrors.JSONParsingErrorResp return } err = json.Unmarshal(body, &data) if err != nil { - logger.Errorf("error in unmarshal parsing. err: %s", err.Error()) + logger.Errorf(ctx, "error in unmarshal parsing. err: %s", err.Error()) err = apperrors.JSONParsingErrorResp return } @@ -96,7 +95,7 @@ func (us *service) GetIntranetUserData(ctx context.Context, req dto.GetIntranetU url := fmt.Sprintf("%s%s%d", config.IntranetBaseUrl(), constants.GetIntranetUserDataPath, req.UserId) intranetReq, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { - logger.Errorf("error in creating new get user request. err: %s", err.Error()) + logger.Errorf(ctx, "error in creating new get user request. err: %s", err.Error()) err = apperrors.InternalServerError return } @@ -104,14 +103,14 @@ func (us *service) GetIntranetUserData(ctx context.Context, req dto.GetIntranetU intranetReq.Header.Add(constants.AuthorizationHeader, req.Token) resp, err := client.Do(intranetReq) if err != nil { - logger.Errorf("error in intranet get user api. status returned: %d, err: %s ", resp.StatusCode, err.Error()) - logger.Errorf("error response: %v", resp) + logger.Errorf(ctx, "error in intranet get user api. status returned: %d, err: %s ", resp.StatusCode, err.Error()) + logger.Errorf(ctx, "error response: %v", resp) err = apperrors.InternalServerError return } if resp.StatusCode != http.StatusOK { - logger.Errorf("error in intranet get user api. status returned: %d ", resp.StatusCode) - logger.Errorf("error response: %v", resp) + logger.Errorf(ctx, "error in intranet get user api. status returned: %d ", resp.StatusCode) + logger.Errorf(ctx, "error response: %v", resp) err = apperrors.InternalServerError return } @@ -119,7 +118,7 @@ func (us *service) GetIntranetUserData(ctx context.Context, req dto.GetIntranetU body, err := io.ReadAll(resp.Body) if err != nil { - logger.Errorf("error in io.readall. err: %s", err.Error()) + logger.Errorf(ctx, "error in io.readall. err: %s", err.Error()) err = apperrors.JSONParsingErrorResp return } @@ -128,7 +127,7 @@ func (us *service) GetIntranetUserData(ctx context.Context, req dto.GetIntranetU err = json.Unmarshal(body, &respData) if err != nil { - logger.Errorf("error in unmarshalling data. err: %s", err.Error()) + logger.Errorf(ctx, "error in unmarshalling data. err: %s", err.Error()) err = apperrors.JSONParsingErrorResp return } @@ -154,7 +153,7 @@ func (us *service) LoginUser(ctx context.Context, u dto.IntranetUserData) (dto.L //sync user data syncNeeded, dataToBeUpdated, err := us.syncData(ctx, u, user) if err != nil { - logger.Error(err.Error()) + logger.Error(ctx, err.Error()) err = apperrors.InternalServerError return resp, err } @@ -162,7 +161,7 @@ func (us *service) LoginUser(ctx context.Context, u dto.IntranetUserData) (dto.L err = us.userRepo.SyncData(ctx, dataToBeUpdated) if err != nil { - logger.Error(err.Error()) + logger.Error(ctx, err.Error()) err = apperrors.InternalServerError return resp, err } @@ -182,7 +181,7 @@ func (us *service) LoginUser(ctx context.Context, u dto.IntranetUserData) (dto.L claims := &dto.Claims{ Id: user.Id, - Role: constants.UserRole, + Role: constants.User, StandardClaims: jwt.StandardClaims{ ExpiresAt: expirationTime.Unix(), }, @@ -194,7 +193,7 @@ func (us *service) LoginUser(ctx context.Context, u dto.IntranetUserData) (dto.L tokenString, err := token.SignedString(jwtKey) if err != nil { - logger.Errorf("error generating authtoken. err: %s", err.Error()) + logger.Errorf(ctx, "error generating authtoken. err: %s", err.Error()) err = apperrors.InternalServerError return resp, err } @@ -204,7 +203,7 @@ func (us *service) LoginUser(ctx context.Context, u dto.IntranetUserData) (dto.L err = us.userRepo.AddDeviceToken(ctx, user.Id, u.NotificationToken) if err != nil { - logger.Errorf("err in adding device token: %v", err) + logger.Errorf(ctx, "err in adding device token: %v", err) } return resp, nil @@ -228,7 +227,7 @@ func (us *service) RegisterUser(ctx context.Context, u dto.IntranetUserData) (us //reward_multiplier from organization config reward_multiplier, err := us.userRepo.GetRewardMultiplier(ctx) if err != nil { - logger.Error(err.Error()) + logger.Error(ctx, err.Error()) err = apperrors.InternalServerError return } @@ -237,7 +236,7 @@ func (us *service) RegisterUser(ctx context.Context, u dto.IntranetUserData) (us //get role by name roleId, err := us.userRepo.GetRoleByName(ctx, constants.UserRole) if err != nil { - logger.Error(err.Error()) + logger.Error(ctx, err.Error()) err = apperrors.InternalServerError return } @@ -251,7 +250,7 @@ func (us *service) RegisterUser(ctx context.Context, u dto.IntranetUserData) (us //register user dbResp, err := us.userRepo.CreateNewUser(ctx, svcData) if err != nil { - logger.Error(err.Error()) + logger.Error(ctx, err.Error()) err = apperrors.InternalServerError return } @@ -266,7 +265,7 @@ func (us *service) ListIntranetUsers(ctx context.Context, reqData dto.GetUserLis url := config.IntranetBaseUrl() + fmt.Sprintf(constants.ListIntranetUsersPath, reqData.Page, constants.DefaultPageSize) intranetReq, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { - logger.Errorf("error in creating new intranet user list request. err: %s", err.Error()) + logger.Errorf(ctx, "error in creating new intranet user list request. err: %s", err.Error()) err = apperrors.InternalServerError return } @@ -274,12 +273,12 @@ func (us *service) ListIntranetUsers(ctx context.Context, reqData dto.GetUserLis intranetReq.Header.Add(constants.AuthorizationHeader, reqData.AuthToken) resp, err := client.Do(intranetReq) if err != nil { - logger.Errorf("error in intranet get user api. status returned: %d, err: %s ", resp.StatusCode, err.Error()) + logger.Errorf(ctx, "error in intranet get user api. status returned: %d, err: %s ", resp.StatusCode, err.Error()) err = apperrors.InternalServerError return } if resp.StatusCode != http.StatusOK { - logger.Errorf("erro in intranet user list request. status returned: %d", resp.StatusCode) + logger.Errorf(ctx, "erro in intranet user list request. status returned: %d", resp.StatusCode) err = apperrors.InternalServerError return } @@ -289,13 +288,13 @@ func (us *service) ListIntranetUsers(ctx context.Context, reqData dto.GetUserLis body, err := io.ReadAll(resp.Body) if err != nil { - logger.Errorf("error in io.readall, err: %s", err.Error()) + logger.Errorf(ctx, "error in io.readall, err: %s", err.Error()) err = apperrors.JSONParsingErrorResp } err = json.Unmarshal(body, &respData) if err != nil { - logger.Errorf("error in unmarshalling data, err: %s", err.Error()) + logger.Errorf(ctx, "error in unmarshalling data, err: %s", err.Error()) err = apperrors.JSONParsingErrorResp return } @@ -317,7 +316,7 @@ func (us *service) ListUsers(ctx context.Context, reqData dto.ListUsersReq) (res dbResp, totalCount, err := us.userRepo.ListUsers(ctx, reqData) if err != nil { - logger.Errorf(err.Error()) + logger.Errorf(ctx, err.Error()) err = apperrors.InternalServerError return } @@ -358,14 +357,14 @@ func (us *service) AdminLogin(ctx context.Context, loginReq dto.AdminLoginReq) ( } if dbUser.RoleID != 2 { - logger.Errorf("unathorized access") + logger.Errorf(ctx, "unathorized access") err = apperrors.RoleUnathorized return } err = bcrypt.CompareHashAndPassword([]byte(dbUser.Password.String), []byte(loginReq.Password)) if err != nil { - logger.Errorf("invalid password, err: %s", err.Error()) + logger.Errorf(ctx, "invalid password, err: %s", err.Error()) err = apperrors.InvalidPassword return } @@ -376,7 +375,7 @@ func (us *service) AdminLogin(ctx context.Context, loginReq dto.AdminLoginReq) ( claims := &dto.Claims{ Id: user.Id, - Role: constants.AdminRole, + Role: constants.Admin, StandardClaims: jwt.StandardClaims{ ExpiresAt: expirationTime.Unix(), }, @@ -388,7 +387,7 @@ func (us *service) AdminLogin(ctx context.Context, loginReq dto.AdminLoginReq) ( tokenString, err := token.SignedString(jwtKey) if err != nil { - logger.Errorf("error generating authtoken. err: %s", err.Error()) + logger.Errorf(ctx, "error generating authtoken. err: %s", err.Error()) err = apperrors.InternalServerError return resp, err } @@ -441,7 +440,7 @@ func (us *service) GetUserById(ctx context.Context) (user dto.GetUserByIdResp, e fmt.Printf("userId: %T", id) userId, ok := id.(int64) if !ok { - logger.Error("Error in typecasting user id") + logger.Error(ctx, "Error in typecasting user id") err = apperrors.InternalServerError return } @@ -460,7 +459,7 @@ func (us *service) GetUserById(ctx context.Context) (user dto.GetUserByIdResp, e grade, err := us.userRepo.GetGradeById(ctx, user.GradeId) if err != nil { - logger.Errorf(err.Error()) + logger.Errorf(ctx, err.Error()) err = apperrors.InternalServerError return } @@ -489,6 +488,7 @@ func (us *service) GetUserById(ctx context.Context) (user dto.GetUserByIdResp, e func (us *service) GetActiveUserList(ctx context.Context) ([]dto.ActiveUser, error) { activeUserDb, err := us.userRepo.GetActiveUserList(ctx, nil) if err != nil { + logger.Errorf(ctx,"usrSvc: GetActiveUserList: err: %v",err) return []dto.ActiveUser{}, err } res := make([]dto.ActiveUser, 0) @@ -518,7 +518,7 @@ func (us *service) GetTop10Users(ctx context.Context) (users []dto.Top10User, er quaterTimeStamp := GetQuarterStartUnixTime() dbUsers, err := us.userRepo.GetTop10Users(ctx, quaterTimeStamp) if err != nil { - logger.Error(err.Error()) + logger.Error(ctx, err.Error()) err = apperrors.InternalServerError return } @@ -584,7 +584,7 @@ func (us *service) NotificationByAdmin(ctx context.Context, notificationReq dto. notificationTokens, err := us.userRepo.ListDeviceTokensByUserID(ctx, notificationReq.Id) if err != nil { - logger.Errorf("err in getting device tokens: %v", err) + logger.Errorf(ctx, "err in getting device tokens: %v", err) err = apperrors.InternalServerError return } @@ -616,14 +616,15 @@ func (us *service) AllAppreciationReport(ctx context.Context, appreciations []dt sheetName := "Appreciations" index, err := f.NewSheet(sheetName) if err != nil { - logger.Errorf("err in generating newsheet, err: %v", err) + logger.Errorf(ctx, "err in generating newsheet, err: %v", err) return } // Set header headers := []string{"Core value", "Core value description", "Appreciation description", "Sender first name", "Sender last name", "Sender designation", "Receiver first name", "Receiver last name", "Receiver designation", "Total rewards", "Total reward points"} for colIndex, header := range headers { - cell := fmt.Sprintf("%s1", string('A'+colIndex)) + + cell := fmt.Sprintf("%c1", 'A'+colIndex) f.SetCellValue(sheetName, cell, header) } @@ -649,7 +650,7 @@ func (us *service) AllAppreciationReport(ctx context.Context, appreciations []dt // Save the Excel file temporarily tempFileName = "report.xlsx" if err = f.SaveAs(tempFileName); err != nil { - logger.Errorf("Failed to save file: %v", err) + logger.Errorf(ctx, "Failed to save file: %v", err) return } @@ -665,14 +666,14 @@ func (us *service) ReportedAppreciationReport(ctx context.Context, appreciations sheetName := "ReportedAppreciations" index, err := f.NewSheet(sheetName) if err != nil { - logger.Errorf("err in generating newsheet, err: %v", err) + logger.Errorf(ctx, "err in generating newsheet, err: %v", err) return } // Set header headers := []string{"Core value", "Core value description", "Appreciation description", "Sender first name", "Sender last name", "Sender designation", "Receiver first name", "Receiver last name", "Receiver designation", "Reporting Comment", "Reported by first name", "Reported by last name", "Reported at", "Moderator comment", "Moderator first name", "Moderator last name", "Status"} for colIndex, header := range headers { - cell := fmt.Sprintf("%s1", string('A'+colIndex)) + cell := fmt.Sprintf("%c1", 'A'+colIndex) f.SetCellValue(sheetName, cell, header) } @@ -704,7 +705,7 @@ func (us *service) ReportedAppreciationReport(ctx context.Context, appreciations // Save the Excel file temporarily tempFileName = "reportedAppreciations.xlsx" if err = f.SaveAs(tempFileName); err != nil { - logger.Errorf("Failed to save file: %v", err) + logger.Errorf(ctx, "Failed to save file: %v", err) return } diff --git a/internal/app/users/service_test.go b/internal/app/users/service_test.go index 29b2227..007ded4 100644 --- a/internal/app/users/service_test.go +++ b/internal/app/users/service_test.go @@ -503,20 +503,16 @@ func TestGetActiveUserList(t *testing.T) { }, expectedResp: []dto.ActiveUser{ { - ID: 55, - FirstName: "Deepak", - LastName: "Kumar", - ProfileImageURL: "", - BadgeName: "", - AppreciationPoints: 0, + ID: 55, + FirstName: "Deepak", + LastName: "Kumar", + ProfileImageURL: "", }, { - ID: 58, - FirstName: "Dominic", - LastName: "Lopes", - ProfileImageURL: "", - BadgeName: "Gold", - AppreciationPoints: 5000, + ID: 58, + FirstName: "Dominic", + LastName: "Lopes", + ProfileImageURL: "", }, }, expectedError: nil, diff --git a/internal/pkg/apperrors/errors.go b/internal/pkg/apperrors/errors.go index 3468839..f3c3280 100644 --- a/internal/pkg/apperrors/errors.go +++ b/internal/pkg/apperrors/errors.go @@ -73,6 +73,12 @@ const ( InvalidPage = CustomError("Invalid page value") NegativeGradePoints = CustomError("Grade points cannot be negative") NegativeBadgePoints = CustomError("Badge reward points cannot be negative") + UnauthorizedDeveloper = CustomError("Unauthorised developer") + InvalidLoggerLevel = CustomError("Invalid Logger Level") + InvalidTos = CustomError("recipient email addresses are required") + InvalidFrom = CustomError("sender email address is required") + InvalidBody = CustomError("email body is required") + InvalidSub = CustomError("email subject is required") ) // ErrKeyNotSet - Returns error object specific to the key value passed in @@ -87,11 +93,11 @@ func GetHTTPStatusCode(err error) int { return http.StatusInternalServerError case OrganizationConfigNotFound, OrganizationNotFound, InvalidOrgId, GradeNotFound, AppreciationNotFound, PageParamNotFound, InvalidCoreValueData, InvalidIntranetData: return http.StatusNotFound - case BadRequest, InvalidId, JSONParsingErrorReq, TextFieldBlank, InvalidParentValue, DescFieldBlank, UniqueCoreValue, SelfAppreciationError, CannotReportOwnAppreciation, RepeatedReport, InvalidCoreValueID, InvalidReceiverID, InvalidRewardMultiplier, InvalidRewardQuotaRenewalFrequency, InvalidTimezone, InvalidRewardPoint, InvalidEmail, InvalidPassword, DescriptionLengthExceed, InvalidPageSize, InvalidPage, NegativeGradePoints, NegativeBadgePoints: + case InvalidLoggerLevel, BadRequest, InvalidId, JSONParsingErrorReq, TextFieldBlank, InvalidParentValue, DescFieldBlank, UniqueCoreValue, SelfAppreciationError, CannotReportOwnAppreciation, RepeatedReport, InvalidCoreValueID, InvalidReceiverID, InvalidRewardMultiplier, InvalidRewardQuotaRenewalFrequency, InvalidTimezone, InvalidRewardPoint, InvalidEmail, InvalidPassword, DescriptionLengthExceed, InvalidPageSize, InvalidPage, NegativeGradePoints, NegativeBadgePoints: return http.StatusBadRequest case InvalidContactEmail, InvalidDomainName, UserAlreadyPresent, RewardAlreadyPresent, RepeatedUser: return http.StatusConflict - case InvalidAuthToken, RoleUnathorized, IntranetValidationFailed: + case InvalidAuthToken, RoleUnathorized, IntranetValidationFailed, UnauthorizedDeveloper: return http.StatusUnauthorized case RewardQuotaIsNotSufficient: return http.StatusUnprocessableEntity diff --git a/internal/pkg/config/config.go b/internal/pkg/config/config.go index de00f59..f97966f 100644 --- a/internal/pkg/config/config.go +++ b/internal/pkg/config/config.go @@ -103,3 +103,7 @@ func PeerlyBaseUrl() string { func IntranetBaseUrl() string { return (ReadEnvString(constants.IntranetBaseUrl)) } + +func DeveloperKey() string { + return (ReadEnvString(constants.DeveloperKey)) +} diff --git a/internal/pkg/constants/system.go b/internal/pkg/constants/system.go index bac0232..3173107 100644 --- a/internal/pkg/constants/system.go +++ b/internal/pkg/constants/system.go @@ -1,7 +1,9 @@ package constants + type UserIdCtxKey string type RoleCtxKey string +type RequestIDCtxKey string // System Constants used to setup environment and basic functionality const ( @@ -17,20 +19,27 @@ const ( IntranetBaseUrl = "INTRANET_BASE_URL" POST = "POST" GET = "GET" + DeveloperKey = "DEVELOPER_KEY" +) + +const ( + Admin int = iota + User ) // User required constants const ( - AuthorizationHeader = "Authorization" - ClientCode = "Client-Code" - UserRole = "user" - AdminRole = "admin" - UserId UserIdCtxKey = "userId" - Role RoleCtxKey = "role" - IntranetAuth = "Intranet-Auth" - PeerlyValidationPath = "/api/peerly/v1/sessions/login" - GetIntranetUserDataPath = "/api/peerly/v1/users/" - ListIntranetUsersPath = "/api/peerly/v1/users?page=%d&per_page=%d" + RequestID RequestIDCtxKey = "RequestID" + AuthorizationHeader = "Authorization" + ClientCode = "Client-Code" + UserRole = "user" + AdminRole = "admin" + UserId UserIdCtxKey = "userId" + Role RoleCtxKey = "role" + IntranetAuth = "Intranet-Auth" + PeerlyValidationPath = "/api/peerly/v1/sessions/login" + GetIntranetUserDataPath = "/api/peerly/v1/users/" + ListIntranetUsersPath = "/api/peerly/v1/users?page=%d&per_page=%d" ) // Pagination Metadata constants @@ -53,3 +62,23 @@ const ( ) const DefaultOrgID = 1 + +// EmailTemplate Icon url +const ( + BronzeBadgeIconImagePath = "/peerly/assets/bronzeBadge.png" + SilverBadgeIconImagePath = "/peerly/assets/silverBadge.png" + GoldBadgeIconImagePath = "/peerly/assets/goldBadge.png" + PlatinumIconImagePath = "/peerly/assets/platinumBadge.png" + CheckIconImagePath = "/peerly/assets/checkIcon.png" + ClosedEnvelopeIconImagePath = "/peerly/assets/closedEnvelopeIcon.png" + OpenEnvelopeIconImagePath = "/peerly/assets/openEnvelopeIcon.png" + RewardQuotaRenewalIconImagePath = "/peerly/assets/rewardQuotaRenewal.png" +) + +//notificatio service account key file +const ServiceAccountKey = "serviceAccountKey.json" + +const AppreciationID = "appreciation_id" + +// Email Dl group of HRs +const HRDLGroup = "dl_peerly.support@joshsoftware.com" \ No newline at end of file diff --git a/internal/pkg/dto/log.go b/internal/pkg/dto/log.go new file mode 100644 index 0000000..cec38c3 --- /dev/null +++ b/internal/pkg/dto/log.go @@ -0,0 +1,6 @@ +package dto + +type ChangeLogLevelRequest struct { + LogLevel string `json:"loglevel"` + DeveloperKey string `json:"developer_key"` +} \ No newline at end of file diff --git a/internal/pkg/dto/reportAppreciations.go b/internal/pkg/dto/reportAppreciations.go index 58899d0..2c1dfdd 100644 --- a/internal/pkg/dto/reportAppreciations.go +++ b/internal/pkg/dto/reportAppreciations.go @@ -68,12 +68,13 @@ type ModerationReq struct { } type DeleteAppreciationMail struct { - ModeratorComment string - AppreciationBy string - AppreciationTo string - ReportingComment string - AppreciationDesc string - Date int64 + ModeratorComment string + AppreciationBy string + AppreciationTo string + ReportingComment string + AppreciationDesc string + Date int64 + ReportIconImageURL string } type ResolveAppreciationMail struct { diff --git a/internal/pkg/dto/users.go b/internal/pkg/dto/users.go index b7ec808..cec99dd 100644 --- a/internal/pkg/dto/users.go +++ b/internal/pkg/dto/users.go @@ -64,7 +64,7 @@ type GetIntranetUserDataReq struct { type Claims struct { Id int64 - Role string + Role int jwt.StandardClaims } @@ -109,10 +109,10 @@ type ListUsersReq struct { } type ActiveUser struct { - ID int `json:"id"` - FirstName string `json:"first_name"` - LastName string `json:"last_name"` - ProfileImageURL string `json:"profile_image_url"` + ID int `json:"id"` + FirstName string `json:"first_name"` + LastName string `json:"last_name"` + ProfileImageURL string `json:"profile_image_url"` // BadgeName string `json:"badge_name"` // AppreciationPoints int `json:"appreciation_points"` } diff --git a/internal/pkg/logger/log.go b/internal/pkg/logger/log.go index ea9b121..cf19033 100644 --- a/internal/pkg/logger/log.go +++ b/internal/pkg/logger/log.go @@ -1,25 +1,95 @@ package log import ( + "context" + "fmt" + "io" + "os" + "time" + + "github.com/joshsoftware/peerly-backend/internal/pkg/constants" l "github.com/sirupsen/logrus" + "gopkg.in/natefinch/lumberjack.v2" ) +var Logger *l.Logger + +var lumberjackLogger = &lumberjack.Logger{ + MaxSize: 100, // megabytes + MaxBackups: 3, // number of log files + MaxAge: 365, // days + Compress: true, +} + // Error - prints out an error -func Error(appError error, msg string, triggeringError error) { - l.WithFields(l.Fields{"appError": appError, "message": msg}).Error(triggeringError) +func Error(ctx context.Context, args ...interface{}) { + log := setRequestId(ctx) + log.Error(args...) } -// Warn - for warnings -func Warn(appError error, msg string, triggeringError error) { - l.WithFields(l.Fields{"appError": appError, "message": msg}).Warn(triggeringError) +// Errorf - prints out an error with formatted output +func Errorf(ctx context.Context, format string, args ...interface{}) { + log := setRequestId(ctx) + log.Errorf(format,args...) +} + +// Warn - prints out a warning +func Warn(ctx context.Context, args ...interface{}) { + log := setRequestId(ctx) + log.Warn(args...) } // Fatal - will print out the error info and exit the program -func Fatal(appError error, msg string, triggeringError error) { - l.WithFields(l.Fields{"appError": appError, "message": msg}).Fatal(triggeringError) +func Fatal(ctx context.Context, args ...interface{}) { + log := setRequestId(ctx) + log.Fatal(args...) } // Info - prints out basic information -func Info(msg string) { - l.WithFields(l.Fields{"info": msg}).Info(msg) +func Info(ctx context.Context, args ...interface{}) { + log := setRequestId(ctx) + log.Info(args...) +} + +// Infof - prints out basic information +func Infof(ctx context.Context, format string, args ...interface{}) { + log := setRequestId(ctx) + log.Infof(format,args...) +} + +// Debug - prints out debug information +func Debug(ctx context.Context, args ...interface{}) { + log := setRequestId(ctx) + log.Debug(args...) +} + +func SetupLogger() (*l.Logger, error) { + + lumberjackLogger.Filename = fmt.Sprintf("/var/log/peerly/%s_peerly_backend.log", time.Now().Format("2006-01-02_15-04-05")) + file, err := os.Create(lumberjackLogger.Filename) + if err != nil { + return nil, fmt.Errorf("failed to create log file: %w", err) + } + file.Close() + + // Initialize Logrus logger + logger := l.New() + logger.SetOutput(io.MultiWriter(os.Stdout, lumberjackLogger)) + logger.SetFormatter(&l.TextFormatter{ + FullTimestamp: true, + }) + + // Set the logging level + logger.SetLevel(l.InfoLevel) + + Logger = logger + return logger, nil +} + +func setRequestId(ctx context.Context) *l.Entry{ + requestID, ok := ctx.Value(constants.RequestID).(string) + if !ok { + requestID = "N/A" + } + return Logger.WithField("req_id",requestID) } diff --git a/internal/pkg/middleware/jwtMiddleware.go b/internal/pkg/middleware/jwtMiddleware.go index ecd541d..0bad35d 100644 --- a/internal/pkg/middleware/jwtMiddleware.go +++ b/internal/pkg/middleware/jwtMiddleware.go @@ -4,10 +4,10 @@ import ( "context" "fmt" "net/http" - "slices" "strings" "github.com/dgrijalva/jwt-go" + "github.com/google/uuid" "github.com/joshsoftware/peerly-backend/internal/pkg/apperrors" "github.com/joshsoftware/peerly-backend/internal/pkg/config" "github.com/joshsoftware/peerly-backend/internal/pkg/constants" @@ -15,7 +15,7 @@ import ( logger "github.com/sirupsen/logrus" ) -func JwtAuthMiddleware(next http.Handler, roles []string) http.Handler { +func JwtAuthMiddleware(next http.Handler, role int) http.Handler { return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { jwtKey := config.JWTKey() authToken := req.Header.Get(constants.AuthorizationHeader) @@ -50,7 +50,7 @@ func JwtAuthMiddleware(next http.Handler, roles []string) http.Handler { Id := claims.Id Role := claims.Role - if !slices.Contains(roles, Role) { + if Role > role { err := apperrors.RoleUnathorized dto.ErrorRepsonse(rw, err) return @@ -60,9 +60,20 @@ func JwtAuthMiddleware(next http.Handler, roles []string) http.Handler { fmt.Println("setting id: ", Id) ctx := context.WithValue(req.Context(), constants.UserId, Id) ctx = context.WithValue(ctx, constants.Role, Role) + req = req.WithContext(ctx) next.ServeHTTP(rw, req) }) } + +// RequestIDMiddleware generates a request ID and adds it to the request context. +func RequestIDMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + requestID := uuid.NewString() + ctx := context.WithValue(r.Context(), constants.RequestID, requestID) + r = r.WithContext(ctx) + next.ServeHTTP(w, r) + }) +} diff --git a/internal/repository/migrations/1723875193_moderation.up.sql b/internal/repository/migrations/1723875193_moderation.up.sql index fd4c3a0..5570861 100644 --- a/internal/repository/migrations/1723875193_moderation.up.sql +++ b/internal/repository/migrations/1723875193_moderation.up.sql @@ -1,4 +1,4 @@ -IF NOT EXISTS create type status as enum('reported','resolved','deleted'); +create type status as enum('reported','resolved','deleted'); alter table resolutions add status status diff --git a/internal/repository/mocks/AppreciationStorer.go b/internal/repository/mocks/AppreciationStorer.go index 675a209..4c35c92 100644 --- a/internal/repository/mocks/AppreciationStorer.go +++ b/internal/repository/mocks/AppreciationStorer.go @@ -1,17 +1,12 @@ -// Code generated by mockery v2.43.2. DO NOT EDIT. +// Code generated by mockery v1.0.0. DO NOT EDIT. package mocks -import ( - context "context" - - dto "github.com/joshsoftware/peerly-backend/internal/pkg/dto" - mock "github.com/stretchr/testify/mock" - - repository "github.com/joshsoftware/peerly-backend/internal/repository" - - sqlx "github.com/jmoiron/sqlx" -) +import context "context" +import dto "github.com/joshsoftware/peerly-backend/internal/pkg/dto" +import mock "github.com/stretchr/testify/mock" +import repository "github.com/joshsoftware/peerly-backend/internal/repository" +import sqlx "github.com/jmoiron/sqlx" // AppreciationStorer is an autogenerated mock type for the AppreciationStorer type type AppreciationStorer struct { @@ -22,15 +17,7 @@ type AppreciationStorer struct { func (_m *AppreciationStorer) BeginTx(ctx context.Context) (repository.Transaction, error) { ret := _m.Called(ctx) - if len(ret) == 0 { - panic("no return value specified for BeginTx") - } - var r0 repository.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(context.Context) (repository.Transaction, error)); ok { - return rf(ctx) - } if rf, ok := ret.Get(0).(func(context.Context) repository.Transaction); ok { r0 = rf(ctx) } else { @@ -39,6 +26,7 @@ func (_m *AppreciationStorer) BeginTx(ctx context.Context) (repository.Transacti } } + var r1 error if rf, ok := ret.Get(1).(func(context.Context) error); ok { r1 = rf(ctx) } else { @@ -52,21 +40,14 @@ func (_m *AppreciationStorer) BeginTx(ctx context.Context) (repository.Transacti func (_m *AppreciationStorer) CreateAppreciation(ctx context.Context, tx repository.Transaction, appreciation dto.Appreciation) (repository.Appreciation, error) { ret := _m.Called(ctx, tx, appreciation) - if len(ret) == 0 { - panic("no return value specified for CreateAppreciation") - } - var r0 repository.Appreciation - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, repository.Transaction, dto.Appreciation) (repository.Appreciation, error)); ok { - return rf(ctx, tx, appreciation) - } if rf, ok := ret.Get(0).(func(context.Context, repository.Transaction, dto.Appreciation) repository.Appreciation); ok { r0 = rf(ctx, tx, appreciation) } else { r0 = ret.Get(0).(repository.Appreciation) } + var r1 error if rf, ok := ret.Get(1).(func(context.Context, repository.Transaction, dto.Appreciation) error); ok { r1 = rf(ctx, tx, appreciation) } else { @@ -80,10 +61,6 @@ func (_m *AppreciationStorer) CreateAppreciation(ctx context.Context, tx reposit func (_m *AppreciationStorer) DeleteAppreciation(ctx context.Context, tx repository.Transaction, apprId int32) error { ret := _m.Called(ctx, tx, apprId) - if len(ret) == 0 { - panic("no return value specified for DeleteAppreciation") - } - var r0 error if rf, ok := ret.Get(0).(func(context.Context, repository.Transaction, int32) error); ok { r0 = rf(ctx, tx, apprId) @@ -98,21 +75,14 @@ func (_m *AppreciationStorer) DeleteAppreciation(ctx context.Context, tx reposit func (_m *AppreciationStorer) GetAppreciationById(ctx context.Context, tx repository.Transaction, appreciationId int32) (repository.AppreciationResponse, error) { ret := _m.Called(ctx, tx, appreciationId) - if len(ret) == 0 { - panic("no return value specified for GetAppreciationById") - } - var r0 repository.AppreciationResponse - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, repository.Transaction, int32) (repository.AppreciationResponse, error)); ok { - return rf(ctx, tx, appreciationId) - } if rf, ok := ret.Get(0).(func(context.Context, repository.Transaction, int32) repository.AppreciationResponse); ok { r0 = rf(ctx, tx, appreciationId) } else { r0 = ret.Get(0).(repository.AppreciationResponse) } + var r1 error if rf, ok := ret.Get(1).(func(context.Context, repository.Transaction, int32) error); ok { r1 = rf(ctx, tx, appreciationId) } else { @@ -126,10 +96,6 @@ func (_m *AppreciationStorer) GetAppreciationById(ctx context.Context, tx reposi func (_m *AppreciationStorer) HandleTransaction(ctx context.Context, tx repository.Transaction, isSuccess bool) error { ret := _m.Called(ctx, tx, isSuccess) - if len(ret) == 0 { - panic("no return value specified for HandleTransaction") - } - var r0 error if rf, ok := ret.Get(0).(func(context.Context, repository.Transaction, bool) error); ok { r0 = rf(ctx, tx, isSuccess) @@ -144,10 +110,6 @@ func (_m *AppreciationStorer) HandleTransaction(ctx context.Context, tx reposito func (_m *AppreciationStorer) InitiateQueryExecutor(tx repository.Transaction) sqlx.Ext { ret := _m.Called(tx) - if len(ret) == 0 { - panic("no return value specified for InitiateQueryExecutor") - } - var r0 sqlx.Ext if rf, ok := ret.Get(0).(func(repository.Transaction) sqlx.Ext); ok { r0 = rf(tx) @@ -164,21 +126,14 @@ func (_m *AppreciationStorer) InitiateQueryExecutor(tx repository.Transaction) s func (_m *AppreciationStorer) IsUserPresent(ctx context.Context, tx repository.Transaction, userID int64) (bool, error) { ret := _m.Called(ctx, tx, userID) - if len(ret) == 0 { - panic("no return value specified for IsUserPresent") - } - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, repository.Transaction, int64) (bool, error)); ok { - return rf(ctx, tx, userID) - } if rf, ok := ret.Get(0).(func(context.Context, repository.Transaction, int64) bool); ok { r0 = rf(ctx, tx, userID) } else { r0 = ret.Get(0).(bool) } + var r1 error if rf, ok := ret.Get(1).(func(context.Context, repository.Transaction, int64) error); ok { r1 = rf(ctx, tx, userID) } else { @@ -192,16 +147,7 @@ func (_m *AppreciationStorer) IsUserPresent(ctx context.Context, tx repository.T func (_m *AppreciationStorer) ListAppreciations(ctx context.Context, tx repository.Transaction, filter dto.AppreciationFilter) ([]repository.AppreciationResponse, repository.Pagination, error) { ret := _m.Called(ctx, tx, filter) - if len(ret) == 0 { - panic("no return value specified for ListAppreciations") - } - var r0 []repository.AppreciationResponse - var r1 repository.Pagination - var r2 error - if rf, ok := ret.Get(0).(func(context.Context, repository.Transaction, dto.AppreciationFilter) ([]repository.AppreciationResponse, repository.Pagination, error)); ok { - return rf(ctx, tx, filter) - } if rf, ok := ret.Get(0).(func(context.Context, repository.Transaction, dto.AppreciationFilter) []repository.AppreciationResponse); ok { r0 = rf(ctx, tx, filter) } else { @@ -210,12 +156,14 @@ func (_m *AppreciationStorer) ListAppreciations(ctx context.Context, tx reposito } } + var r1 repository.Pagination if rf, ok := ret.Get(1).(func(context.Context, repository.Transaction, dto.AppreciationFilter) repository.Pagination); ok { r1 = rf(ctx, tx, filter) } else { r1 = ret.Get(1).(repository.Pagination) } + var r2 error if rf, ok := ret.Get(2).(func(context.Context, repository.Transaction, dto.AppreciationFilter) error); ok { r2 = rf(ctx, tx, filter) } else { @@ -225,8 +173,50 @@ func (_m *AppreciationStorer) ListAppreciations(ctx context.Context, tx reposito return r0, r1, r2 } -// NewAppreciationStorer creates a new instance of AppreciationStorer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. +// UpdateAppreciationTotalRewardsOfYesterday provides a mock function with given fields: ctx, tx +func (_m *AppreciationStorer) UpdateAppreciationTotalRewardsOfYesterday(ctx context.Context, tx repository.Transaction) (bool, error) { + ret := _m.Called(ctx, tx) + + var r0 bool + if rf, ok := ret.Get(0).(func(context.Context, repository.Transaction) bool); ok { + r0 = rf(ctx, tx) + } else { + r0 = ret.Get(0).(bool) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, repository.Transaction) error); ok { + r1 = rf(ctx, tx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// UpdateUserBadgesBasedOnTotalRewards provides a mock function with given fields: ctx, tx +func (_m *AppreciationStorer) UpdateUserBadgesBasedOnTotalRewards(ctx context.Context, tx repository.Transaction) ([]repository.UserBadgeDetails, error) { + ret := _m.Called(ctx, tx) + + var r0 []repository.UserBadgeDetails + if rf, ok := ret.Get(0).(func(context.Context, repository.Transaction) []repository.UserBadgeDetails); ok { + r0 = rf(ctx, tx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]repository.UserBadgeDetails) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, repository.Transaction) error); ok { + r1 = rf(ctx, tx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + func NewAppreciationStorer(t interface { mock.TestingT Cleanup(func()) diff --git a/internal/repository/mocks/ReportAppreciationStorer.go b/internal/repository/mocks/ReportAppreciationStorer.go index e2e5eb5..90d1a86 100644 --- a/internal/repository/mocks/ReportAppreciationStorer.go +++ b/internal/repository/mocks/ReportAppreciationStorer.go @@ -96,6 +96,27 @@ func (_m *ReportAppreciationStorer) DeleteAppreciation(ctx context.Context, mode return r0 } +// GetResolution provides a mock function with given fields: ctx, id +func (_m *ReportAppreciationStorer) GetResolution(ctx context.Context, id int64) (repository.ListReportedAppreciations, error) { + ret := _m.Called(ctx, id) + + var r0 repository.ListReportedAppreciations + if rf, ok := ret.Get(0).(func(context.Context, int64) repository.ListReportedAppreciations); ok { + r0 = rf(ctx, id) + } else { + r0 = ret.Get(0).(repository.ListReportedAppreciations) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { + r1 = rf(ctx, id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GetSenderAndReceiver provides a mock function with given fields: ctx, reqData func (_m *ReportAppreciationStorer) GetSenderAndReceiver(ctx context.Context, reqData dto.ReportAppreciationReq) (dto.GetSenderAndReceiverResp, error) { ret := _m.Called(ctx, reqData) @@ -161,6 +182,20 @@ func (_m *ReportAppreciationStorer) ReportAppreciation(ctx context.Context, repo return r0, r1 } +// ResolveAppreciation provides a mock function with given fields: ctx, moderationReq +func (_m *ReportAppreciationStorer) ResolveAppreciation(ctx context.Context, moderationReq dto.ModerationReq) error { + ret := _m.Called(ctx, moderationReq) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, dto.ModerationReq) error); ok { + r0 = rf(ctx, moderationReq) + } else { + r0 = ret.Error(0) + } + + return r0 +} + func NewReportAppreciationStorer(t interface { mock.TestingT Cleanup(func()) diff --git a/internal/repository/mocks/UserStorer.go b/internal/repository/mocks/UserStorer.go index 29df5de..33cb751 100644 --- a/internal/repository/mocks/UserStorer.go +++ b/internal/repository/mocks/UserStorer.go @@ -386,3 +386,4 @@ func NewUserStorer(t interface { return mock } + diff --git a/internal/repository/postgresdb/appreciation.go b/internal/repository/postgresdb/appreciation.go index 169d911..502f185 100644 --- a/internal/repository/postgresdb/appreciation.go +++ b/internal/repository/postgresdb/appreciation.go @@ -6,7 +6,6 @@ import ( "fmt" "slices" "strings" - "time" "github.com/Masterminds/squirrel" "github.com/jmoiron/sqlx" @@ -14,7 +13,7 @@ import ( "github.com/joshsoftware/peerly-backend/internal/pkg/constants" "github.com/joshsoftware/peerly-backend/internal/pkg/dto" "github.com/joshsoftware/peerly-backend/internal/repository" - logger "github.com/sirupsen/logrus" + logger "github.com/joshsoftware/peerly-backend/internal/pkg/logger" ) var AppreciationColumns = []string{"id", "core_value_id", "description", "quarter", "sender", "receiver"} @@ -39,6 +38,7 @@ func NewAppreciationRepo(db *sqlx.DB) repository.AppreciationStorer { func (appr *appreciationsStore) CreateAppreciation(ctx context.Context, tx repository.Transaction, appreciation dto.Appreciation) (repository.Appreciation, error) { + logger.Debug(ctx,"repoAppr: CreateAppreciation: appreciation: ",appreciation) queryExecutor := appr.InitiateQueryExecutor(tx) insertQuery, args, err := repository.Sq. @@ -47,29 +47,33 @@ func (appr *appreciationsStore) CreateAppreciation(ctx context.Context, tx repos Suffix("RETURNING id,core_value_id, description,total_reward_points,quarter,sender,receiver,created_at,updated_at"). ToSql() if err != nil { - logger.Errorf("error in generating squirrel query, err: %v", err) + logger.Errorf(ctx,"repoAppr: error in generating squirrel query, err: %v", err) return repository.Appreciation{}, apperrors.InternalServerError } + logger.Infof(ctx,"repoAppr: insertQuery: %s , args: %v",insertQuery,args) + var resAppr repository.Appreciation err = queryExecutor.QueryRowx(insertQuery, args...).StructScan(&resAppr) if err != nil { - logger.Errorf("Error executing create appreciation insert query: %v", err) + logger.Errorf(ctx,"repoAppr: Error executing create appreciation insert query: %v", err) return repository.Appreciation{}, apperrors.InternalServer } + logger.Debug(ctx,"repoAppr: createappreciation response: ",resAppr) return resAppr, nil } func (appr *appreciationsStore) GetAppreciationById(ctx context.Context, tx repository.Transaction, apprId int32) (repository.AppreciationResponse, error) { + logger.Debug(ctx,"repoAppr: GetAppreciationById: apprId: ",apprId) queryExecutor := appr.InitiateQueryExecutor(tx) // Get logged-in user ID data := ctx.Value(constants.UserId) userID, ok := data.(int64) if !ok { - logger.Error("err in parsing userID from token") + logger.Error(ctx,"err in parsing userID from token") return repository.AppreciationResponse{}, apperrors.InternalServer } @@ -113,33 +117,37 @@ func (appr *appreciationsStore) GetAppreciationById(ctx context.Context, tx repo ToSql() if err != nil { - logger.Errorf("error in generating squirrel query, err: %v", err) + logger.Errorf(ctx,"error in generating squirrel query, err: %v", err) return repository.AppreciationResponse{}, apperrors.InternalServer } + logger.Infof(ctx,"repoAppr: insertQuery: %s , args: %v",query,args) + var resAppr repository.AppreciationResponse // Execute the query err = queryExecutor.QueryRowx(query, args...).StructScan(&resAppr) if err != nil { if err == sql.ErrNoRows { - logger.Warn(fmt.Sprintf("no appreciation found with id: %d", apprId)) + logger.Errorf(ctx,"repoAppr: no appreciation found with id: %d", apprId) return repository.AppreciationResponse{}, apperrors.AppreciationNotFound } - logger.Errorf("failed to execute query: %v", err) + logger.Errorf(ctx,"repoAppr: failed to execute query: %v", err) return repository.AppreciationResponse{}, apperrors.InternalServer } + logger.Debug(ctx,"repoAppr: appreciationById: ",resAppr) return resAppr, nil } func (appr *appreciationsStore) ListAppreciations(ctx context.Context, tx repository.Transaction, filter dto.AppreciationFilter) ([]repository.AppreciationResponse, repository.Pagination, error) { + logger.Debug(ctx,"repoAppr: ListAppreciations: filter: ",filter) queryExecutor := appr.InitiateQueryExecutor(tx) // Get logged-in user ID data := ctx.Value(constants.UserId) userID, ok := data.(int64) if !ok { - logger.Error("err in parsing userID from token") + logger.Error(ctx,"err in parsing userID from token") return []repository.AppreciationResponse{}, repository.Pagination{}, apperrors.InternalServerError } @@ -169,18 +177,21 @@ func (appr *appreciationsStore) ListAppreciations(ctx context.Context, tx reposi countSql, countArgs, err := queryBuilder.ToSql() if err != nil { - logger.Error("failed to build count query: ", err.Error()) + logger.Error(ctx,"repoAppr: failed to build count query: ", err.Error()) return []repository.AppreciationResponse{}, repository.Pagination{}, apperrors.InternalServerError } + logger.Debug(ctx,fmt.Sprintf("repoAppr: listAppreciation: countSql: %s, countArgs: %v",countSql,countArgs)) + var totalRecords int32 err = queryExecutor.QueryRowx(countSql, countArgs...).Scan(&totalRecords) if err != nil { - logger.Error("failed to execute count query: ", err.Error()) + logger.Error(ctx,"failed to execute count query: ", err.Error()) return []repository.AppreciationResponse{}, repository.Pagination{}, apperrors.InternalServerError } pagination := getPaginationMetaData(filter.Page, filter.Limit, totalRecords) + logger.Debug(ctx," pagination: ",pagination) queryBuilder = queryBuilder.RemoveColumns() queryBuilder = queryBuilder.Columns( "a.id", @@ -223,71 +234,56 @@ func (appr *appreciationsStore) ListAppreciations(ctx context.Context, tx reposi } offset := (filter.Page - 1) * filter.Limit - // Add pagination queryBuilder = queryBuilder.Limit(uint64(filter.Limit)).Offset(uint64(offset)) sql, args, err := queryBuilder.ToSql() if err != nil { - logger.Error("failed to build query: ", err.Error()) + logger.Error(ctx,"failed to build query: ", err.Error()) return nil, repository.Pagination{}, apperrors.InternalServerError } + logger.Debug(ctx,fmt.Sprintf("repoAppr: listAprreciation: sqlQuery: %s,args: %v",sql,args)) queryExecutor = appr.InitiateQueryExecutor(tx) res := make([]repository.AppreciationResponse, 0) - - logger.Info("sp : filter: ", filter) - logger.Info("sp : sql: ", sql) - logger.Info("sp : args: ", args) err = sqlx.Select(queryExecutor, &res, sql, args...) if err != nil { - logger.Error("failed to execute query appreciation: ", err.Error()) - logger.Error("err res data: ", res) + logger.Error(ctx,"repoAppr:failed to execute query appreciation: ", err.Error()) return nil, repository.Pagination{}, apperrors.InternalServerError } + logger.Error(ctx,"repoAppr: res data: ", res) id := ctx.Value(constants.UserId) - fmt.Println("id -> ", id) + logger.Debug(ctx," id -> ", id) userId, ok := ctx.Value(constants.UserId).(int64) if !ok { - logger.Error("unable to convert context user id to int64") + logger.Error(ctx,"unable to convert context user id to int64") return nil, repository.Pagination{}, apperrors.InternalServerError } + logger.Debug(ctx," userId: ",userId) for idx, appreciation := range res { var userIds []int64 queryBuilder = repository.Sq.Select("reported_by").From("resolutions").Where(squirrel.Eq{"appreciation_id": appreciation.ID}) query, args, err := queryBuilder.ToSql() if err != nil { - logger.Errorf("error in generating squirrel query, err: %s", err.Error()) + logger.Errorf(ctx,"error in generating squirrel query, err: %s", err.Error()) return nil, repository.Pagination{}, apperrors.InternalServerError } - err = appr.DB.SelectContext(ctx, &userIds, query, args...) - if err != nil { - logger.Errorf("error in reported flag query, err: %s", err.Error()) - return nil, repository.Pagination{}, apperrors.InternalServerError - } - res[idx].ReportedFlag = slices.Contains(userIds, userId) - } - for idx, appreciation := range res { - var userIds []int64 - queryBuilder = repository.Sq.Select("reported_by").From("resolutions").Where(squirrel.Eq{"appreciation_id": appreciation.ID}) - query, args, err := queryBuilder.ToSql() - if err != nil { - logger.Errorf("error in generating squirrel query, err: %s", err.Error()) - return nil, repository.Pagination{}, apperrors.InternalServerError - } + logger.Debug(ctx,fmt.Sprintf("repoAppr: resolutions query: %s,args: %v",query,args)) err = appr.DB.SelectContext(ctx, &userIds, query, args...) if err != nil { - logger.Errorf("error in reported flag query, err: %s", err.Error()) + logger.Errorf(ctx,"error in reported flag query, err: %s", err.Error()) return nil, repository.Pagination{}, apperrors.InternalServerError } res[idx].ReportedFlag = slices.Contains(userIds, userId) } + logger.Debug(ctx,fmt.Sprintf("repoAppr: res: %v, pagination : %v",res,pagination)) return res, pagination, nil } func (appr *appreciationsStore) DeleteAppreciation(ctx context.Context, tx repository.Transaction, apprId int32) error { + logger.Debug(ctx,"repoAppr: apprId: ",apprId) query, args, err := repository.Sq.Update(appr.AppreciationsTable). Set("is_valid", false). Where(squirrel.And{ @@ -296,8 +292,9 @@ func (appr *appreciationsStore) DeleteAppreciation(ctx context.Context, tx repos }). ToSql() + logger.Debug(ctx,fmt.Sprintf("repoAppr: query: %s,args: %v",query,args)) if err != nil { - logger.Error("Error building SQL: ", err.Error()) + logger.Error(ctx,"Error building SQL: ", err.Error()) return apperrors.InternalServer } @@ -305,18 +302,18 @@ func (appr *appreciationsStore) DeleteAppreciation(ctx context.Context, tx repos result, err := queryExecutor.Exec(query, args...) if err != nil { - logger.Error("Error executing SQL: ", err.Error()) + logger.Error(ctx,"Error executing SQL: ", err.Error()) return apperrors.InternalServer } rowsAffected, err := result.RowsAffected() if err != nil { - logger.Error("Error getting rows affected: ", err.Error()) + logger.Error(ctx,"Error getting rows affected: ", err.Error()) return apperrors.InternalServer } if rowsAffected == 0 { - logger.Warn("No rows affected") + logger.Warn(ctx,"No rows affected") return apperrors.AppreciationNotFound } @@ -325,54 +322,40 @@ func (appr *appreciationsStore) DeleteAppreciation(ctx context.Context, tx repos func (appr *appreciationsStore) IsUserPresent(ctx context.Context, tx repository.Transaction, userID int64) (bool, error) { + logger.Debug(ctx,"repoAppr: IsUserPresent: userID: ",userID) // Build the SQL query query, args, err := repository.Sq.Select("COUNT(*)"). From(appr.UsersTable). Where(squirrel.Eq{"id": userID}). ToSql() + logger.Debug(ctx," query: ",query) if err != nil { - logger.Error("err ", err.Error()) + logger.Error(ctx,"err ", err.Error()) return false, apperrors.InternalServer } + logger.Debug(ctx,fmt.Sprintf("repoAppr: query: %s,args: %v",query,args)) queryExecutor := appr.InitiateQueryExecutor(tx) var count int // Execute the query err = queryExecutor.QueryRowx(query, args...).Scan(&count) if err != nil { - logger.Error("failed to execute query: ", err.Error()) + logger.Error(ctx,"failed to execute query: ", err.Error()) return false, apperrors.InternalServer } + logger.Debug(ctx,"repoAppr: count: ",count) // Check if user is present return count > 0, nil } func (appr *appreciationsStore) UpdateAppreciationTotalRewardsOfYesterday(ctx context.Context, tx repository.Transaction) (bool, error) { - fmt.Println("UpdateAppreciationTotalRewardsOfYesterday") - + logger.Info(ctx,"appr: UpdateAppreciationTotalRewardsOfYesterday") // Initialize query executor queryExecutor := appr.InitiateQueryExecutor(tx) - // Load the location for Asia/Kolkata - location, err := time.LoadLocation("Asia/Kolkata") - if err != nil { - fmt.Printf("error loading location: %v\n", err) - return false, apperrors.InternalServerError - } - // Get today's date in Asia/Kolkata at 00:00:00 - now := time.Now().In(location) - todayMidnight := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, location) - - // Get yesterday's date in Asia/Kolkata at 00:00:00 - yesterdayMidnight := todayMidnight.AddDate(0, 0, -1) - - // Convert to Unix milliseconds - todayMidnightUnixMilli := todayMidnight.UnixMilli() - yesterdayMidnightUnixMilli := yesterdayMidnight.UnixMilli() - // Build the SQL update query with subquery query := ` UPDATE appreciations AS app @@ -384,27 +367,36 @@ FROM ( JOIN users u ON r.sender = u.id JOIN grades g ON u.grade_id = g.id WHERE a.is_valid = true - AND r.created_at >= $1 - AND r.created_at < $2 + AND r.created_at >= EXTRACT(EPOCH FROM TIMESTAMP 'yesterday'::TIMESTAMP) * 1000 + AND r.created_at < EXTRACT(EPOCH FROM TIMESTAMP 'today'::TIMESTAMP) * 1000 GROUP BY appreciation_id ) AS agg WHERE app.id = agg.appreciation_id; ` + logger.Debug(ctx," query: ",query) // Execute the query using the query executor - _, err = queryExecutor.Exec(query,yesterdayMidnightUnixMilli,todayMidnightUnixMilli) + res, err := queryExecutor.Exec(query) if err != nil { - logger.Error("Error executing SQL query:", err.Error()) + logger.Error(ctx,"Error executing SQL query:", err.Error()) return false, apperrors.InternalServer } + rowsAffected,err := res.RowsAffected() + if err != nil{ + logger.Error(ctx," err: ",err) + return false,nil + } + logger.Info(ctx,"repoAppr: rowsAffected: ",rowsAffected) return true, nil } func (appr *appreciationsStore) UpdateUserBadgesBasedOnTotalRewards(ctx context.Context, tx repository.Transaction) ([]repository.UserBadgeDetails, error) { + logger.Info(ctx," appr: UpdateUserBadgesBasedOnTotalRewards") queryExecutor := appr.InitiateQueryExecutor(tx) afterTime := GetQuarterStartUnixTime() + logger.Info(ctx," aftertime: ",afterTime) query := ` -- Calculate total reward points for each receiver WITH receiver_points AS ( @@ -486,8 +478,10 @@ JOIN badges b ON ib.badge_id = b.id; ` + logger.Debug(ctx,fmt.Sprintf("repoAppr: query: %s, args: %v %v",query,afterTime,afterTime)) rows, err := queryExecutor.Query(query, afterTime, afterTime) if err != nil { + logger.Error(ctx,"repoAppr: error in extecution query") return []repository.UserBadgeDetails{}, err } defer rows.Close() @@ -501,6 +495,7 @@ JOIN userBadgeDetails = append(userBadgeDetails, detail) } + logger.Debug(ctx," userBadgeDetails: ",userBadgeDetails) if err = rows.Err(); err != nil { return []repository.UserBadgeDetails{}, err } diff --git a/internal/repository/postgresdb/coreValues.go b/internal/repository/postgresdb/coreValues.go index 444e7e3..4371105 100644 --- a/internal/repository/postgresdb/coreValues.go +++ b/internal/repository/postgresdb/coreValues.go @@ -9,8 +9,8 @@ import ( "github.com/joshsoftware/peerly-backend/internal/pkg/apperrors" "github.com/joshsoftware/peerly-backend/internal/pkg/constants" "github.com/joshsoftware/peerly-backend/internal/pkg/dto" + logger "github.com/joshsoftware/peerly-backend/internal/pkg/logger" "github.com/joshsoftware/peerly-backend/internal/repository" - logger "github.com/sirupsen/logrus" ) var CoreValueColumns = []string{"id", "name", "description", "parent_core_value_id"} @@ -56,7 +56,7 @@ func (cs *coreValueStore) GetCoreValue(ctx context.Context, coreValueID int64) ( getCoreValueQuery, args, err := queryBuilder.ToSql() if err != nil { - logger.Errorf("error in generating squirrel query, err: %s", err.Error()) + logger.Errorf(ctx, "error in generating squirrel query, err: %s", err.Error()) err = apperrors.InternalServerError return } @@ -68,7 +68,7 @@ func (cs *coreValueStore) GetCoreValue(ctx context.Context, coreValueID int64) ( args..., ) if err != nil { - logger.Errorf("error while getting core value, corevalue_id: %d, err: %s", coreValueID, err.Error()) + logger.Errorf(ctx, "error while getting core value, corevalue_id: %d, err: %s", coreValueID, err.Error()) err = apperrors.InvalidCoreValueData return } diff --git a/internal/repository/postgresdb/organizationConfig.go b/internal/repository/postgresdb/organizationConfig.go index 839acc0..771335c 100644 --- a/internal/repository/postgresdb/organizationConfig.go +++ b/internal/repository/postgresdb/organizationConfig.go @@ -4,15 +4,16 @@ import ( "context" "database/sql" "errors" + "fmt" "time" sq "github.com/Masterminds/squirrel" "github.com/jmoiron/sqlx" "github.com/joshsoftware/peerly-backend/internal/pkg/apperrors" + "github.com/joshsoftware/peerly-backend/internal/pkg/constants" "github.com/joshsoftware/peerly-backend/internal/pkg/dto" + logger "github.com/joshsoftware/peerly-backend/internal/pkg/logger" "github.com/joshsoftware/peerly-backend/internal/repository" - "github.com/joshsoftware/peerly-backend/internal/pkg/constants" - logger "github.com/sirupsen/logrus" ) type OrganizationConfigStore struct { @@ -29,6 +30,7 @@ func NewOrganizationConfigRepo(db *sqlx.DB) repository.OrganizationConfigStorer func (org *OrganizationConfigStore) CreateOrganizationConfig(ctx context.Context,tx repository.Transaction, orgConfigInfo dto.OrganizationConfig) (createdOrganization repository.OrganizationConfig, err error) { + logger.Infof(ctx,"orgRepo: CreateOrganizationConfig: %v",orgConfigInfo) queryExecutor := org.InitiateQueryExecutor(tx) insertQuery, args, err := repository.Sq. @@ -42,21 +44,26 @@ func (org *OrganizationConfigStore) CreateOrganizationConfig(ctx context.Context Suffix("RETURNING id, reward_multiplier ,reward_quota_renewal_frequency, timezone, created_by, updated_by, created_at, updated_at"). ToSql() if err != nil { - logger.Errorf("err in creating query: %v",err) + logger.Errorf(ctx,"err in creating query: %v",err) return repository.OrganizationConfig{}, apperrors.InternalServer } + + logger.Debug(ctx,fmt.Sprintf("orgRepo: query: %s,args: %v",insertQuery,args)) err = queryExecutor.QueryRowx(insertQuery, args...).StructScan(&createdOrganization) if err != nil { if err == sql.ErrNoRows { - logger.Errorf("err in creating orgconfig : %v ", err) + logger.Errorf(ctx,"err in creating orgconfig : %v ", err) return repository.OrganizationConfig{}, apperrors.InternalServer } } + + logger.Debug(ctx,fmt.Sprintf("orgRepo: query: %s,args: %v",insertQuery,args)) return } func (org *OrganizationConfigStore) UpdateOrganizationConfig(ctx context.Context, tx repository.Transaction, reqOrganization dto.OrganizationConfig) (updatedOrganization repository.OrganizationConfig, err error) { + logger.Infof(ctx,"orgRepo: UpdateOrganizationConfig: %v",reqOrganization) queryExecutor := org.InitiateQueryExecutor(tx) updateBuilder := repository.Sq.Update(org.OrganizationConfigTable). @@ -79,14 +86,15 @@ func (org *OrganizationConfigStore) UpdateOrganizationConfig(ctx context.Context query, args, err := updateBuilder.ToSql() if err != nil { - logger.Errorf("Error building update query: %v",err) + logger.Errorf(ctx,"Error building update query: %v",err) return repository.OrganizationConfig{}, err } + logger.Debug(ctx,fmt.Sprintf("orgRepo: query: %s,args: %v",query,args)) err = queryExecutor.QueryRowx(query, args...).StructScan(&updatedOrganization) if err != nil { if err == sql.ErrNoRows { - logger.Errorf("err in updating orgconfig : %v ", err) + logger.Errorf(ctx,"orgRepo: err in updating orgconfig : %v ", err) return repository.OrganizationConfig{}, apperrors.InternalServer } } @@ -95,6 +103,7 @@ func (org *OrganizationConfigStore) UpdateOrganizationConfig(ctx context.Context // GetOrganization - returns an organization from the database if it exists based on its ID primary key func (org *OrganizationConfigStore) GetOrganizationConfig(ctx context.Context, tx repository.Transaction) (updatedOrgConfig repository.OrganizationConfig, err error) { + logger.Debug(ctx,"orgRepo: GetOrganizationConfig") queryExecutor := org.InitiateQueryExecutor(tx) queryBuilder := repository.Sq. @@ -104,20 +113,23 @@ func (org *OrganizationConfigStore) GetOrganizationConfig(ctx context.Context, t query, args, err := queryBuilder.ToSql() if err != nil { - logger.Errorf("Error building select query: %v",err) + logger.Errorf(ctx,"Error building select query: %v",err) return repository.OrganizationConfig{}, err } + logger.Debug(ctx,fmt.Sprintf("orgRepo: query: %s,args: %v",query,args)) + err = queryExecutor.QueryRowx( query, args...).StructScan(&updatedOrgConfig) if err != nil { if errors.Is(err, sql.ErrNoRows) { - logger.Errorf("Organization not found: %v",err) + logger.Errorf(ctx,"Organization not found: %v",err) return repository.OrganizationConfig{}, apperrors.OrganizationConfigNotFound } - logger.Errorf("Error fetching organization: %v",err) + logger.Errorf(ctx,"Error fetching organization: %v",err) return repository.OrganizationConfig{}, err } + logger.Debug(ctx," updateOrgConfig: ",updatedOrgConfig) return updatedOrgConfig, nil } diff --git a/internal/repository/postgresdb/reportAppreciation.go b/internal/repository/postgresdb/reportAppreciation.go index 2bb7811..a72a5b1 100644 --- a/internal/repository/postgresdb/reportAppreciation.go +++ b/internal/repository/postgresdb/reportAppreciation.go @@ -8,8 +8,8 @@ import ( "github.com/jmoiron/sqlx" "github.com/joshsoftware/peerly-backend/internal/pkg/apperrors" "github.com/joshsoftware/peerly-backend/internal/pkg/dto" + logger "github.com/joshsoftware/peerly-backend/internal/pkg/logger" "github.com/joshsoftware/peerly-backend/internal/repository" - logger "github.com/sirupsen/logrus" ) type reportAppreciationStore struct { @@ -39,7 +39,7 @@ func (rs *reportAppreciationStore) CheckAppreciation(ctx context.Context, reqDat reqData.AppreciationId, ) if err != nil { - logger.WithField("err", err.Error()).Error("Error in retriving appreciation count") + logger.Errorf(ctx, "error in retriving appreciation, err: %v") return } if count == 0 { @@ -60,7 +60,7 @@ func (rs *reportAppreciationStore) CheckDuplicateReport(ctx context.Context, req reqData.ReportedBy, ) if err != nil { - logger.WithField("err", err.Error()).Error("Error in looking for duplicate report") + logger.Errorf(ctx, "error in looking for duplicate report, err: %v", err) return } if count > 0 { @@ -79,7 +79,7 @@ func (rs *reportAppreciationStore) GetSenderAndReceiver(ctx context.Context, req reqData.AppreciationId, ) if err != nil { - logger.WithField("err", err.Error()).Error("Error in fetching appreciation sender and receiver") + logger.Errorf(ctx, "error in fetching appreciation sender and receiver, err: %v", err) return } return @@ -96,7 +96,7 @@ func (rs *reportAppreciationStore) ReportAppreciation(ctx context.Context, repor reportReq.ReportedBy, ) if err != nil { - logger.WithField("err", err.Error()).Error("Error in creating report") + logger.Error(ctx, "error in creating report, err:%v", err) return } return @@ -190,11 +190,11 @@ func (rs *reportAppreciationStore) GetResolution(ctx context.Context, id int64) ) if err != nil { if err == sql.ErrNoRows { - logger.Errorf("no such resolution exists") + logger.Errorf(ctx, "no such resolution exists") err = apperrors.InvalidId return } - logger.Errorf("error in retriving reported appriciation, err:%w", err) + logger.Errorf(ctx, "error in retriving reported appriciation, err:%w", err) err = apperrors.InternalServerError return } diff --git a/internal/repository/postgresdb/rewards.go b/internal/repository/postgresdb/rewards.go index fdde384..a14a170 100644 --- a/internal/repository/postgresdb/rewards.go +++ b/internal/repository/postgresdb/rewards.go @@ -9,8 +9,8 @@ import ( "github.com/joshsoftware/peerly-backend/internal/pkg/apperrors" "github.com/joshsoftware/peerly-backend/internal/pkg/constants" "github.com/joshsoftware/peerly-backend/internal/pkg/dto" + logger "github.com/joshsoftware/peerly-backend/internal/pkg/logger" "github.com/joshsoftware/peerly-backend/internal/repository" - logger "github.com/sirupsen/logrus" ) type rewardStore struct { @@ -25,6 +25,7 @@ func NewRewardRepo(db *sqlx.DB) repository.RewardStorer { func (rwrd *rewardStore) GiveReward(ctx context.Context, tx repository.Transaction, reward dto.Reward) (repository.Reward, error) { + logger.Debug(ctx,fmt.Sprintf("rwrdRepo: GiveReward: %v",reward)) queryExecutor := rwrd.InitiateQueryExecutor(tx) insertQuery, args, err := repository.Sq. Insert("rewards"). @@ -34,26 +35,26 @@ func (rwrd *rewardStore) GiveReward(ctx context.Context, tx repository.Transacti ToSql() if err != nil { - logger.Error("err: ", "error in creating query", err.Error()) + logger.Error(ctx,"err: ", "error in creating query", err.Error()) return repository.Reward{}, apperrors.InternalServer } + logger.Debug(ctx,fmt.Sprintf("rwrdRepo: insertQuery: %s,args: %v",insertQuery,args)) var rewardInfo repository.Reward err = queryExecutor.QueryRowx(insertQuery, args...).Scan(&rewardInfo.Id, &rewardInfo.AppreciationId, &rewardInfo.Point, &rewardInfo.SenderId, &rewardInfo.CreatedAt) if err != nil { - logger.Error("Error executing create reward insert query: ", err) + logger.Error(ctx,"Error executing create reward insert query: ", err) return repository.Reward{}, apperrors.InternalServer } + logger.Debug(ctx," rewardInfo: ",rewardInfo) return rewardInfo, nil } func (rwrd *rewardStore) IsUserRewardForAppreciationPresent(ctx context.Context, tx repository.Transaction, apprId int64, senderId int64) (bool, error) { // Initialize the Squirrel query builder - - fmt.Println("appr id: ", apprId) - fmt.Println("sender: ", senderId) + logger.Infof(ctx,"rwrdRepo: appr id: %d,sender: %d", apprId,senderId) // Build the SQL query query, args, err := repository.Sq.Select("COUNT(*)"). From("rewards"). @@ -63,11 +64,11 @@ func (rwrd *rewardStore) IsUserRewardForAppreciationPresent(ctx context.Context, }). ToSql() if err != nil { - logger.Error("err ", err.Error()) + logger.Error(ctx,"rwrdRepo: err ", err.Error()) return false, apperrors.InternalServer } - fmt.Println("query: ", query) + logger.Debug(ctx,fmt.Sprintf("rwrdRepo: query: %s,args: %v", query,args)) queryExecutor := rwrd.InitiateQueryExecutor(tx) @@ -75,10 +76,10 @@ func (rwrd *rewardStore) IsUserRewardForAppreciationPresent(ctx context.Context, // Execute the query err = queryExecutor.QueryRowx(query, args...).Scan(&count) if err != nil { - logger.Error("failed to execute query: ", err.Error()) + logger.Error(ctx,"failed to execute query: ", err.Error()) return false, apperrors.InternalServer } - fmt.Println("count: ", count) + logger.Info(ctx,"rwrdRepo: userCount: ", count) // Check if user and appreciation id is present return count > 0, nil } @@ -93,21 +94,22 @@ func (rwrd *rewardStore) DeduceRewardQuotaOfUser(ctx context.Context, tx reposit ToSql() if err != nil { - logger.Error("err: building SQL Query ", err.Error()) + logger.Error(ctx,"err: building SQL Query ", err.Error()) return false, err } + logger.Debug(ctx,fmt.Sprintf("rwrdRepo: query: %s,args: %v", updateQuery,args)) // Execute the query within the transaction context result, err := queryExecutor.Exec(updateQuery, args...) if err != nil { - logger.Error("err: error executing SQL query:", err.Error()) + logger.Error(ctx,"err: error executing SQL query:", err.Error()) return false, err } // Check how many rows were affected rowsAffected, err := result.RowsAffected() if err != nil { - logger.Error("err: error getting rows affected:", err) + logger.Error(ctx,"err: error getting rows affected:", err) return false, err } @@ -119,6 +121,7 @@ func (rwrd *rewardStore) UserHasRewardQuota(ctx context.Context, tx repository.T // Initialize the Squirrel query builder // psql := sq.StatementBuilder.PlaceholderFormat(sq.Dollar) + logger.Info(ctx," rwrd: UserHasRewardQuota",userID," ",points) // Build the SQL query query := ` SELECT COUNT(*) @@ -131,8 +134,7 @@ func (rwrd *rewardStore) UserHasRewardQuota(ctx context.Context, tx repository.T // Arguments for the query args := []interface{}{userID, points} - fmt.Println("id: ", userID, "points: ", points) - fmt.Println("query: ", query) + logger.Infof(ctx,"rwrdRepo: query: %s,id: %d,points: %d", query,userID, points) queryExecutor := rwrd.InitiateQueryExecutor(tx) @@ -140,10 +142,10 @@ func (rwrd *rewardStore) UserHasRewardQuota(ctx context.Context, tx repository.T // Execute the query err := queryExecutor.QueryRowx(query, args...).Scan(&count) if err != nil { - logger.Error("failed to execute query: ", err.Error()) + logger.Error(ctx,"failed to execute query: ", err.Error()) return false, apperrors.InternalServer } - fmt.Println("count: ", count) + logger.Info(ctx,"rwrdRepo: count: ", count) // Check if user is present return count > 0, nil } diff --git a/internal/repository/postgresdb/user.go b/internal/repository/postgresdb/user.go index 1153f48..4177d19 100644 --- a/internal/repository/postgresdb/user.go +++ b/internal/repository/postgresdb/user.go @@ -10,8 +10,8 @@ import ( "github.com/joshsoftware/peerly-backend/internal/pkg/apperrors" "github.com/joshsoftware/peerly-backend/internal/pkg/constants" "github.com/joshsoftware/peerly-backend/internal/pkg/dto" + logger "github.com/joshsoftware/peerly-backend/internal/pkg/logger" "github.com/joshsoftware/peerly-backend/internal/repository" - logger "github.com/sirupsen/logrus" ) var ( @@ -50,7 +50,7 @@ func (us *userStore) GetUserByEmail(ctx context.Context, email string) (user rep queryBuilder := repository.Sq.Select(userColumns...).From(us.UsersTable).Where(squirrel.Like{"email": email}) getUserByEmailQuery, args, err := queryBuilder.ToSql() if err != nil { - logger.Errorf("error in generating query, err: %s", err.Error()) + logger.Errorf(ctx, "error in generating query, err: %s", err.Error()) err = apperrors.InternalServerError return } @@ -67,7 +67,7 @@ func (us *userStore) GetUserByEmail(ctx context.Context, email string) (user rep return } else { // Possible that there's no rows in the result set - logger.Errorf("error selecting user from database by email, err: %s", err.Error()) + logger.Errorf(ctx, "error selecting user from database by email, err: %s", err.Error()) err = apperrors.InternalServerError return } @@ -126,7 +126,7 @@ func (us *userStore) GetGradeByName(ctx context.Context, name string) (grade rep queryBuilder := repository.Sq.Select(gradeColumns...).From(us.GradesTable).Where(squirrel.Like{"name": name}) getGradeId, args, err := queryBuilder.ToSql() if err != nil { - logger.Errorf("error in generating query, err: %s", err) + logger.Errorf(ctx, "error in generating query, err: %s", err) err = apperrors.InternalServerError return } @@ -137,7 +137,7 @@ func (us *userStore) GetGradeByName(ctx context.Context, name string) (grade rep err = apperrors.GradeNotFound return } - logger.Errorf("error in retriving grade id, grade: %s, err: %s", name, err.Error()) + logger.Errorf(ctx, "error in retriving grade id, grade: %s, err: %s", name, err.Error()) err = apperrors.InternalServerError return } @@ -251,7 +251,7 @@ func (us *userStore) ListUsers(ctx context.Context, reqData dto.ListUsersReq) (r err = us.DB.Select(&resp, listUsersQuery, args...) if err != nil { if err == sql.ErrNoRows { - logger.Errorf("no fields returned, err:%s", err.Error()) + logger.Errorf(ctx, "no fields returned, err:%s", err.Error()) err = nil return } @@ -325,11 +325,11 @@ LEFT JOIN WHERE ub.id = (SELECT MAX(id) FROM user_badges WHERE user_id = ub.user_id)) AS b ON u.id = b.user_id LIMIT 10; ` - logger.Info("afterTime: ", afterTime) + logger.Info(ctx, "afterTime: ", afterTime) rows, err := queryExecutor.Query(query, afterTime, afterTime, afterTime) if err != nil { - logger.Error("err: userStore ", err.Error()) + logger.Error(ctx, "err: userStore ", err.Error()) return []repository.ActiveUser{}, err } defer rows.Close() @@ -344,14 +344,14 @@ LIMIT 10; &user.BadgeName, &user.AppreciationPoints, ); err != nil { - logger.Error("err: userStore ", err.Error()) + logger.Error(ctx, "err: userStore ", err.Error()) return nil, err } activeUsers = append(activeUsers, user) } if err = rows.Err(); err != nil { - logger.Error("err: userStore ", err.Error()) + logger.Error(ctx, "err: userStore ", err.Error()) return []repository.ActiveUser{}, err } @@ -370,7 +370,7 @@ func (us *userStore) UpdateRewardQuota(ctx context.Context, tx repository.Transa _, err = queryExecutor.Exec(query) if err != nil { - logger.Error("err: userStore ", err.Error()) + logger.Error(ctx, "err: userStore ", err.Error()) return err } return @@ -402,11 +402,11 @@ func (us *userStore) GetUserById(ctx context.Context, reqData dto.GetUserByIdReq err = us.DB.Select(&userList, getUserById, reqData.QuaterTimeStamp, reqData.UserId) if err != nil { if err == sql.ErrNoRows { - logger.WithField("err", err.Error()).Error("No fields returned") + logger.Errorf(ctx, "no fields returned, err:%v", err) err = apperrors.InvalidId return } - logger.WithField("err", err.Error()).Error("Error in fetching users from database") + logger.Errorf(ctx, "error in fetching users from database, err: %v", err) err = apperrors.InternalServerError return } @@ -480,11 +480,11 @@ func (us *userStore) GetAdmin(ctx context.Context, email string) (user repositor ) if err != nil { if err == sql.ErrNoRows { - logger.Errorf("invalid user email, err:%s", err.Error()) + logger.Errorf(ctx, "invalid user email, err:%s", err.Error()) err = apperrors.InvalidEmail return } - logger.Errorf("error in get admin query, err: %s", err.Error()) + logger.Errorf(ctx, "error in get admin query, err: %s", err.Error()) err = apperrors.InternalServerError return } @@ -502,7 +502,7 @@ func (us *userStore) AddDeviceToken(ctx context.Context, userID int64, notificat Suffix("RETURNING id,user_id,notification_token"). ToSql() if err != nil { - logger.Errorf("error in generating squirrel query, err: %v", err) + logger.Errorf(ctx, "error in generating squirrel query, err: %v", err) return apperrors.InternalServerError } @@ -517,10 +517,10 @@ func (us *userStore) AddDeviceToken(ctx context.Context, userID int64, notificat err = us.DB.QueryRowx(insertQuery, args...).StructScan(&device) if err != nil { if err == sql.ErrNoRows { - logger.Error("device not found") + logger.Error(ctx, "device not found") return apperrors.InternalServerError } - logger.Errorf("failed to execute query: %v", err) + logger.Errorf(ctx, "failed to execute query: %v", err) return apperrors.InternalServerError } return nil diff --git a/logs/2024-08-26_12-52-33_peerly_backend.log b/logs/2024-08-26_12-52-33_peerly_backend.log new file mode 100644 index 0000000..45441b7 --- /dev/null +++ b/logs/2024-08-26_12-52-33_peerly_backend.log @@ -0,0 +1 @@ +time="2024-08-26T12:52:33+05:30" level=info msg="req_id: [Starting Peerly Application...]"