From 4d2fb76100cfb29899eb442f3eee580d701c3b03 Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Wed, 22 Mar 2023 15:15:18 +0530 Subject: [PATCH 01/19] feat:Cluster description note added --- api/cluster/ClusterRestHandler.go | 108 ++++++++-- api/cluster/ClusterRouter.go | 9 + api/cluster/wire_cluster.go | 18 +- pkg/cluster/ClusterNoteService.go | 196 ++++++++++++++++++ .../ClusterNoteHistoryRepository.go | 62 ++++++ .../repository/ClusterNoteRepository.go | 83 ++++++++ .../sql/124_alter_cluster_details.down.sql | 2 + scripts/sql/124_alter_cluster_details.up.sql | 39 ++++ wire_gen.go | 5 +- 9 files changed, 504 insertions(+), 18 deletions(-) create mode 100644 pkg/cluster/ClusterNoteService.go create mode 100644 pkg/cluster/repository/ClusterNoteHistoryRepository.go create mode 100644 pkg/cluster/repository/ClusterNoteRepository.go create mode 100644 scripts/sql/124_alter_cluster_details.down.sql create mode 100644 scripts/sql/124_alter_cluster_details.up.sql diff --git a/api/cluster/ClusterRestHandler.go b/api/cluster/ClusterRestHandler.go index 8cb8187a15..09bb8404ff 100644 --- a/api/cluster/ClusterRestHandler.go +++ b/api/cluster/ClusterRestHandler.go @@ -44,10 +44,10 @@ const CLUSTER_DELETE_SUCCESS_RESP = "Cluster deleted successfully." type ClusterRestHandler interface { Save(w http.ResponseWriter, r *http.Request) FindAll(w http.ResponseWriter, r *http.Request) - FindById(w http.ResponseWriter, r *http.Request) + FindByClusterId(w http.ResponseWriter, r *http.Request) Update(w http.ResponseWriter, r *http.Request) - + UpdateClusterNote(w http.ResponseWriter, r *http.Request) FindAllForAutoComplete(w http.ResponseWriter, r *http.Request) DeleteCluster(w http.ResponseWriter, r *http.Request) GetClusterNamespaces(w http.ResponseWriter, r *http.Request) @@ -56,16 +56,18 @@ type ClusterRestHandler interface { } type ClusterRestHandlerImpl struct { - clusterService cluster.ClusterService - logger *zap.SugaredLogger - userService user.UserService - validator *validator.Validate - enforcer casbin.Enforcer - deleteService delete2.DeleteService - argoUserService argo.ArgoUserService + clusterService cluster.ClusterService + clusterNoteService cluster.ClusterNoteService + logger *zap.SugaredLogger + userService user.UserService + validator *validator.Validate + enforcer casbin.Enforcer + deleteService delete2.DeleteService + argoUserService argo.ArgoUserService } func NewClusterRestHandlerImpl(clusterService cluster.ClusterService, + clusterNoteService cluster.ClusterNoteService, logger *zap.SugaredLogger, userService user.UserService, validator *validator.Validate, @@ -73,13 +75,14 @@ func NewClusterRestHandlerImpl(clusterService cluster.ClusterService, deleteService delete2.DeleteService, argoUserService argo.ArgoUserService) *ClusterRestHandlerImpl { return &ClusterRestHandlerImpl{ - clusterService: clusterService, - logger: logger, - userService: userService, - validator: validator, - enforcer: enforcer, - deleteService: deleteService, - argoUserService: argoUserService, + clusterService: clusterService, + clusterNoteService: clusterNoteService, + logger: logger, + userService: userService, + validator: validator, + enforcer: enforcer, + deleteService: deleteService, + argoUserService: argoUserService, } } @@ -200,6 +203,24 @@ func (impl ClusterRestHandlerImpl) FindById(w http.ResponseWriter, r *http.Reque common.WriteJsonResp(w, err, bean, http.StatusOK) } +func (impl ClusterRestHandlerImpl) FindByClusterId(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + id := vars["id"] + i, err := strconv.Atoi(id) + if err != nil { + impl.logger.Errorw("request err, FindById", "error", err, "clusterId", id) + common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + return + } + bean, err := impl.clusterNoteService.FindByClusterId(i) + if err != nil { + impl.logger.Errorw("service err, FindById", "err", err, "clusterId", id) + common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + return + } + common.WriteJsonResp(w, err, bean, http.StatusOK) +} + func (impl ClusterRestHandlerImpl) Update(w http.ResponseWriter, r *http.Request) { token := r.Header.Get("token") decoder := json.NewDecoder(r.Body) @@ -261,6 +282,61 @@ func (impl ClusterRestHandlerImpl) Update(w http.ResponseWriter, r *http.Request common.WriteJsonResp(w, err, bean, http.StatusOK) } +func (impl ClusterRestHandlerImpl) UpdateClusterNote(w http.ResponseWriter, r *http.Request) { + token := r.Header.Get("token") + decoder := json.NewDecoder(r.Body) + userId, err := impl.userService.GetLoggedInUser(r) + if userId == 0 || err != nil { + impl.logger.Errorw("service err, Update", "error", err, "userId", userId) + common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + return + } + var bean cluster.ClusterNoteBean + err = decoder.Decode(&bean) + if err != nil { + impl.logger.Errorw("request err, Update", "error", err, "payload", bean) + common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + return + } + impl.logger.Infow("request payload, Update", "payload", bean) + err = impl.validator.Struct(bean) + if err != nil { + impl.logger.Errorw("validate err, Update", "error", err, "payload", bean) + common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + return + } + + ctx, cancel := context.WithCancel(r.Context()) + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + if util2.IsBaseStack() { + ctx = context.WithValue(ctx, "token", token) + } else { + acdToken, err := impl.argoUserService.GetLatestDevtronArgoCdUserToken() + if err != nil { + impl.logger.Errorw("error in getting acd token", "err", err) + common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + return + } + ctx = context.WithValue(ctx, "token", acdToken) + } + _, err = impl.clusterNoteService.Update(ctx, &bean, userId) + if err != nil { + impl.logger.Errorw("service err, Update", "error", err, "payload", bean) + common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + return + } + + common.WriteJsonResp(w, err, bean, http.StatusOK) +} + func (impl ClusterRestHandlerImpl) FindAllForAutoComplete(w http.ResponseWriter, r *http.Request) { start := time.Now() clusterList, err := impl.clusterService.FindAllForAutoComplete() diff --git a/api/cluster/ClusterRouter.go b/api/cluster/ClusterRouter.go index 400a0c1792..b699c95e1d 100644 --- a/api/cluster/ClusterRouter.go +++ b/api/cluster/ClusterRouter.go @@ -45,11 +45,20 @@ func (impl ClusterRouterImpl) InitClusterRouter(clusterRouter *mux.Router) { Queries("id", "{id}"). HandlerFunc(impl.clusterRestHandler.FindById) + clusterRouter.Path("/description"). + Methods("GET"). + Queries("id", "{id}"). + HandlerFunc(impl.clusterRestHandler.FindByClusterId) + clusterRouter.Path(""). Methods("GET"). HandlerFunc(impl.clusterRestHandler.FindAll) clusterRouter.Path(""). + Methods("PUT"). + HandlerFunc(impl.clusterRestHandler.UpdateClusterNote) + + clusterRouter.Path("/description"). Methods("PUT"). HandlerFunc(impl.clusterRestHandler.Update) diff --git a/api/cluster/wire_cluster.go b/api/cluster/wire_cluster.go index 1ada47d0bc..7d315140bb 100644 --- a/api/cluster/wire_cluster.go +++ b/api/cluster/wire_cluster.go @@ -13,6 +13,14 @@ var ClusterWireSet = wire.NewSet( wire.Bind(new(repository.ClusterRepository), new(*repository.ClusterRepositoryImpl)), cluster.NewClusterServiceImplExtended, wire.Bind(new(cluster.ClusterService), new(*cluster.ClusterServiceImplExtended)), + + repository.NewClusterNoteHistoryRepositoryImpl, + wire.Bind(new(repository.ClusterNoteHistoryRepository), new(*repository.ClusterNoteHistoryRepositoryImpl)), + repository.NewClusterNoteRepositoryImpl, + wire.Bind(new(repository.ClusterNoteRepository), new(*repository.ClusterNoteRepositoryImpl)), + cluster.NewClusterNoteServiceImpl, + wire.Bind(new(cluster.ClusterNoteService), new(*cluster.ClusterNoteServiceImpl)), + NewClusterRestHandlerImpl, wire.Bind(new(ClusterRestHandler), new(*ClusterRestHandlerImpl)), NewClusterRouterImpl, @@ -28,12 +36,20 @@ var ClusterWireSet = wire.NewSet( wire.Bind(new(EnvironmentRouter), new(*EnvironmentRouterImpl)), ) -//minimal wire to be used with EA +// minimal wire to be used with EA var ClusterWireSetEa = wire.NewSet( repository.NewClusterRepositoryImpl, wire.Bind(new(repository.ClusterRepository), new(*repository.ClusterRepositoryImpl)), cluster.NewClusterServiceImpl, wire.Bind(new(cluster.ClusterService), new(*cluster.ClusterServiceImpl)), + + repository.NewClusterNoteRepositoryImpl, + wire.Bind(new(repository.ClusterNoteRepository), new(*repository.ClusterNoteRepositoryImpl)), + repository.NewClusterNoteHistoryRepositoryImpl, + wire.Bind(new(repository.ClusterNoteHistoryRepository), new(*repository.ClusterNoteHistoryRepositoryImpl)), + cluster.NewClusterNoteServiceImpl, + wire.Bind(new(cluster.ClusterNoteService), new(*cluster.ClusterNoteServiceImpl)), + NewClusterRestHandlerImpl, wire.Bind(new(ClusterRestHandler), new(*ClusterRestHandlerImpl)), NewClusterRouterImpl, diff --git a/pkg/cluster/ClusterNoteService.go b/pkg/cluster/ClusterNoteService.go new file mode 100644 index 0000000000..53688adeb4 --- /dev/null +++ b/pkg/cluster/ClusterNoteService.go @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2020 Devtron Labs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package cluster + +import ( + "context" + "fmt" + "time" + + "github.com/devtron-labs/devtron/internal/constants" + "github.com/devtron-labs/devtron/internal/util" + "github.com/devtron-labs/devtron/pkg/cluster/repository" + "github.com/go-pg/pg" + "go.uber.org/zap" +) + +type ClusterNoteBean struct { + Id int `json:"id,omitempty" validate:"number"` + ClusterId int `json:"cluster_id,omitempty" validate:"required"` + Description string `json:"description,omitempty"` + CreatedBy int `json:"created_by,omitempty"` + CreatedOn time.Time `json:"created_on,omitempty"` +} + +type ClusterNoteHistoryBean struct { + Id int `json:"id,omitempty" validate:"number"` + NoteId int `json:"note_id,omitempty" validate:"required"` + Description string `json:"description,omitempty"` + CreatedBy int `json:"created_by,omitempty"` + CreatedOn time.Time `json:"created_on,omitempty"` +} + +type ClusterNoteService interface { + Save(parent context.Context, bean *ClusterNoteBean, userId int32) (*ClusterNoteBean, error) + FindByClusterId(id int) (*ClusterNoteBean, error) + FindByClusterIds(id []int) ([]ClusterNoteBean, error) + Update(ctx context.Context, bean *ClusterNoteBean, userId int32) (*ClusterNoteBean, error) + Delete(bean *ClusterNoteBean, userId int32) error +} + +type ClusterNoteServiceImpl struct { + clusterNoteRepository repository.ClusterNoteRepository + clusterNoteHistoryRepository repository.ClusterNoteHistoryRepository + logger *zap.SugaredLogger +} + +func NewClusterNoteServiceImpl(repository repository.ClusterNoteRepository, repositoryHistory repository.ClusterNoteHistoryRepository, logger *zap.SugaredLogger) *ClusterNoteServiceImpl { + clusterNoteService := &ClusterNoteServiceImpl{ + clusterNoteRepository: repository, + clusterNoteHistoryRepository: repositoryHistory, + logger: logger, + } + return clusterNoteService +} + +func (impl *ClusterNoteServiceImpl) Save(parent context.Context, bean *ClusterNoteBean, userId int32) (*ClusterNoteBean, error) { + existingModel, err := impl.clusterNoteRepository.FindByClusterId(bean.ClusterId) + if err != nil && err != pg.ErrNoRows { + impl.logger.Error(err) + return nil, err + } + if existingModel.Id > 0 { + impl.logger.Errorw("error on fetching cluster, duplicate", "id", bean.ClusterId) + return nil, fmt.Errorf("cluster note already exists") + } + + model := &repository.ClusterNote{ + ClusterId: bean.ClusterId, + Description: bean.Description, + } + + model.CreatedBy = userId + model.UpdatedBy = userId + model.CreatedOn = time.Now() + model.UpdatedOn = time.Now() + + err = impl.clusterNoteRepository.Save(model) + if err != nil { + impl.logger.Errorw("error in saving cluster note in db", "err", err) + err = &util.ApiError{ + Code: constants.ClusterCreateDBFailed, + InternalMessage: "cluster note creation failed in db", + UserMessage: fmt.Sprintf("requested by %d", userId), + } + } + bean.Id = model.Id + // audit the existing description to cluster audit history + cluster_audit := &repository.ClusterNoteHistory{ + NoteId: bean.Id, + Description: bean.Description, + } + err = impl.clusterNoteHistoryRepository.SaveHistory(cluster_audit) + if err != nil { + return nil, err + } + return bean, err +} + +func (impl *ClusterNoteServiceImpl) FindByClusterId(id int) (*ClusterNoteBean, error) { + model, err := impl.clusterNoteRepository.FindByClusterId(id) + if err != nil { + return nil, err + } + bean := &ClusterNoteBean{ + Id: model.Id, + ClusterId: model.ClusterId, + Description: model.Description, + CreatedBy: int(model.CreatedBy), + CreatedOn: model.CreatedOn, + } + return bean, nil +} + +func (impl *ClusterNoteServiceImpl) FindByClusterIds(ids []int) ([]ClusterNoteBean, error) { + models, err := impl.clusterNoteRepository.FindByClusterIds(ids) + if err != nil { + return nil, err + } + var beans []ClusterNoteBean + + for _, model := range models { + beans = append(beans, ClusterNoteBean{ + Id: model.Id, + ClusterId: model.ClusterId, + Description: model.Description, + CreatedBy: int(model.CreatedBy), + CreatedOn: model.CreatedOn, + }) + } + return beans, nil +} + +func (impl *ClusterNoteServiceImpl) Update(ctx context.Context, bean *ClusterNoteBean, userId int32) (*ClusterNoteBean, error) { + model, err := impl.clusterNoteRepository.FindByClusterId(bean.ClusterId) + if err != nil { + impl.logger.Error(err) + return nil, err + } + if model.Id == 0 { + impl.logger.Errorw("error on fetching cluster note, not found", "id", bean.Id) + return nil, fmt.Errorf("cluster note not found") + } + if bean.Description == "" || bean.Description == model.Description { + // no change in description + impl.logger.Errorw("no change found in cluster note, duplicate", "id", bean.Id) + return nil, fmt.Errorf("duplicate cluster note") + } + // update the cluster description with new data + model.Description = bean.Description + model.UpdatedBy = userId + model.UpdatedOn = time.Now() + + err = impl.clusterNoteRepository.Update(model) + if err != nil { + err = &util.ApiError{ + Code: constants.ClusterUpdateDBFailed, + InternalMessage: "cluster note update failed in db", + UserMessage: fmt.Sprintf("requested by %d", userId), + } + return bean, err + } + bean.Id = model.Id + // audit the existing description to cluster audit history + cluster_audit := &repository.ClusterNoteHistory{ + NoteId: bean.Id, + Description: bean.Description, + } + err = impl.clusterNoteHistoryRepository.SaveHistory(cluster_audit) + if err != nil { + return nil, err + } + return bean, err +} + +func (impl *ClusterNoteServiceImpl) Delete(bean *ClusterNoteBean, userId int32) error { + model, err := impl.clusterNoteRepository.FindByClusterId(bean.ClusterId) + if err != nil { + return err + } + return impl.clusterNoteRepository.Delete(model) +} diff --git a/pkg/cluster/repository/ClusterNoteHistoryRepository.go b/pkg/cluster/repository/ClusterNoteHistoryRepository.go new file mode 100644 index 0000000000..bfff5c8015 --- /dev/null +++ b/pkg/cluster/repository/ClusterNoteHistoryRepository.go @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2020 Devtron Labs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package repository + +import ( + "github.com/devtron-labs/devtron/pkg/sql" + "github.com/go-pg/pg" + "go.uber.org/zap" +) + +type ClusterNoteHistory struct { + tableName struct{} `sql:"cluster_note_history" pg:",discard_unknown_columns"` + Id int `sql:"id,pk"` + NoteId int `sql:"note_id"` + Description string `sql:"description"` + sql.AuditLog +} + +type ClusterNoteHistoryRepository interface { + SaveHistory(model *ClusterNoteHistory) error + FindHistoryByNoteId(id []int) ([]ClusterNoteHistory, error) +} + +func NewClusterNoteHistoryRepositoryImpl(dbConnection *pg.DB, logger *zap.SugaredLogger) *ClusterNoteHistoryRepositoryImpl { + return &ClusterNoteHistoryRepositoryImpl{ + dbConnection: dbConnection, + logger: logger, + } +} + +type ClusterNoteHistoryRepositoryImpl struct { + dbConnection *pg.DB + logger *zap.SugaredLogger +} + +func (impl ClusterNoteHistoryRepositoryImpl) SaveHistory(model *ClusterNoteHistory) error { + return impl.dbConnection.Insert(model) +} + +func (impl ClusterNoteHistoryRepositoryImpl) FindHistoryByNoteId(id []int) ([]ClusterNoteHistory, error) { + var clusterNoteHistories []ClusterNoteHistory + err := impl.dbConnection. + Model(&clusterNoteHistories). + Where("note_id =?", id). + Select() + return clusterNoteHistories, err +} diff --git a/pkg/cluster/repository/ClusterNoteRepository.go b/pkg/cluster/repository/ClusterNoteRepository.go new file mode 100644 index 0000000000..4cb4393663 --- /dev/null +++ b/pkg/cluster/repository/ClusterNoteRepository.go @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2020 Devtron Labs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package repository + +import ( + "github.com/devtron-labs/devtron/pkg/sql" + "github.com/go-pg/pg" + "go.uber.org/zap" +) + +type ClusterNote struct { + tableName struct{} `sql:"cluster_note" pg:",discard_unknown_columns"` + Id int `sql:"id,pk"` + ClusterId int `sql:"cluster_id"` + Description string `sql:"description"` + sql.AuditLog +} + +type ClusterNoteRepository interface { + Save(model *ClusterNote) error + FindByClusterId(id int) (*ClusterNote, error) + FindByClusterIds(id []int) ([]ClusterNote, error) + Update(model *ClusterNote) error + Delete(model *ClusterNote) error +} + +func NewClusterNoteRepositoryImpl(dbConnection *pg.DB, logger *zap.SugaredLogger) *ClusterNoteRepositoryImpl { + return &ClusterNoteRepositoryImpl{ + dbConnection: dbConnection, + logger: logger, + } +} + +type ClusterNoteRepositoryImpl struct { + dbConnection *pg.DB + logger *zap.SugaredLogger +} + +func (impl ClusterNoteRepositoryImpl) Save(model *ClusterNote) error { + return impl.dbConnection.Insert(model) +} + +func (impl ClusterNoteRepositoryImpl) FindByClusterId(id int) (*ClusterNote, error) { + clusterNote := &ClusterNote{} + err := impl.dbConnection. + Model(clusterNote). + Where("cluster_id =?", id). + Limit(1). + Select() + return clusterNote, err +} + +func (impl ClusterNoteRepositoryImpl) FindByClusterIds(id []int) ([]ClusterNote, error) { + var clusterNotes []ClusterNote + err := impl.dbConnection. + Model(&clusterNotes). + Where("cluster_id in(?)", pg.In(id)). + Select() + return clusterNotes, err +} + +func (impl ClusterNoteRepositoryImpl) Update(model *ClusterNote) error { + return impl.dbConnection.Update(model) +} + +func (impl ClusterNoteRepositoryImpl) Delete(model *ClusterNote) error { + return impl.dbConnection.Delete(model) +} \ No newline at end of file diff --git a/scripts/sql/124_alter_cluster_details.down.sql b/scripts/sql/124_alter_cluster_details.down.sql new file mode 100644 index 0000000000..61e07525d6 --- /dev/null +++ b/scripts/sql/124_alter_cluster_details.down.sql @@ -0,0 +1,2 @@ +DROP TABLE IF EXISTS "cluster_note_history"; +DROP TABLE IF EXISTS "cluster_note"; \ No newline at end of file diff --git a/scripts/sql/124_alter_cluster_details.up.sql b/scripts/sql/124_alter_cluster_details.up.sql new file mode 100644 index 0000000000..78b01f0fb0 --- /dev/null +++ b/scripts/sql/124_alter_cluster_details.up.sql @@ -0,0 +1,39 @@ +-- Sequence and defined type for cluster_note +CREATE SEQUENCE IF NOT EXISTS id_seq_cluster_note; + +-- Sequence and defined type for cluster_note_history +CREATE SEQUENCE IF NOT EXISTS id_seq_cluster_note_history; + +-- cluster_note Table Definition +CREATE TABLE IF NOT EXISTS public.cluster_note +( + "id" int4 NOT NULL DEFAULT nextval('id_seq_cluster_note'::regclass), + "cluster_id" int4 NOT NULL, + "description" TEXT NOT NULL, + "created_on" timestamptz NOT NULL, + "created_by" int4 NOT NULL, + "updated_on" timestamptz, + "updated_by" int4, + PRIMARY KEY ("id") +); + +-- add foreign key +ALTER TABLE "public"."cluster_note" + ADD FOREIGN KEY ("cluster_id") REFERENCES "public"."cluster" ("id"); + +-- cluster_note_history Table Definition +CREATE TABLE IF NOT EXISTS public.cluster_note_history +( + "id" int4 NOT NULL DEFAULT nextval('id_seq_cluster_note_history'::regclass), + "note_id" int4 NOT NULL, + "description" TEXT NOT NULL, + "created_on" timestamptz NOT NULL, + "created_by" int4 NOT NULL, + "updated_on" timestamptz, + "updated_by" int4, + PRIMARY KEY ("id") +); + +-- add foreign key +ALTER TABLE "public"."cluster_note_history" + ADD FOREIGN KEY ("note_id") REFERENCES "public"."cluster_note" ("id"); \ No newline at end of file diff --git a/wire_gen.go b/wire_gen.go index dacbc78539..b358d62405 100644 --- a/wire_gen.go +++ b/wire_gen.go @@ -460,7 +460,10 @@ func InitializeApp() (*App, error) { deleteServiceExtendedImpl := delete2.NewDeleteServiceExtendedImpl(sugaredLogger, teamServiceImpl, clusterServiceImplExtended, environmentServiceImpl, appRepositoryImpl, environmentRepositoryImpl, pipelineRepositoryImpl, chartRepositoryServiceImpl, installedAppRepositoryImpl) environmentRestHandlerImpl := cluster3.NewEnvironmentRestHandlerImpl(environmentServiceImpl, sugaredLogger, userServiceImpl, validate, enforcerImpl, deleteServiceExtendedImpl) environmentRouterImpl := cluster3.NewEnvironmentRouterImpl(environmentRestHandlerImpl) - clusterRestHandlerImpl := cluster3.NewClusterRestHandlerImpl(clusterServiceImplExtended, sugaredLogger, userServiceImpl, validate, enforcerImpl, deleteServiceExtendedImpl, argoUserServiceImpl) + clusterNoteRepositoryImpl := repository2.NewClusterNoteRepositoryImpl(db, sugaredLogger) + clusterNoteHistoryRepositoryImpl := repository2.NewClusterNoteHistoryRepositoryImpl(db, sugaredLogger) + clusterNoteServiceImpl := cluster2.NewClusterNoteServiceImpl(clusterNoteRepositoryImpl, clusterNoteHistoryRepositoryImpl, sugaredLogger) + clusterRestHandlerImpl := cluster3.NewClusterRestHandlerImpl(clusterServiceImplExtended, clusterNoteServiceImpl, sugaredLogger, userServiceImpl, validate, enforcerImpl, deleteServiceExtendedImpl, argoUserServiceImpl) clusterRouterImpl := cluster3.NewClusterRouterImpl(clusterRestHandlerImpl) gitWebhookRepositoryImpl := repository.NewGitWebhookRepositoryImpl(db) gitWebhookServiceImpl := git.NewGitWebhookServiceImpl(sugaredLogger, ciHandlerImpl, gitWebhookRepositoryImpl) From 716fb9b1dcbecc643044d435105b01dbab59bb19 Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Wed, 22 Mar 2023 17:30:01 +0530 Subject: [PATCH 02/19] fixed bugs and modifed --- api/cluster/ClusterRestHandler.go | 15 ++++++++-- api/cluster/ClusterRouter.go | 4 +-- pkg/cluster/ClusterNoteService.go | 28 ++++++++++++------- .../sql/124_alter_cluster_details.down.sql | 7 ++++- 4 files changed, 38 insertions(+), 16 deletions(-) diff --git a/api/cluster/ClusterRestHandler.go b/api/cluster/ClusterRestHandler.go index 09bb8404ff..7930386c9c 100644 --- a/api/cluster/ClusterRestHandler.go +++ b/api/cluster/ClusterRestHandler.go @@ -27,13 +27,13 @@ import ( "time" "github.com/devtron-labs/devtron/api/restHandler/common" + "github.com/devtron-labs/devtron/pkg/cluster" delete2 "github.com/devtron-labs/devtron/pkg/delete" + "github.com/devtron-labs/devtron/pkg/user" "github.com/devtron-labs/devtron/pkg/user/casbin" util2 "github.com/devtron-labs/devtron/util" "github.com/devtron-labs/devtron/util/argo" - - "github.com/devtron-labs/devtron/pkg/cluster" - "github.com/devtron-labs/devtron/pkg/user" + "github.com/go-pg/pg" "github.com/gorilla/mux" "go.uber.org/zap" "gopkg.in/go-playground/validator.v9" @@ -327,7 +327,16 @@ func (impl ClusterRestHandlerImpl) UpdateClusterNote(w http.ResponseWriter, r *h } ctx = context.WithValue(ctx, "token", acdToken) } + _, err = impl.clusterService.FindByIdWithoutConfig(bean.ClusterId) + if err != nil { + impl.logger.Errorw("service err, FindById", "err", err, "clusterId", bean.ClusterId) + common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + return + } _, err = impl.clusterNoteService.Update(ctx, &bean, userId) + if err == pg.ErrNoRows { + _, err = impl.clusterNoteService.Save(ctx, &bean, userId) + } if err != nil { impl.logger.Errorw("service err, Update", "error", err, "payload", bean) common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) diff --git a/api/cluster/ClusterRouter.go b/api/cluster/ClusterRouter.go index b699c95e1d..ed7c9049b0 100644 --- a/api/cluster/ClusterRouter.go +++ b/api/cluster/ClusterRouter.go @@ -56,11 +56,11 @@ func (impl ClusterRouterImpl) InitClusterRouter(clusterRouter *mux.Router) { clusterRouter.Path(""). Methods("PUT"). - HandlerFunc(impl.clusterRestHandler.UpdateClusterNote) + HandlerFunc(impl.clusterRestHandler.Update) clusterRouter.Path("/description"). Methods("PUT"). - HandlerFunc(impl.clusterRestHandler.Update) + HandlerFunc(impl.clusterRestHandler.UpdateClusterNote) clusterRouter.Path("/autocomplete"). Methods("GET"). diff --git a/pkg/cluster/ClusterNoteService.go b/pkg/cluster/ClusterNoteService.go index 53688adeb4..3ffb16a1b9 100644 --- a/pkg/cluster/ClusterNoteService.go +++ b/pkg/cluster/ClusterNoteService.go @@ -32,17 +32,17 @@ import ( type ClusterNoteBean struct { Id int `json:"id,omitempty" validate:"number"` ClusterId int `json:"cluster_id,omitempty" validate:"required"` - Description string `json:"description,omitempty"` - CreatedBy int `json:"created_by,omitempty"` - CreatedOn time.Time `json:"created_on,omitempty"` + Description string `json:"description,omitempty" validate:"required"` + CreatedBy int `json:"created_by"` + CreatedOn time.Time `json:"created_on"` } type ClusterNoteHistoryBean struct { Id int `json:"id,omitempty" validate:"number"` NoteId int `json:"note_id,omitempty" validate:"required"` - Description string `json:"description,omitempty"` - CreatedBy int `json:"created_by,omitempty"` - CreatedOn time.Time `json:"created_on,omitempty"` + Description string `json:"description,omitempty" validate:"required"` + CreatedBy int `json:"created_by"` + CreatedOn time.Time `json:"created_on"` } type ClusterNoteService interface { @@ -100,11 +100,15 @@ func (impl *ClusterNoteServiceImpl) Save(parent context.Context, bean *ClusterNo } bean.Id = model.Id // audit the existing description to cluster audit history - cluster_audit := &repository.ClusterNoteHistory{ + clusterAudit := &repository.ClusterNoteHistory{ NoteId: bean.Id, Description: bean.Description, } - err = impl.clusterNoteHistoryRepository.SaveHistory(cluster_audit) + clusterAudit.CreatedBy = userId + clusterAudit.UpdatedBy = userId + clusterAudit.CreatedOn = time.Now() + clusterAudit.UpdatedOn = time.Now() + err = impl.clusterNoteHistoryRepository.SaveHistory(clusterAudit) if err != nil { return nil, err } @@ -176,11 +180,15 @@ func (impl *ClusterNoteServiceImpl) Update(ctx context.Context, bean *ClusterNot } bean.Id = model.Id // audit the existing description to cluster audit history - cluster_audit := &repository.ClusterNoteHistory{ + clusterAudit := &repository.ClusterNoteHistory{ NoteId: bean.Id, Description: bean.Description, } - err = impl.clusterNoteHistoryRepository.SaveHistory(cluster_audit) + clusterAudit.CreatedBy = userId + clusterAudit.UpdatedBy = userId + clusterAudit.CreatedOn = time.Now() + clusterAudit.UpdatedOn = time.Now() + err = impl.clusterNoteHistoryRepository.SaveHistory(clusterAudit) if err != nil { return nil, err } diff --git a/scripts/sql/124_alter_cluster_details.down.sql b/scripts/sql/124_alter_cluster_details.down.sql index 61e07525d6..d6c90bb81e 100644 --- a/scripts/sql/124_alter_cluster_details.down.sql +++ b/scripts/sql/124_alter_cluster_details.down.sql @@ -1,2 +1,7 @@ +---- DROP table DROP TABLE IF EXISTS "cluster_note_history"; -DROP TABLE IF EXISTS "cluster_note"; \ No newline at end of file +DROP TABLE IF EXISTS "cluster_note"; + +---- DROP sequence +DROP SEQUENCE IF EXISTS public.id_seq_cluster_note; +DROP SEQUENCE IF EXISTS public.id_seq_cluster_note_history; \ No newline at end of file From e6e1a0cf030e012454d089266179ea3154d5439f Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Wed, 22 Mar 2023 17:56:20 +0530 Subject: [PATCH 03/19] updated rback and removed unnecessary context --- api/cluster/ClusterRestHandler.go | 35 +++++++++---------------------- pkg/cluster/ClusterNoteService.go | 14 ++++++++----- 2 files changed, 19 insertions(+), 30 deletions(-) diff --git a/api/cluster/ClusterRestHandler.go b/api/cluster/ClusterRestHandler.go index 7930386c9c..8f9bdaa49b 100644 --- a/api/cluster/ClusterRestHandler.go +++ b/api/cluster/ClusterRestHandler.go @@ -305,37 +305,22 @@ func (impl ClusterRestHandlerImpl) UpdateClusterNote(w http.ResponseWriter, r *h common.WriteJsonResp(w, err, nil, http.StatusBadRequest) return } - - ctx, cancel := context.WithCancel(r.Context()) - if cn, ok := w.(http.CloseNotifier); ok { - go func(done <-chan struct{}, closed <-chan bool) { - select { - case <-done: - case <-closed: - cancel() - } - }(ctx.Done(), cn.CloseNotify()) - } - if util2.IsBaseStack() { - ctx = context.WithValue(ctx, "token", token) - } else { - acdToken, err := impl.argoUserService.GetLatestDevtronArgoCdUserToken() - if err != nil { - impl.logger.Errorw("error in getting acd token", "err", err) - common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) - return - } - ctx = context.WithValue(ctx, "token", acdToken) - } - _, err = impl.clusterService.FindByIdWithoutConfig(bean.ClusterId) + cluster, err := impl.clusterService.FindByIdWithoutConfig(bean.ClusterId) if err != nil { impl.logger.Errorw("service err, FindById", "err", err, "clusterId", bean.ClusterId) common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) return } - _, err = impl.clusterNoteService.Update(ctx, &bean, userId) + // RBAC enforcer applying + if ok := impl.enforcer.Enforce(token, casbin.ResourceCluster, casbin.ActionUpdate, strings.ToLower(cluster.ClusterName)); !ok { + common.WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden) + return + } + // RBAC enforcer ends + + _, err = impl.clusterNoteService.Update(&bean, userId) if err == pg.ErrNoRows { - _, err = impl.clusterNoteService.Save(ctx, &bean, userId) + _, err = impl.clusterNoteService.Save(&bean, userId) } if err != nil { impl.logger.Errorw("service err, Update", "error", err, "payload", bean) diff --git a/pkg/cluster/ClusterNoteService.go b/pkg/cluster/ClusterNoteService.go index 3ffb16a1b9..8b8678bf2b 100644 --- a/pkg/cluster/ClusterNoteService.go +++ b/pkg/cluster/ClusterNoteService.go @@ -18,7 +18,6 @@ package cluster import ( - "context" "fmt" "time" @@ -46,10 +45,10 @@ type ClusterNoteHistoryBean struct { } type ClusterNoteService interface { - Save(parent context.Context, bean *ClusterNoteBean, userId int32) (*ClusterNoteBean, error) + Save(bean *ClusterNoteBean, userId int32) (*ClusterNoteBean, error) FindByClusterId(id int) (*ClusterNoteBean, error) FindByClusterIds(id []int) ([]ClusterNoteBean, error) - Update(ctx context.Context, bean *ClusterNoteBean, userId int32) (*ClusterNoteBean, error) + Update(bean *ClusterNoteBean, userId int32) (*ClusterNoteBean, error) Delete(bean *ClusterNoteBean, userId int32) error } @@ -68,7 +67,7 @@ func NewClusterNoteServiceImpl(repository repository.ClusterNoteRepository, repo return clusterNoteService } -func (impl *ClusterNoteServiceImpl) Save(parent context.Context, bean *ClusterNoteBean, userId int32) (*ClusterNoteBean, error) { +func (impl *ClusterNoteServiceImpl) Save(bean *ClusterNoteBean, userId int32) (*ClusterNoteBean, error) { existingModel, err := impl.clusterNoteRepository.FindByClusterId(bean.ClusterId) if err != nil && err != pg.ErrNoRows { impl.logger.Error(err) @@ -149,7 +148,7 @@ func (impl *ClusterNoteServiceImpl) FindByClusterIds(ids []int) ([]ClusterNoteBe return beans, nil } -func (impl *ClusterNoteServiceImpl) Update(ctx context.Context, bean *ClusterNoteBean, userId int32) (*ClusterNoteBean, error) { +func (impl *ClusterNoteServiceImpl) Update(bean *ClusterNoteBean, userId int32) (*ClusterNoteBean, error) { model, err := impl.clusterNoteRepository.FindByClusterId(bean.ClusterId) if err != nil { impl.logger.Error(err) @@ -159,6 +158,11 @@ func (impl *ClusterNoteServiceImpl) Update(ctx context.Context, bean *ClusterNot impl.logger.Errorw("error on fetching cluster note, not found", "id", bean.Id) return nil, fmt.Errorf("cluster note not found") } + if bean.Description == "" { + // blank description + impl.logger.Errorw("blank cluster note, blank", "id", bean.Id) + return nil, fmt.Errorf("blank cluster note") + } if bean.Description == "" || bean.Description == model.Description { // no change in description impl.logger.Errorw("no change found in cluster note, duplicate", "id", bean.Id) From 876593633b23969c862a11e00e56a32053dcc0f1 Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Wed, 22 Mar 2023 19:31:40 +0530 Subject: [PATCH 04/19] updated validations --- pkg/cluster/ClusterNoteService.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/pkg/cluster/ClusterNoteService.go b/pkg/cluster/ClusterNoteService.go index 8b8678bf2b..d389be95e1 100644 --- a/pkg/cluster/ClusterNoteService.go +++ b/pkg/cluster/ClusterNoteService.go @@ -158,16 +158,6 @@ func (impl *ClusterNoteServiceImpl) Update(bean *ClusterNoteBean, userId int32) impl.logger.Errorw("error on fetching cluster note, not found", "id", bean.Id) return nil, fmt.Errorf("cluster note not found") } - if bean.Description == "" { - // blank description - impl.logger.Errorw("blank cluster note, blank", "id", bean.Id) - return nil, fmt.Errorf("blank cluster note") - } - if bean.Description == "" || bean.Description == model.Description { - // no change in description - impl.logger.Errorw("no change found in cluster note, duplicate", "id", bean.Id) - return nil, fmt.Errorf("duplicate cluster note") - } // update the cluster description with new data model.Description = bean.Description model.UpdatedBy = userId From 299b4aa866e9423915a17f350b650862c28411be Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Thu, 23 Mar 2023 12:50:31 +0530 Subject: [PATCH 05/19] added Integration test cases --- pkg/cluster/ClusterNoteService_test.go | 144 +++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 pkg/cluster/ClusterNoteService_test.go diff --git a/pkg/cluster/ClusterNoteService_test.go b/pkg/cluster/ClusterNoteService_test.go new file mode 100644 index 0000000000..eea814adb7 --- /dev/null +++ b/pkg/cluster/ClusterNoteService_test.go @@ -0,0 +1,144 @@ +package cluster + +import ( + "log" + "testing" + "time" + + "github.com/caarlos0/env" + "github.com/devtron-labs/devtron/internal/util" + "github.com/devtron-labs/devtron/pkg/cluster/repository" + "github.com/go-pg/pg" + "github.com/stretchr/testify/assert" +) + +type Config struct { + Addr string `env:"TEST_PG_ADDR" envDefault:"127.0.0.1"` + Port string `env:"TEST_PG_PORT" envDefault:"55000"` + User string `env:"TEST_PG_USER" envDefault:"postgres"` + Password string `env:"TEST_PG_PASSWORD" envDefault:"postgrespw" secretData:"-"` + Database string `env:"TEST_PG_DATABASE" envDefault:"orchestrator"` + ApplicationName string `env:"TEST_APP" envDefault:"orchestrator"` + LogQuery bool `env:"TEST_PG_LOG_QUERY" envDefault:"true"` +} + +var clusterNoteService *ClusterNoteServiceImpl + +func TestClusterNoteService_Save(t *testing.T) { + t.SkipNow() + if clusterNoteService == nil { + InitClusterNoteService() + } + + testCases := []struct { + name string + input *ClusterNoteBean + expectedErr bool + }{ + { + name: "TEST : successfully save the note", + input: &ClusterNoteBean{ + Id: 0, + ClusterId: 1, + Description: "Test Note", + CreatedBy: 1, + CreatedOn: time.Now(), + }, + expectedErr: false, + }, + { + name: "TEST : error while saving the existing note", + input: &ClusterNoteBean{ + Id: 0, + ClusterId: 1, + Description: "Test Note", + CreatedBy: 1, + CreatedOn: time.Now(), + }, + expectedErr: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(tt *testing.T) { + res, err := clusterNoteService.Save(tc.input, 1) + if tc.expectedErr { + assert.NotNil(tt, err) + } else { + assert.Nil(tt, err) + assert.NotEqual(tt, res.Id, 0) + } + }) + } +} + +func TestClusterNoteServiceImpl_Update_InvalidFields(t *testing.T) { + t.SkipNow() + if clusterNoteService == nil { + InitClusterNoteService() + } + + // insert a cluster note in the database which will be updated later + note := &ClusterNoteBean{ + ClusterId: 100, + Description: "test note", + CreatedBy: 1, + } + _, err := clusterNoteService.Save(note, 1) + if err != nil { + t.Fatalf("Error inserting record in database: %s", err.Error()) + } + + // define input for update function + input := &ClusterNoteBean{ + Id: 1, + ClusterId: 100, + } + + // try updating the record with invalid fields and check if it returns error + _, err = clusterNoteService.Update(input, 1) + if err == nil { + t.Fatal("Expected an error on updating record with invalid fields, but got nil") + } +} + +var db *pg.DB + +func getDbConn() (*pg.DB, error) { + if db != nil { + return db, nil + } + cfg := Config{} + err := env.Parse(&cfg) + if err != nil { + return nil, err + } + options := pg.Options{ + Addr: cfg.Addr + ":" + cfg.Port, + User: cfg.User, + Password: cfg.Password, + Database: cfg.Database, + ApplicationName: cfg.ApplicationName, + } + dbConnection := pg.Connect(&options) + return dbConnection, nil +} + +func InitClusterNoteService() { + if clusterNoteService != nil { + return + } + logger, err := util.NewSugardLogger() + if err != nil { + log.Fatalf("error in logger initialization %s,%s", "err", err) + } + conn, err := getDbConn() + if err != nil { + log.Fatalf("error in db connection initialization %s, %s", "err", err) + } + + clusterNoteHistoryRepository := repository.NewClusterNoteHistoryRepositoryImpl(conn, logger) + clusterNoteRepository := repository.NewClusterNoteRepositoryImpl(conn, logger) + + clusterNoteService = NewClusterNoteServiceImpl(clusterNoteRepository, clusterNoteHistoryRepository, logger) +} From 1b9516b1cd8f05473c016a42cc03af7064f57a0c Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Thu, 23 Mar 2023 17:49:35 +0530 Subject: [PATCH 06/19] incorporated the feedbacks --- pkg/cluster/ClusterNoteService.go | 17 +++---------- .../repository/ClusterNoteRepository.go | 25 ++++++++----------- 2 files changed, 14 insertions(+), 28 deletions(-) diff --git a/pkg/cluster/ClusterNoteService.go b/pkg/cluster/ClusterNoteService.go index d389be95e1..3267fedafd 100644 --- a/pkg/cluster/ClusterNoteService.go +++ b/pkg/cluster/ClusterNoteService.go @@ -47,9 +47,8 @@ type ClusterNoteHistoryBean struct { type ClusterNoteService interface { Save(bean *ClusterNoteBean, userId int32) (*ClusterNoteBean, error) FindByClusterId(id int) (*ClusterNoteBean, error) - FindByClusterIds(id []int) ([]ClusterNoteBean, error) + FindByClusterIds(id []int) ([]*ClusterNoteBean, error) Update(bean *ClusterNoteBean, userId int32) (*ClusterNoteBean, error) - Delete(bean *ClusterNoteBean, userId int32) error } type ClusterNoteServiceImpl struct { @@ -129,15 +128,15 @@ func (impl *ClusterNoteServiceImpl) FindByClusterId(id int) (*ClusterNoteBean, e return bean, nil } -func (impl *ClusterNoteServiceImpl) FindByClusterIds(ids []int) ([]ClusterNoteBean, error) { +func (impl *ClusterNoteServiceImpl) FindByClusterIds(ids []int) ([]*ClusterNoteBean, error) { models, err := impl.clusterNoteRepository.FindByClusterIds(ids) if err != nil { return nil, err } - var beans []ClusterNoteBean + var beans []*ClusterNoteBean for _, model := range models { - beans = append(beans, ClusterNoteBean{ + beans = append(beans, &ClusterNoteBean{ Id: model.Id, ClusterId: model.ClusterId, Description: model.Description, @@ -188,11 +187,3 @@ func (impl *ClusterNoteServiceImpl) Update(bean *ClusterNoteBean, userId int32) } return bean, err } - -func (impl *ClusterNoteServiceImpl) Delete(bean *ClusterNoteBean, userId int32) error { - model, err := impl.clusterNoteRepository.FindByClusterId(bean.ClusterId) - if err != nil { - return err - } - return impl.clusterNoteRepository.Delete(model) -} diff --git a/pkg/cluster/repository/ClusterNoteRepository.go b/pkg/cluster/repository/ClusterNoteRepository.go index 4cb4393663..a7843bfb46 100644 --- a/pkg/cluster/repository/ClusterNoteRepository.go +++ b/pkg/cluster/repository/ClusterNoteRepository.go @@ -34,9 +34,8 @@ type ClusterNote struct { type ClusterNoteRepository interface { Save(model *ClusterNote) error FindByClusterId(id int) (*ClusterNote, error) - FindByClusterIds(id []int) ([]ClusterNote, error) + FindByClusterIds(id []int) ([]*ClusterNote, error) Update(model *ClusterNote) error - Delete(model *ClusterNote) error } func NewClusterNoteRepositoryImpl(dbConnection *pg.DB, logger *zap.SugaredLogger) *ClusterNoteRepositoryImpl { @@ -58,26 +57,22 @@ func (impl ClusterNoteRepositoryImpl) Save(model *ClusterNote) error { func (impl ClusterNoteRepositoryImpl) FindByClusterId(id int) (*ClusterNote, error) { clusterNote := &ClusterNote{} err := impl.dbConnection. - Model(clusterNote). - Where("cluster_id =?", id). - Limit(1). - Select() + Model(clusterNote). + Where("cluster_id =?", id). + Limit(1). + Select() return clusterNote, err } -func (impl ClusterNoteRepositoryImpl) FindByClusterIds(id []int) ([]ClusterNote, error) { - var clusterNotes []ClusterNote +func (impl ClusterNoteRepositoryImpl) FindByClusterIds(id []int) ([]*ClusterNote, error) { + var clusterNotes []*ClusterNote err := impl.dbConnection. - Model(&clusterNotes). - Where("cluster_id in(?)", pg.In(id)). - Select() + Model(&clusterNotes). + Where("cluster_id in(?)", pg.In(id)). + Select() return clusterNotes, err } func (impl ClusterNoteRepositoryImpl) Update(model *ClusterNote) error { return impl.dbConnection.Update(model) } - -func (impl ClusterNoteRepositoryImpl) Delete(model *ClusterNote) error { - return impl.dbConnection.Delete(model) -} \ No newline at end of file From 64e12cbf23b5400fc41260c0e3cb46987337347b Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Thu, 23 Mar 2023 17:52:28 +0530 Subject: [PATCH 07/19] updated the migration script numbers --- ...luster_details.down.sql => 123_alter_cluster_details.down.sql} | 0 ...er_cluster_details.up.sql => 123_alter_cluster_details.up.sql} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename scripts/sql/{124_alter_cluster_details.down.sql => 123_alter_cluster_details.down.sql} (100%) rename scripts/sql/{124_alter_cluster_details.up.sql => 123_alter_cluster_details.up.sql} (100%) diff --git a/scripts/sql/124_alter_cluster_details.down.sql b/scripts/sql/123_alter_cluster_details.down.sql similarity index 100% rename from scripts/sql/124_alter_cluster_details.down.sql rename to scripts/sql/123_alter_cluster_details.down.sql diff --git a/scripts/sql/124_alter_cluster_details.up.sql b/scripts/sql/123_alter_cluster_details.up.sql similarity index 100% rename from scripts/sql/124_alter_cluster_details.up.sql rename to scripts/sql/123_alter_cluster_details.up.sql From 5ce5601d11c55306b49c5343dfc7b3e73e73ca2b Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Thu, 23 Mar 2023 17:59:54 +0530 Subject: [PATCH 08/19] updated param name for id --- pkg/cluster/repository/ClusterNoteRepository.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/cluster/repository/ClusterNoteRepository.go b/pkg/cluster/repository/ClusterNoteRepository.go index a7843bfb46..c33c348800 100644 --- a/pkg/cluster/repository/ClusterNoteRepository.go +++ b/pkg/cluster/repository/ClusterNoteRepository.go @@ -64,11 +64,11 @@ func (impl ClusterNoteRepositoryImpl) FindByClusterId(id int) (*ClusterNote, err return clusterNote, err } -func (impl ClusterNoteRepositoryImpl) FindByClusterIds(id []int) ([]*ClusterNote, error) { +func (impl ClusterNoteRepositoryImpl) FindByClusterIds(ids []int) ([]*ClusterNote, error) { var clusterNotes []*ClusterNote err := impl.dbConnection. Model(&clusterNotes). - Where("cluster_id in(?)", pg.In(id)). + Where("cluster_id in(?)", pg.In(ids)). Select() return clusterNotes, err } From 9dda6e90e555b659599832d4ac8581e52eb65121 Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Mon, 24 Apr 2023 17:00:06 +0530 Subject: [PATCH 09/19] migration scripts updated --- ...luster_details.down.sql => 132_alter_cluster_details.down.sql} | 0 ...er_cluster_details.up.sql => 132_alter_cluster_details.up.sql} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename scripts/sql/{123_alter_cluster_details.down.sql => 132_alter_cluster_details.down.sql} (100%) rename scripts/sql/{123_alter_cluster_details.up.sql => 132_alter_cluster_details.up.sql} (100%) diff --git a/scripts/sql/123_alter_cluster_details.down.sql b/scripts/sql/132_alter_cluster_details.down.sql similarity index 100% rename from scripts/sql/123_alter_cluster_details.down.sql rename to scripts/sql/132_alter_cluster_details.down.sql diff --git a/scripts/sql/123_alter_cluster_details.up.sql b/scripts/sql/132_alter_cluster_details.up.sql similarity index 100% rename from scripts/sql/123_alter_cluster_details.up.sql rename to scripts/sql/132_alter_cluster_details.up.sql From 3122cbc5f0a17d804f75f5ad22eafc20bed5f1f1 Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Mon, 24 Apr 2023 20:24:42 +0530 Subject: [PATCH 10/19] error handler update and rbac added --- api/cluster/ClusterRestHandler.go | 74 +++++++++++++------ api/cluster/ClusterRouter.go | 2 +- pkg/cluster/ClusterNoteService.go | 6 +- ...sql => 133_alter_cluster_details.down.sql} | 0 ...p.sql => 133_alter_cluster_details.up.sql} | 0 5 files changed, 56 insertions(+), 26 deletions(-) rename scripts/sql/{132_alter_cluster_details.down.sql => 133_alter_cluster_details.down.sql} (100%) rename scripts/sql/{132_alter_cluster_details.up.sql => 133_alter_cluster_details.up.sql} (100%) diff --git a/api/cluster/ClusterRestHandler.go b/api/cluster/ClusterRestHandler.go index 8f9bdaa49b..e50088ce8f 100644 --- a/api/cluster/ClusterRestHandler.go +++ b/api/cluster/ClusterRestHandler.go @@ -45,7 +45,7 @@ type ClusterRestHandler interface { Save(w http.ResponseWriter, r *http.Request) FindAll(w http.ResponseWriter, r *http.Request) FindById(w http.ResponseWriter, r *http.Request) - FindByClusterId(w http.ResponseWriter, r *http.Request) + FindNoteByClusterId(w http.ResponseWriter, r *http.Request) Update(w http.ResponseWriter, r *http.Request) UpdateClusterNote(w http.ResponseWriter, r *http.Request) FindAllForAutoComplete(w http.ResponseWriter, r *http.Request) @@ -56,14 +56,14 @@ type ClusterRestHandler interface { } type ClusterRestHandlerImpl struct { - clusterService cluster.ClusterService - clusterNoteService cluster.ClusterNoteService - logger *zap.SugaredLogger - userService user.UserService - validator *validator.Validate - enforcer casbin.Enforcer - deleteService delete2.DeleteService - argoUserService argo.ArgoUserService + clusterService cluster.ClusterService + clusterNoteService cluster.ClusterNoteService + logger *zap.SugaredLogger + userService user.UserService + validator *validator.Validate + enforcer casbin.Enforcer + deleteService delete2.DeleteService + argoUserService argo.ArgoUserService } func NewClusterRestHandlerImpl(clusterService cluster.ClusterService, @@ -75,14 +75,14 @@ func NewClusterRestHandlerImpl(clusterService cluster.ClusterService, deleteService delete2.DeleteService, argoUserService argo.ArgoUserService) *ClusterRestHandlerImpl { return &ClusterRestHandlerImpl{ - clusterService: clusterService, - clusterNoteService: clusterNoteService, - logger: logger, - userService: userService, - validator: validator, - enforcer: enforcer, - deleteService: deleteService, - argoUserService: argoUserService, + clusterService: clusterService, + clusterNoteService: clusterNoteService, + logger: logger, + userService: userService, + validator: validator, + enforcer: enforcer, + deleteService: deleteService, + argoUserService: argoUserService, } } @@ -203,7 +203,7 @@ func (impl ClusterRestHandlerImpl) FindById(w http.ResponseWriter, r *http.Reque common.WriteJsonResp(w, err, bean, http.StatusOK) } -func (impl ClusterRestHandlerImpl) FindByClusterId(w http.ResponseWriter, r *http.Request) { +func (impl ClusterRestHandlerImpl) FindNoteByClusterId(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id := vars["id"] i, err := strconv.Atoi(id) @@ -212,12 +212,37 @@ func (impl ClusterRestHandlerImpl) FindByClusterId(w http.ResponseWriter, r *htt common.WriteJsonResp(w, err, nil, http.StatusBadRequest) return } + + clusterBean, err := impl.clusterService.FindByIdWithoutConfig(i) + if err != nil { + if err == pg.ErrNoRows { + impl.logger.Errorw("cluster id not found, FindById", "err", err, "clusterId", i) + common.WriteJsonResp(w, errors.New("invalid cluster id"), nil, http.StatusBadRequest) + return + } + impl.logger.Errorw("cluster service err, FindById", "err", err, "clusterId", i) + common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + return + } + // RBAC enforcer applying + token := r.Header.Get("token") + if ok := impl.enforcer.Enforce(token, casbin.ResourceCluster, casbin.ActionGet, strings.ToLower(clusterBean.ClusterName)); !ok { + common.WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden) + return + } + //RBAC enforcer Ends bean, err := impl.clusterNoteService.FindByClusterId(i) if err != nil { - impl.logger.Errorw("service err, FindById", "err", err, "clusterId", id) + if err == pg.ErrNoRows { + impl.logger.Errorw("cluster note not found, FindById", "err", err, "clusterId", id) + common.WriteJsonResp(w, errors.New("no cluster note found"), nil, http.StatusOK) + return + } + impl.logger.Errorw("cluster note service err, FindById", "err", err, "clusterId", id) common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) return } + common.WriteJsonResp(w, err, bean, http.StatusOK) } @@ -307,7 +332,12 @@ func (impl ClusterRestHandlerImpl) UpdateClusterNote(w http.ResponseWriter, r *h } cluster, err := impl.clusterService.FindByIdWithoutConfig(bean.ClusterId) if err != nil { - impl.logger.Errorw("service err, FindById", "err", err, "clusterId", bean.ClusterId) + if err == pg.ErrNoRows { + impl.logger.Errorw("cluster id not found, FindById", "err", err, "clusterId", bean.ClusterId) + common.WriteJsonResp(w, errors.New("invalid cluster id"), nil, http.StatusBadRequest) + return + } + impl.logger.Errorw("cluster service err, FindById", "err", err, "clusterId", bean.ClusterId) common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) return } @@ -317,13 +347,13 @@ func (impl ClusterRestHandlerImpl) UpdateClusterNote(w http.ResponseWriter, r *h return } // RBAC enforcer ends - + _, err = impl.clusterNoteService.Update(&bean, userId) if err == pg.ErrNoRows { _, err = impl.clusterNoteService.Save(&bean, userId) } if err != nil { - impl.logger.Errorw("service err, Update", "error", err, "payload", bean) + impl.logger.Errorw("cluster note service err, Update", "error", err, "payload", bean) common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) return } diff --git a/api/cluster/ClusterRouter.go b/api/cluster/ClusterRouter.go index ed7c9049b0..a00751b0e8 100644 --- a/api/cluster/ClusterRouter.go +++ b/api/cluster/ClusterRouter.go @@ -48,7 +48,7 @@ func (impl ClusterRouterImpl) InitClusterRouter(clusterRouter *mux.Router) { clusterRouter.Path("/description"). Methods("GET"). Queries("id", "{id}"). - HandlerFunc(impl.clusterRestHandler.FindByClusterId) + HandlerFunc(impl.clusterRestHandler.FindNoteByClusterId) clusterRouter.Path(""). Methods("GET"). diff --git a/pkg/cluster/ClusterNoteService.go b/pkg/cluster/ClusterNoteService.go index 3267fedafd..d895b8e3d3 100644 --- a/pkg/cluster/ClusterNoteService.go +++ b/pkg/cluster/ClusterNoteService.go @@ -29,9 +29,9 @@ import ( ) type ClusterNoteBean struct { - Id int `json:"id,omitempty" validate:"number"` - ClusterId int `json:"cluster_id,omitempty" validate:"required"` - Description string `json:"description,omitempty" validate:"required"` + Id int `json:"id" validate:"number"` + ClusterId int `json:"cluster_id" validate:"required"` + Description string `json:"description" validate:"required"` CreatedBy int `json:"created_by"` CreatedOn time.Time `json:"created_on"` } diff --git a/scripts/sql/132_alter_cluster_details.down.sql b/scripts/sql/133_alter_cluster_details.down.sql similarity index 100% rename from scripts/sql/132_alter_cluster_details.down.sql rename to scripts/sql/133_alter_cluster_details.down.sql diff --git a/scripts/sql/132_alter_cluster_details.up.sql b/scripts/sql/133_alter_cluster_details.up.sql similarity index 100% rename from scripts/sql/132_alter_cluster_details.up.sql rename to scripts/sql/133_alter_cluster_details.up.sql From d911fd0bee4fc3b92f517f4ca7c8e373101c6ff4 Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Tue, 25 Apr 2023 16:31:57 +0530 Subject: [PATCH 11/19] updated and sanity --- api/cluster/ClusterRestHandler.go | 27 +++++++++---- pkg/cluster/ClusterNoteService.go | 64 ++++++++++++++++++++++++++----- pkg/cluster/ClusterService.go | 4 ++ wire_gen.go | 7 ++-- 4 files changed, 82 insertions(+), 20 deletions(-) diff --git a/api/cluster/ClusterRestHandler.go b/api/cluster/ClusterRestHandler.go index e50088ce8f..53af1a8547 100644 --- a/api/cluster/ClusterRestHandler.go +++ b/api/cluster/ClusterRestHandler.go @@ -217,7 +217,7 @@ func (impl ClusterRestHandlerImpl) FindNoteByClusterId(w http.ResponseWriter, r if err != nil { if err == pg.ErrNoRows { impl.logger.Errorw("cluster id not found, FindById", "err", err, "clusterId", i) - common.WriteJsonResp(w, errors.New("invalid cluster id"), nil, http.StatusBadRequest) + common.WriteJsonResp(w, errors.New("invalid cluster id"), nil, http.StatusNotFound) return } impl.logger.Errorw("cluster service err, FindById", "err", err, "clusterId", i) @@ -234,16 +234,25 @@ func (impl ClusterRestHandlerImpl) FindNoteByClusterId(w http.ResponseWriter, r bean, err := impl.clusterNoteService.FindByClusterId(i) if err != nil { if err == pg.ErrNoRows { + clusterDescriptionBean, userIdErr := impl.clusterNoteService.GenerateClusterDescription(bean, clusterBean, false) + if userIdErr != nil { + common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + return + } impl.logger.Errorw("cluster note not found, FindById", "err", err, "clusterId", id) - common.WriteJsonResp(w, errors.New("no cluster note found"), nil, http.StatusOK) + common.WriteJsonResp(w, nil, clusterDescriptionBean, http.StatusOK) return } impl.logger.Errorw("cluster note service err, FindById", "err", err, "clusterId", id) common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) return } - - common.WriteJsonResp(w, err, bean, http.StatusOK) + clusterDescriptionBean, userIdErr := impl.clusterNoteService.GenerateClusterDescription(bean, clusterBean, false) + if userIdErr != nil { + common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + return + } + common.WriteJsonResp(w, err, clusterDescriptionBean, http.StatusOK) } func (impl ClusterRestHandlerImpl) Update(w http.ResponseWriter, r *http.Request) { @@ -334,7 +343,7 @@ func (impl ClusterRestHandlerImpl) UpdateClusterNote(w http.ResponseWriter, r *h if err != nil { if err == pg.ErrNoRows { impl.logger.Errorw("cluster id not found, FindById", "err", err, "clusterId", bean.ClusterId) - common.WriteJsonResp(w, errors.New("invalid cluster id"), nil, http.StatusBadRequest) + common.WriteJsonResp(w, errors.New("invalid cluster id"), nil, http.StatusNotFound) return } impl.logger.Errorw("cluster service err, FindById", "err", err, "clusterId", bean.ClusterId) @@ -357,8 +366,12 @@ func (impl ClusterRestHandlerImpl) UpdateClusterNote(w http.ResponseWriter, r *h common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) return } - - common.WriteJsonResp(w, err, bean, http.StatusOK) + clusterDescriptionBean, userIdErr := impl.clusterNoteService.GenerateClusterDescription(&bean, cluster, true) + if userIdErr != nil { + common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + return + } + common.WriteJsonResp(w, err, clusterDescriptionBean, http.StatusOK) } func (impl ClusterRestHandlerImpl) FindAllForAutoComplete(w http.ResponseWriter, r *http.Request) { diff --git a/pkg/cluster/ClusterNoteService.go b/pkg/cluster/ClusterNoteService.go index d895b8e3d3..c78a37220c 100644 --- a/pkg/cluster/ClusterNoteService.go +++ b/pkg/cluster/ClusterNoteService.go @@ -24,6 +24,7 @@ import ( "github.com/devtron-labs/devtron/internal/constants" "github.com/devtron-labs/devtron/internal/util" "github.com/devtron-labs/devtron/pkg/cluster/repository" + repository2 "github.com/devtron-labs/devtron/pkg/user/repository" "github.com/go-pg/pg" "go.uber.org/zap" ) @@ -32,14 +33,25 @@ type ClusterNoteBean struct { Id int `json:"id" validate:"number"` ClusterId int `json:"cluster_id" validate:"required"` Description string `json:"description" validate:"required"` - CreatedBy int `json:"created_by"` - CreatedOn time.Time `json:"created_on"` + UpdatedBy int `json:"updated_by"` + UpdatedOn time.Time `json:"updated_on"` +} + +type ClusterDescriptionBean struct { + Id int `json:"id,omitempty"` + ClusterId int `json:"cluster_id"` + ClusterName string `json:"cluster_name"` + Description string `json:"description,omitempty"` + CreatedBy string `json:"updated_by,omitempty"` + CreatedOn *time.Time `json:"updated_on,omitempty"` + ClusterCreatedBy string `json:"cluster_created_by"` + ClusterCreatedOn *time.Time `json:"cluster_created_on"` } type ClusterNoteHistoryBean struct { - Id int `json:"id,omitempty" validate:"number"` - NoteId int `json:"note_id,omitempty" validate:"required"` - Description string `json:"description,omitempty" validate:"required"` + Id int `json:"id" validate:"number"` + NoteId int `json:"note_id" validate:"required"` + Description string `json:"description" validate:"required"` CreatedBy int `json:"created_by"` CreatedOn time.Time `json:"created_on"` } @@ -49,23 +61,53 @@ type ClusterNoteService interface { FindByClusterId(id int) (*ClusterNoteBean, error) FindByClusterIds(id []int) ([]*ClusterNoteBean, error) Update(bean *ClusterNoteBean, userId int32) (*ClusterNoteBean, error) + GenerateClusterDescription(bean *ClusterNoteBean, clusterBean *ClusterBean, isUpdate bool) (*ClusterDescriptionBean, error) } type ClusterNoteServiceImpl struct { clusterNoteRepository repository.ClusterNoteRepository clusterNoteHistoryRepository repository.ClusterNoteHistoryRepository + userRepository repository2.UserRepository logger *zap.SugaredLogger } -func NewClusterNoteServiceImpl(repository repository.ClusterNoteRepository, repositoryHistory repository.ClusterNoteHistoryRepository, logger *zap.SugaredLogger) *ClusterNoteServiceImpl { +func NewClusterNoteServiceImpl(repository repository.ClusterNoteRepository, repositoryHistory repository.ClusterNoteHistoryRepository, userRepository repository2.UserRepository, logger *zap.SugaredLogger) *ClusterNoteServiceImpl { clusterNoteService := &ClusterNoteServiceImpl{ clusterNoteRepository: repository, clusterNoteHistoryRepository: repositoryHistory, + userRepository: userRepository, logger: logger, } return clusterNoteService } +func (impl *ClusterNoteServiceImpl) GenerateClusterDescription(bean *ClusterNoteBean, clusterBean *ClusterBean, isUpdate bool) (*ClusterDescriptionBean, error) { + clusterDescription := &ClusterDescriptionBean{} + if !isUpdate { + userDetails, err := impl.userRepository.GetById(int32(clusterBean.CreatedBy)) + if err != nil { + impl.logger.Errorw("user service err, GetById", "err", err, "id", clusterBean.CreatedBy) + return nil, err + } + clusterDescription.ClusterCreatedOn = &clusterBean.CreatedOn + clusterDescription.ClusterCreatedBy = userDetails.EmailId + clusterDescription.ClusterId = clusterBean.Id + clusterDescription.ClusterName = clusterBean.ClusterName + } + if bean != nil { + userDetails, err := impl.userRepository.GetById(int32(bean.UpdatedBy)) + if err != nil { + impl.logger.Errorw("user service err, GetById", "err", err, "id", bean.UpdatedBy) + return nil, err + } + clusterDescription.Id = bean.Id + clusterDescription.Description = bean.Description + clusterDescription.CreatedOn = &bean.UpdatedOn + clusterDescription.CreatedBy = userDetails.EmailId + } + return clusterDescription, nil +} + func (impl *ClusterNoteServiceImpl) Save(bean *ClusterNoteBean, userId int32) (*ClusterNoteBean, error) { existingModel, err := impl.clusterNoteRepository.FindByClusterId(bean.ClusterId) if err != nil && err != pg.ErrNoRows { @@ -122,8 +164,8 @@ func (impl *ClusterNoteServiceImpl) FindByClusterId(id int) (*ClusterNoteBean, e Id: model.Id, ClusterId: model.ClusterId, Description: model.Description, - CreatedBy: int(model.CreatedBy), - CreatedOn: model.CreatedOn, + UpdatedBy: int(model.UpdatedBy), + UpdatedOn: model.UpdatedOn, } return bean, nil } @@ -140,8 +182,8 @@ func (impl *ClusterNoteServiceImpl) FindByClusterIds(ids []int) ([]*ClusterNoteB Id: model.Id, ClusterId: model.ClusterId, Description: model.Description, - CreatedBy: int(model.CreatedBy), - CreatedOn: model.CreatedOn, + UpdatedBy: int(model.CreatedBy), + UpdatedOn: model.CreatedOn, }) } return beans, nil @@ -172,6 +214,8 @@ func (impl *ClusterNoteServiceImpl) Update(bean *ClusterNoteBean, userId int32) return bean, err } bean.Id = model.Id + bean.UpdatedBy = int(model.UpdatedBy) + bean.UpdatedOn = model.UpdatedOn // audit the existing description to cluster audit history clusterAudit := &repository.ClusterNoteHistory{ NoteId: bean.Id, diff --git a/pkg/cluster/ClusterService.go b/pkg/cluster/ClusterService.go index c9cee9799a..ebd3e646c4 100644 --- a/pkg/cluster/ClusterService.go +++ b/pkg/cluster/ClusterService.go @@ -69,6 +69,8 @@ type ClusterBean struct { HasConfigOrUrlChanged bool `json:"-"` ErrorInConnecting string `json:"errorInConnecting,omitempty"` IsCdArgoSetup bool `json:"isCdArgoSetup"` + CreatedBy int `json:"cluster_created_by"` + CreatedOn time.Time `json:"cluster_created_on"` } type PrometheusAuth struct { @@ -370,6 +372,8 @@ func (impl *ClusterServiceImpl) FindById(id int) (*ClusterBean, error) { Active: model.Active, Config: model.Config, K8sVersion: model.K8sVersion, + CreatedOn: model.CreatedOn, + CreatedBy: int(model.CreatedBy), } prometheusAuth := &PrometheusAuth{ UserName: model.PUserName, diff --git a/wire_gen.go b/wire_gen.go index 7739c2a715..b36268139d 100644 --- a/wire_gen.go +++ b/wire_gen.go @@ -1,7 +1,8 @@ // Code generated by Wire. DO NOT EDIT. -//go:generate wire -//+build !wireinject +//go:generate go run github.com/google/wire/cmd/wire +//go:build !wireinject +// +build !wireinject package main @@ -469,7 +470,7 @@ func InitializeApp() (*App, error) { environmentRouterImpl := cluster3.NewEnvironmentRouterImpl(environmentRestHandlerImpl) clusterNoteRepositoryImpl := repository2.NewClusterNoteRepositoryImpl(db, sugaredLogger) clusterNoteHistoryRepositoryImpl := repository2.NewClusterNoteHistoryRepositoryImpl(db, sugaredLogger) - clusterNoteServiceImpl := cluster2.NewClusterNoteServiceImpl(clusterNoteRepositoryImpl, clusterNoteHistoryRepositoryImpl, sugaredLogger) + clusterNoteServiceImpl := cluster2.NewClusterNoteServiceImpl(clusterNoteRepositoryImpl, clusterNoteHistoryRepositoryImpl, userRepositoryImpl, sugaredLogger) clusterRestHandlerImpl := cluster3.NewClusterRestHandlerImpl(clusterServiceImplExtended, clusterNoteServiceImpl, sugaredLogger, userServiceImpl, validate, enforcerImpl, deleteServiceExtendedImpl, argoUserServiceImpl) clusterRouterImpl := cluster3.NewClusterRouterImpl(clusterRestHandlerImpl) gitWebhookRepositoryImpl := repository.NewGitWebhookRepositoryImpl(db) From 2bb0d72350a26bffa2eb47f52324d6c79d584377 Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Tue, 25 Apr 2023 19:49:17 +0530 Subject: [PATCH 12/19] fixed bug while saving --- pkg/cluster/ClusterNoteService.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/cluster/ClusterNoteService.go b/pkg/cluster/ClusterNoteService.go index c78a37220c..cd1837969b 100644 --- a/pkg/cluster/ClusterNoteService.go +++ b/pkg/cluster/ClusterNoteService.go @@ -139,6 +139,8 @@ func (impl *ClusterNoteServiceImpl) Save(bean *ClusterNoteBean, userId int32) (* } } bean.Id = model.Id + bean.UpdatedBy = int(model.UpdatedBy) + bean.UpdatedOn = model.UpdatedOn // audit the existing description to cluster audit history clusterAudit := &repository.ClusterNoteHistory{ NoteId: bean.Id, From 5753ede4bd532b4f73744585b45b2f27a43b45c7 Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Wed, 26 Apr 2023 02:30:38 +0530 Subject: [PATCH 13/19] updated the integration test case --- pkg/cluster/ClusterNoteService_test.go | 85 +++++++++++++++++++------- 1 file changed, 63 insertions(+), 22 deletions(-) diff --git a/pkg/cluster/ClusterNoteService_test.go b/pkg/cluster/ClusterNoteService_test.go index eea814adb7..d22572c24a 100644 --- a/pkg/cluster/ClusterNoteService_test.go +++ b/pkg/cluster/ClusterNoteService_test.go @@ -8,28 +8,27 @@ import ( "github.com/caarlos0/env" "github.com/devtron-labs/devtron/internal/util" "github.com/devtron-labs/devtron/pkg/cluster/repository" + repository2 "github.com/devtron-labs/devtron/pkg/user/repository" "github.com/go-pg/pg" "github.com/stretchr/testify/assert" ) type Config struct { - Addr string `env:"TEST_PG_ADDR" envDefault:"127.0.0.1"` - Port string `env:"TEST_PG_PORT" envDefault:"55000"` - User string `env:"TEST_PG_USER" envDefault:"postgres"` - Password string `env:"TEST_PG_PASSWORD" envDefault:"postgrespw" secretData:"-"` - Database string `env:"TEST_PG_DATABASE" envDefault:"orchestrator"` - ApplicationName string `env:"TEST_APP" envDefault:"orchestrator"` - LogQuery bool `env:"TEST_PG_LOG_QUERY" envDefault:"true"` + Addr string `env:"TEST_PG_ADDR" envDefault:"127.0.0.1"` + Port string `env:"TEST_PG_PORT" envDefault:"5432"` + User string `env:"TEST_PG_USER" envDefault:"postgres"` + Password string `env:"TEST_PG_PASSWORD" envDefault:"postgrespw" secretData:"-"` + Database string `env:"TEST_PG_DATABASE" envDefault:"postgres"` + LogQuery bool `env:"TEST_PG_LOG_QUERY" envDefault:"true"` } var clusterNoteService *ClusterNoteServiceImpl func TestClusterNoteService_Save(t *testing.T) { - t.SkipNow() if clusterNoteService == nil { InitClusterNoteService() } - + initialiseDb(t) testCases := []struct { name string input *ClusterNoteBean @@ -41,8 +40,8 @@ func TestClusterNoteService_Save(t *testing.T) { Id: 0, ClusterId: 1, Description: "Test Note", - CreatedBy: 1, - CreatedOn: time.Now(), + UpdatedBy: 1, + UpdatedOn: time.Now(), }, expectedErr: false, }, @@ -52,8 +51,8 @@ func TestClusterNoteService_Save(t *testing.T) { Id: 0, ClusterId: 1, Description: "Test Note", - CreatedBy: 1, - CreatedOn: time.Now(), + UpdatedBy: 1, + UpdatedOn: time.Now(), }, expectedErr: true, }, @@ -70,19 +69,20 @@ func TestClusterNoteService_Save(t *testing.T) { } }) } + //clean data in db + cleanDb(t) } func TestClusterNoteServiceImpl_Update_InvalidFields(t *testing.T) { - t.SkipNow() if clusterNoteService == nil { InitClusterNoteService() } - + initialiseDb(t) // insert a cluster note in the database which will be updated later note := &ClusterNoteBean{ ClusterId: 100, Description: "test note", - CreatedBy: 1, + UpdatedBy: 1, } _, err := clusterNoteService.Save(note, 1) if err != nil { @@ -100,6 +100,8 @@ func TestClusterNoteServiceImpl_Update_InvalidFields(t *testing.T) { if err == nil { t.Fatal("Expected an error on updating record with invalid fields, but got nil") } + //clean data in db + cleanDb(t) } var db *pg.DB @@ -114,16 +116,54 @@ func getDbConn() (*pg.DB, error) { return nil, err } options := pg.Options{ - Addr: cfg.Addr + ":" + cfg.Port, - User: cfg.User, - Password: cfg.Password, - Database: cfg.Database, - ApplicationName: cfg.ApplicationName, + Addr: cfg.Addr + ":" + cfg.Port, + User: cfg.User, + Password: cfg.Password, + Database: cfg.Database, } dbConnection := pg.Connect(&options) return dbConnection, nil } +func cleanDb(tt *testing.T) { + DB, _ := getDbConn() + query := "truncate cluster cascade;" + _, err := DB.Exec(query) + assert.Nil(tt, err) + if err != nil { + return + } +} + +func initialiseDb(tt *testing.T) { + DB, _ := getDbConn() + query := "CREATE TABLE IF NOT EXISTS public.cluster (\n id integer NOT NULL PRIMARY KEY,\n cluster_name character varying(250) NOT NULL,\n active boolean NOT NULL,\n created_on timestamp with time zone NOT NULL,\n created_by integer NOT NULL,\n updated_on timestamp with time zone NOT NULL,\n updated_by integer NOT NULL,\n server_url character varying(250),\n config json,\n prometheus_endpoint character varying(250),\n cd_argo_setup boolean DEFAULT false,\n p_username character varying(250),\n p_password character varying(250),\n p_tls_client_cert text,\n p_tls_client_key text\n);\n\n\nALTER TABLE public.cluster OWNER TO postgres;" + _, err := DB.Exec(query) + assert.Nil(tt, err) + if err != nil { + return + } + query = "-- Sequence and defined type for cluster_note\nCREATE SEQUENCE IF NOT EXISTS id_seq_cluster_note;\n\n-- Sequence and defined type for cluster_note_history\nCREATE SEQUENCE IF NOT EXISTS id_seq_cluster_note_history;\n\n-- cluster_note Table Definition\nCREATE TABLE IF NOT EXISTS public.cluster_note\n(\n \"id\" int4 NOT NULL DEFAULT nextval('id_seq_cluster_note'::regclass),\n \"cluster_id\" int4 NOT NULL,\n \"description\" TEXT NOT NULL,\n \"created_on\" timestamptz NOT NULL,\n \"created_by\" int4 NOT NULL,\n \"updated_on\" timestamptz,\n \"updated_by\" int4,\n PRIMARY KEY (\"id\")\n);\n\n-- add foreign key\nALTER TABLE \"public\".\"cluster_note\"\n ADD FOREIGN KEY (\"cluster_id\") REFERENCES \"public\".\"cluster\" (\"id\");\n\n-- cluster_note_history Table Definition\nCREATE TABLE IF NOT EXISTS public.cluster_note_history\n(\n \"id\" int4 NOT NULL DEFAULT nextval('id_seq_cluster_note_history'::regclass),\n \"note_id\" int4 NOT NULL,\n \"description\" TEXT NOT NULL,\n \"created_on\" timestamptz NOT NULL,\n \"created_by\" int4 NOT NULL,\n \"updated_on\" timestamptz,\n \"updated_by\" int4,\n PRIMARY KEY (\"id\")\n);\n\n-- add foreign key\nALTER TABLE \"public\".\"cluster_note_history\"\n ADD FOREIGN KEY (\"note_id\") REFERENCES \"public\".\"cluster_note\" (\"id\");" + _, err = DB.Exec(query) + assert.Nil(tt, err) + if err != nil { + return + } + query = "INSERT INTO public.cluster (\nid, cluster_name, active, created_on, created_by, updated_on, updated_by) VALUES (\n'1'::integer, 'test'::character varying, true::boolean, '2009-10-31T01:48:52Z '::timestamp with time zone, '1'::integer, '2009-10-31T01:48:52Z '::timestamp with time zone, '1'::integer)\n returning id;" + _, err = DB.Exec(query) + assert.Nil(tt, err) + if err != nil { + return + } + query = "INSERT INTO public.cluster (\nid, cluster_name, active, created_on, created_by, updated_on, updated_by) VALUES (\n'100'::integer, 'test-cluster'::character varying, true::boolean, '2009-10-31T01:48:52Z '::timestamp with time zone, '1'::integer, '2009-10-31T01:48:52Z '::timestamp with time zone, '1'::integer)\n returning id;" + _, err = DB.Exec(query) + assert.Nil(tt, err) + if err != nil { + return + } + +} + func InitClusterNoteService() { if clusterNoteService != nil { return @@ -139,6 +179,7 @@ func InitClusterNoteService() { clusterNoteHistoryRepository := repository.NewClusterNoteHistoryRepositoryImpl(conn, logger) clusterNoteRepository := repository.NewClusterNoteRepositoryImpl(conn, logger) + userRepository := repository2.NewUserRepositoryImpl(conn, logger) - clusterNoteService = NewClusterNoteServiceImpl(clusterNoteRepository, clusterNoteHistoryRepository, logger) + clusterNoteService = NewClusterNoteServiceImpl(clusterNoteRepository, clusterNoteHistoryRepository, userRepository, logger) } From 4065da9f800c2bc3817210fac195443e2aa3e615 Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Sun, 30 Apr 2023 15:54:20 +0530 Subject: [PATCH 14/19] updated and refactored --- api/cluster/ClusterRestHandler.go | 90 ++++++------ api/cluster/ClusterRouter.go | 2 +- api/cluster/wire_cluster.go | 16 ++- pkg/cluster/ClusterDescriptionService.go | 87 ++++++++++++ pkg/cluster/ClusterNoteHistoryService.go | 67 +++++++++ pkg/cluster/ClusterNoteService.go | 134 +++--------------- pkg/cluster/ClusterNoteService_test.go | 5 +- pkg/cluster/ClusterService.go | 4 - .../ClusterDescriptionRepository.go | 59 ++++++++ .../repository/ClusterNoteRepository.go | 18 +-- scripts/sql/133_alter_cluster_details.up.sql | 20 ++- wire_gen.go | 7 +- 12 files changed, 314 insertions(+), 195 deletions(-) create mode 100644 pkg/cluster/ClusterDescriptionService.go create mode 100644 pkg/cluster/ClusterNoteHistoryService.go create mode 100644 pkg/cluster/repository/ClusterDescriptionRepository.go diff --git a/api/cluster/ClusterRestHandler.go b/api/cluster/ClusterRestHandler.go index 53af1a8547..caf651d3bf 100644 --- a/api/cluster/ClusterRestHandler.go +++ b/api/cluster/ClusterRestHandler.go @@ -56,18 +56,20 @@ type ClusterRestHandler interface { } type ClusterRestHandlerImpl struct { - clusterService cluster.ClusterService - clusterNoteService cluster.ClusterNoteService - logger *zap.SugaredLogger - userService user.UserService - validator *validator.Validate - enforcer casbin.Enforcer - deleteService delete2.DeleteService - argoUserService argo.ArgoUserService + clusterService cluster.ClusterService + clusterNoteService cluster.ClusterNoteService + clusterDescriptionService cluster.ClusterDescriptionService + logger *zap.SugaredLogger + userService user.UserService + validator *validator.Validate + enforcer casbin.Enforcer + deleteService delete2.DeleteService + argoUserService argo.ArgoUserService } func NewClusterRestHandlerImpl(clusterService cluster.ClusterService, clusterNoteService cluster.ClusterNoteService, + clusterDescriptionService cluster.ClusterDescriptionService, logger *zap.SugaredLogger, userService user.UserService, validator *validator.Validate, @@ -75,14 +77,15 @@ func NewClusterRestHandlerImpl(clusterService cluster.ClusterService, deleteService delete2.DeleteService, argoUserService argo.ArgoUserService) *ClusterRestHandlerImpl { return &ClusterRestHandlerImpl{ - clusterService: clusterService, - clusterNoteService: clusterNoteService, - logger: logger, - userService: userService, - validator: validator, - enforcer: enforcer, - deleteService: deleteService, - argoUserService: argoUserService, + clusterService: clusterService, + clusterNoteService: clusterNoteService, + clusterDescriptionService: clusterDescriptionService, + logger: logger, + userService: userService, + validator: validator, + enforcer: enforcer, + deleteService: deleteService, + argoUserService: argoUserService, } } @@ -231,28 +234,13 @@ func (impl ClusterRestHandlerImpl) FindNoteByClusterId(w http.ResponseWriter, r return } //RBAC enforcer Ends - bean, err := impl.clusterNoteService.FindByClusterId(i) + bean, err := impl.clusterDescriptionService.FindByClusterIdWithClusterDetails(i) if err != nil { - if err == pg.ErrNoRows { - clusterDescriptionBean, userIdErr := impl.clusterNoteService.GenerateClusterDescription(bean, clusterBean, false) - if userIdErr != nil { - common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) - return - } - impl.logger.Errorw("cluster note not found, FindById", "err", err, "clusterId", id) - common.WriteJsonResp(w, nil, clusterDescriptionBean, http.StatusOK) - return - } impl.logger.Errorw("cluster note service err, FindById", "err", err, "clusterId", id) common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) return } - clusterDescriptionBean, userIdErr := impl.clusterNoteService.GenerateClusterDescription(bean, clusterBean, false) - if userIdErr != nil { - common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) - return - } - common.WriteJsonResp(w, err, clusterDescriptionBean, http.StatusOK) + common.WriteJsonResp(w, err, bean, http.StatusOK) } func (impl ClusterRestHandlerImpl) Update(w http.ResponseWriter, r *http.Request) { @@ -339,19 +327,14 @@ func (impl ClusterRestHandlerImpl) UpdateClusterNote(w http.ResponseWriter, r *h common.WriteJsonResp(w, err, nil, http.StatusBadRequest) return } - cluster, err := impl.clusterService.FindByIdWithoutConfig(bean.ClusterId) + clusterDescription, err := impl.clusterDescriptionService.FindByClusterIdWithClusterDetails(bean.ClusterId) if err != nil { - if err == pg.ErrNoRows { - impl.logger.Errorw("cluster id not found, FindById", "err", err, "clusterId", bean.ClusterId) - common.WriteJsonResp(w, errors.New("invalid cluster id"), nil, http.StatusNotFound) - return - } - impl.logger.Errorw("cluster service err, FindById", "err", err, "clusterId", bean.ClusterId) + impl.logger.Errorw("service err, FindById", "err", err, "clusterId", bean.ClusterId) common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) return } // RBAC enforcer applying - if ok := impl.enforcer.Enforce(token, casbin.ResourceCluster, casbin.ActionUpdate, strings.ToLower(cluster.ClusterName)); !ok { + if ok := impl.enforcer.Enforce(token, casbin.ResourceCluster, casbin.ActionUpdate, strings.ToLower(clusterDescription.ClusterName)); !ok { common.WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden) return } @@ -360,18 +343,35 @@ func (impl ClusterRestHandlerImpl) UpdateClusterNote(w http.ResponseWriter, r *h _, err = impl.clusterNoteService.Update(&bean, userId) if err == pg.ErrNoRows { _, err = impl.clusterNoteService.Save(&bean, userId) + if err != nil { + impl.logger.Errorw("service err, Save", "error", err, "payload", bean) + common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + return + } } if err != nil { - impl.logger.Errorw("cluster note service err, Update", "error", err, "payload", bean) + impl.logger.Errorw("service err, Update", "error", err, "payload", bean) + common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + return + } + userInfo, err := impl.userService.GetById(bean.UpdatedBy) + if err != nil { + impl.logger.Errorw("user service err, FindById", "err", err, "userId", bean.UpdatedBy) common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) return } - clusterDescriptionBean, userIdErr := impl.clusterNoteService.GenerateClusterDescription(&bean, cluster, true) - if userIdErr != nil { + clusterNoteResponseBean := &cluster.ClusterNoteResponseBean{ + Id: bean.Id, + Description: bean.Description, + UpdatedOn: bean.UpdatedOn, + UpdatedBy: userInfo.EmailId, + } + if err != nil { + impl.logger.Errorw("cluster note service err, Update", "error", err, "payload", bean) common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) return } - common.WriteJsonResp(w, err, clusterDescriptionBean, http.StatusOK) + common.WriteJsonResp(w, err, clusterNoteResponseBean, http.StatusOK) } func (impl ClusterRestHandlerImpl) FindAllForAutoComplete(w http.ResponseWriter, r *http.Request) { diff --git a/api/cluster/ClusterRouter.go b/api/cluster/ClusterRouter.go index a00751b0e8..c26f3e850e 100644 --- a/api/cluster/ClusterRouter.go +++ b/api/cluster/ClusterRouter.go @@ -58,7 +58,7 @@ func (impl ClusterRouterImpl) InitClusterRouter(clusterRouter *mux.Router) { Methods("PUT"). HandlerFunc(impl.clusterRestHandler.Update) - clusterRouter.Path("/description"). + clusterRouter.Path("/description/note"). Methods("PUT"). HandlerFunc(impl.clusterRestHandler.UpdateClusterNote) diff --git a/api/cluster/wire_cluster.go b/api/cluster/wire_cluster.go index 7d315140bb..30f86de636 100644 --- a/api/cluster/wire_cluster.go +++ b/api/cluster/wire_cluster.go @@ -14,12 +14,18 @@ var ClusterWireSet = wire.NewSet( cluster.NewClusterServiceImplExtended, wire.Bind(new(cluster.ClusterService), new(*cluster.ClusterServiceImplExtended)), + repository.NewClusterDescriptionRepositoryImpl, + wire.Bind(new(repository.ClusterDescriptionRepository), new(*repository.ClusterDescriptionRepositoryImpl)), repository.NewClusterNoteHistoryRepositoryImpl, wire.Bind(new(repository.ClusterNoteHistoryRepository), new(*repository.ClusterNoteHistoryRepositoryImpl)), repository.NewClusterNoteRepositoryImpl, wire.Bind(new(repository.ClusterNoteRepository), new(*repository.ClusterNoteRepositoryImpl)), + cluster.NewClusterNoteHistoryServiceImpl, + wire.Bind(new(cluster.ClusterNoteHistoryService), new(*cluster.ClusterNoteHistoryServiceImpl)), cluster.NewClusterNoteServiceImpl, wire.Bind(new(cluster.ClusterNoteService), new(*cluster.ClusterNoteServiceImpl)), + cluster.NewClusterDescriptionServiceImpl, + wire.Bind(new(cluster.ClusterDescriptionService), new(*cluster.ClusterDescriptionServiceImpl)), NewClusterRestHandlerImpl, wire.Bind(new(ClusterRestHandler), new(*ClusterRestHandlerImpl)), @@ -43,12 +49,18 @@ var ClusterWireSetEa = wire.NewSet( cluster.NewClusterServiceImpl, wire.Bind(new(cluster.ClusterService), new(*cluster.ClusterServiceImpl)), - repository.NewClusterNoteRepositoryImpl, - wire.Bind(new(repository.ClusterNoteRepository), new(*repository.ClusterNoteRepositoryImpl)), + repository.NewClusterDescriptionRepositoryImpl, + wire.Bind(new(repository.ClusterDescriptionRepository), new(*repository.ClusterDescriptionRepositoryImpl)), repository.NewClusterNoteHistoryRepositoryImpl, wire.Bind(new(repository.ClusterNoteHistoryRepository), new(*repository.ClusterNoteHistoryRepositoryImpl)), + repository.NewClusterNoteRepositoryImpl, + wire.Bind(new(repository.ClusterNoteRepository), new(*repository.ClusterNoteRepositoryImpl)), + cluster.NewClusterNoteHistoryServiceImpl, + wire.Bind(new(cluster.ClusterNoteHistoryService), new(*cluster.ClusterNoteHistoryServiceImpl)), cluster.NewClusterNoteServiceImpl, wire.Bind(new(cluster.ClusterNoteService), new(*cluster.ClusterNoteServiceImpl)), + cluster.NewClusterDescriptionServiceImpl, + wire.Bind(new(cluster.ClusterDescriptionService), new(*cluster.ClusterDescriptionServiceImpl)), NewClusterRestHandlerImpl, wire.Bind(new(ClusterRestHandler), new(*ClusterRestHandlerImpl)), diff --git a/pkg/cluster/ClusterDescriptionService.go b/pkg/cluster/ClusterDescriptionService.go new file mode 100644 index 0000000000..c80971703b --- /dev/null +++ b/pkg/cluster/ClusterDescriptionService.go @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2020 Devtron Labs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package cluster + +import ( + repository2 "github.com/devtron-labs/devtron/pkg/user/repository" + "time" + + "github.com/devtron-labs/devtron/pkg/cluster/repository" + "github.com/go-pg/pg" + "go.uber.org/zap" +) + +type ClusterDescriptionBean struct { + ClusterId int `json:"clusterId" validate:"number"` + ClusterName string `json:"clusterName" validate:"required"` + ClusterCreatedBy string `json:"clusterCreatedBy" validate:"number"` + ClusterCreatedOn time.Time `json:"clusterCreatedOn" validate:"required"` + ClusterNote *ClusterNoteResponseBean `json:"clusterNote,omitempty"` +} + +type ClusterDescriptionService interface { + FindByClusterIdWithClusterDetails(id int) (*ClusterDescriptionBean, error) +} + +type ClusterDescriptionServiceImpl struct { + clusterDescriptionRepository repository.ClusterDescriptionRepository + userRepository repository2.UserRepository + logger *zap.SugaredLogger +} + +func NewClusterDescriptionServiceImpl(repository repository.ClusterDescriptionRepository, userRepository repository2.UserRepository, logger *zap.SugaredLogger) *ClusterDescriptionServiceImpl { + clusterDescriptionService := &ClusterDescriptionServiceImpl{ + clusterDescriptionRepository: repository, + userRepository: userRepository, + logger: logger, + } + return clusterDescriptionService +} + +func (impl *ClusterDescriptionServiceImpl) FindByClusterIdWithClusterDetails(id int) (*ClusterDescriptionBean, error) { + model, err := impl.clusterDescriptionRepository.FindByClusterIdWithClusterDetails(id) + if err != nil { + return nil, err + } + clusterCreatedByUser, err := impl.userRepository.GetById(model.ClusterCreatedBy) + if err != nil { + impl.logger.Errorw("error in fetching user", "error", err) + return nil, err + } + noteUpdatedByUser, err := impl.userRepository.GetById(model.UpdatedBy) + if err != nil && err != pg.ErrNoRows { + impl.logger.Errorw("error in fetching user", "error", err) + return nil, err + } + bean := &ClusterDescriptionBean{ + ClusterId: model.ClusterId, + ClusterName: model.ClusterName, + ClusterCreatedBy: clusterCreatedByUser.EmailId, + ClusterCreatedOn: model.ClusterCreatedOn, + } + if model.NoteId > 0 { + clusterNote := &ClusterNoteResponseBean{ + Id: model.NoteId, + Description: model.Description, + UpdatedBy: noteUpdatedByUser.EmailId, + UpdatedOn: model.UpdatedOn, + } + bean.ClusterNote = clusterNote + } + return bean, nil +} diff --git a/pkg/cluster/ClusterNoteHistoryService.go b/pkg/cluster/ClusterNoteHistoryService.go new file mode 100644 index 0000000000..e341992b99 --- /dev/null +++ b/pkg/cluster/ClusterNoteHistoryService.go @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2020 Devtron Labs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package cluster + +import ( + "time" + + "github.com/devtron-labs/devtron/pkg/cluster/repository" + "go.uber.org/zap" +) + +type ClusterNoteHistoryBean struct { + Id int `json:"id" validate:"number"` + NoteId int `json:"noteId" validate:"required"` + Description string `json:"description" validate:"required"` + CreatedBy int `json:"createdBy"` + CreatedOn time.Time `json:"createdOn"` +} + +type ClusterNoteHistoryService interface { + Save(bean *ClusterNoteHistoryBean, userId int32) (*ClusterNoteHistoryBean, error) +} + +type ClusterNoteHistoryServiceImpl struct { + clusterNoteHistoryRepository repository.ClusterNoteHistoryRepository + logger *zap.SugaredLogger +} + +func NewClusterNoteHistoryServiceImpl(repositoryHistory repository.ClusterNoteHistoryRepository, logger *zap.SugaredLogger) *ClusterNoteHistoryServiceImpl { + clusterNoteHistoryService := &ClusterNoteHistoryServiceImpl{ + clusterNoteHistoryRepository: repositoryHistory, + logger: logger, + } + return clusterNoteHistoryService +} + +func (impl *ClusterNoteHistoryServiceImpl) Save(bean *ClusterNoteHistoryBean, userId int32) (*ClusterNoteHistoryBean, error) { + clusterAudit := &repository.ClusterNoteHistory{ + NoteId: bean.NoteId, + Description: bean.Description, + } + clusterAudit.CreatedBy = userId + clusterAudit.UpdatedBy = userId + clusterAudit.CreatedOn = time.Now() + clusterAudit.UpdatedOn = time.Now() + err := impl.clusterNoteHistoryRepository.SaveHistory(clusterAudit) + if err != nil { + impl.logger.Errorw("cluster note history save failed in db", "id", bean.NoteId) + return nil, err + } + return bean, err +} diff --git a/pkg/cluster/ClusterNoteService.go b/pkg/cluster/ClusterNoteService.go index cd1837969b..a2630ab370 100644 --- a/pkg/cluster/ClusterNoteService.go +++ b/pkg/cluster/ClusterNoteService.go @@ -24,90 +24,45 @@ import ( "github.com/devtron-labs/devtron/internal/constants" "github.com/devtron-labs/devtron/internal/util" "github.com/devtron-labs/devtron/pkg/cluster/repository" - repository2 "github.com/devtron-labs/devtron/pkg/user/repository" "github.com/go-pg/pg" "go.uber.org/zap" ) type ClusterNoteBean struct { Id int `json:"id" validate:"number"` - ClusterId int `json:"cluster_id" validate:"required"` + ClusterId int `json:"clusterId" validate:"required"` Description string `json:"description" validate:"required"` - UpdatedBy int `json:"updated_by"` - UpdatedOn time.Time `json:"updated_on"` + UpdatedBy int32 `json:"updatedBy"` + UpdatedOn time.Time `json:"updatedOn"` } -type ClusterDescriptionBean struct { - Id int `json:"id,omitempty"` - ClusterId int `json:"cluster_id"` - ClusterName string `json:"cluster_name"` - Description string `json:"description,omitempty"` - CreatedBy string `json:"updated_by,omitempty"` - CreatedOn *time.Time `json:"updated_on,omitempty"` - ClusterCreatedBy string `json:"cluster_created_by"` - ClusterCreatedOn *time.Time `json:"cluster_created_on"` -} - -type ClusterNoteHistoryBean struct { +type ClusterNoteResponseBean struct { Id int `json:"id" validate:"number"` - NoteId int `json:"note_id" validate:"required"` Description string `json:"description" validate:"required"` - CreatedBy int `json:"created_by"` - CreatedOn time.Time `json:"created_on"` + UpdatedBy string `json:"updatedBy"` + UpdatedOn time.Time `json:"updatedOn"` } type ClusterNoteService interface { Save(bean *ClusterNoteBean, userId int32) (*ClusterNoteBean, error) - FindByClusterId(id int) (*ClusterNoteBean, error) - FindByClusterIds(id []int) ([]*ClusterNoteBean, error) Update(bean *ClusterNoteBean, userId int32) (*ClusterNoteBean, error) - GenerateClusterDescription(bean *ClusterNoteBean, clusterBean *ClusterBean, isUpdate bool) (*ClusterDescriptionBean, error) } type ClusterNoteServiceImpl struct { - clusterNoteRepository repository.ClusterNoteRepository - clusterNoteHistoryRepository repository.ClusterNoteHistoryRepository - userRepository repository2.UserRepository - logger *zap.SugaredLogger + clusterNoteRepository repository.ClusterNoteRepository + clusterNoteHistoryService ClusterNoteHistoryService + logger *zap.SugaredLogger } -func NewClusterNoteServiceImpl(repository repository.ClusterNoteRepository, repositoryHistory repository.ClusterNoteHistoryRepository, userRepository repository2.UserRepository, logger *zap.SugaredLogger) *ClusterNoteServiceImpl { +func NewClusterNoteServiceImpl(repository repository.ClusterNoteRepository, clusterNoteHistoryService ClusterNoteHistoryService, logger *zap.SugaredLogger) *ClusterNoteServiceImpl { clusterNoteService := &ClusterNoteServiceImpl{ - clusterNoteRepository: repository, - clusterNoteHistoryRepository: repositoryHistory, - userRepository: userRepository, - logger: logger, + clusterNoteRepository: repository, + clusterNoteHistoryService: clusterNoteHistoryService, + logger: logger, } return clusterNoteService } -func (impl *ClusterNoteServiceImpl) GenerateClusterDescription(bean *ClusterNoteBean, clusterBean *ClusterBean, isUpdate bool) (*ClusterDescriptionBean, error) { - clusterDescription := &ClusterDescriptionBean{} - if !isUpdate { - userDetails, err := impl.userRepository.GetById(int32(clusterBean.CreatedBy)) - if err != nil { - impl.logger.Errorw("user service err, GetById", "err", err, "id", clusterBean.CreatedBy) - return nil, err - } - clusterDescription.ClusterCreatedOn = &clusterBean.CreatedOn - clusterDescription.ClusterCreatedBy = userDetails.EmailId - clusterDescription.ClusterId = clusterBean.Id - clusterDescription.ClusterName = clusterBean.ClusterName - } - if bean != nil { - userDetails, err := impl.userRepository.GetById(int32(bean.UpdatedBy)) - if err != nil { - impl.logger.Errorw("user service err, GetById", "err", err, "id", bean.UpdatedBy) - return nil, err - } - clusterDescription.Id = bean.Id - clusterDescription.Description = bean.Description - clusterDescription.CreatedOn = &bean.UpdatedOn - clusterDescription.CreatedBy = userDetails.EmailId - } - return clusterDescription, nil -} - func (impl *ClusterNoteServiceImpl) Save(bean *ClusterNoteBean, userId int32) (*ClusterNoteBean, error) { existingModel, err := impl.clusterNoteRepository.FindByClusterId(bean.ClusterId) if err != nil && err != pg.ErrNoRows { @@ -137,60 +92,20 @@ func (impl *ClusterNoteServiceImpl) Save(bean *ClusterNoteBean, userId int32) (* InternalMessage: "cluster note creation failed in db", UserMessage: fmt.Sprintf("requested by %d", userId), } + return nil, err } bean.Id = model.Id - bean.UpdatedBy = int(model.UpdatedBy) + bean.UpdatedBy = model.UpdatedBy bean.UpdatedOn = model.UpdatedOn // audit the existing description to cluster audit history - clusterAudit := &repository.ClusterNoteHistory{ + clusterAudit := &ClusterNoteHistoryBean{ NoteId: bean.Id, Description: bean.Description, } - clusterAudit.CreatedBy = userId - clusterAudit.UpdatedBy = userId - clusterAudit.CreatedOn = time.Now() - clusterAudit.UpdatedOn = time.Now() - err = impl.clusterNoteHistoryRepository.SaveHistory(clusterAudit) - if err != nil { - return nil, err - } + _, _ = impl.clusterNoteHistoryService.Save(clusterAudit, userId) return bean, err } -func (impl *ClusterNoteServiceImpl) FindByClusterId(id int) (*ClusterNoteBean, error) { - model, err := impl.clusterNoteRepository.FindByClusterId(id) - if err != nil { - return nil, err - } - bean := &ClusterNoteBean{ - Id: model.Id, - ClusterId: model.ClusterId, - Description: model.Description, - UpdatedBy: int(model.UpdatedBy), - UpdatedOn: model.UpdatedOn, - } - return bean, nil -} - -func (impl *ClusterNoteServiceImpl) FindByClusterIds(ids []int) ([]*ClusterNoteBean, error) { - models, err := impl.clusterNoteRepository.FindByClusterIds(ids) - if err != nil { - return nil, err - } - var beans []*ClusterNoteBean - - for _, model := range models { - beans = append(beans, &ClusterNoteBean{ - Id: model.Id, - ClusterId: model.ClusterId, - Description: model.Description, - UpdatedBy: int(model.CreatedBy), - UpdatedOn: model.CreatedOn, - }) - } - return beans, nil -} - func (impl *ClusterNoteServiceImpl) Update(bean *ClusterNoteBean, userId int32) (*ClusterNoteBean, error) { model, err := impl.clusterNoteRepository.FindByClusterId(bean.ClusterId) if err != nil { @@ -213,23 +128,16 @@ func (impl *ClusterNoteServiceImpl) Update(bean *ClusterNoteBean, userId int32) InternalMessage: "cluster note update failed in db", UserMessage: fmt.Sprintf("requested by %d", userId), } - return bean, err + return nil, err } bean.Id = model.Id - bean.UpdatedBy = int(model.UpdatedBy) + bean.UpdatedBy = model.UpdatedBy bean.UpdatedOn = model.UpdatedOn // audit the existing description to cluster audit history - clusterAudit := &repository.ClusterNoteHistory{ + clusterAudit := &ClusterNoteHistoryBean{ NoteId: bean.Id, Description: bean.Description, } - clusterAudit.CreatedBy = userId - clusterAudit.UpdatedBy = userId - clusterAudit.CreatedOn = time.Now() - clusterAudit.UpdatedOn = time.Now() - err = impl.clusterNoteHistoryRepository.SaveHistory(clusterAudit) - if err != nil { - return nil, err - } + _, _ = impl.clusterNoteHistoryService.Save(clusterAudit, userId) return bean, err } diff --git a/pkg/cluster/ClusterNoteService_test.go b/pkg/cluster/ClusterNoteService_test.go index d22572c24a..98816cbc13 100644 --- a/pkg/cluster/ClusterNoteService_test.go +++ b/pkg/cluster/ClusterNoteService_test.go @@ -8,7 +8,6 @@ import ( "github.com/caarlos0/env" "github.com/devtron-labs/devtron/internal/util" "github.com/devtron-labs/devtron/pkg/cluster/repository" - repository2 "github.com/devtron-labs/devtron/pkg/user/repository" "github.com/go-pg/pg" "github.com/stretchr/testify/assert" ) @@ -179,7 +178,7 @@ func InitClusterNoteService() { clusterNoteHistoryRepository := repository.NewClusterNoteHistoryRepositoryImpl(conn, logger) clusterNoteRepository := repository.NewClusterNoteRepositoryImpl(conn, logger) - userRepository := repository2.NewUserRepositoryImpl(conn, logger) + clusterNoteHistoryService := NewClusterNoteHistoryServiceImpl(clusterNoteHistoryRepository, logger) - clusterNoteService = NewClusterNoteServiceImpl(clusterNoteRepository, clusterNoteHistoryRepository, userRepository, logger) + clusterNoteService = NewClusterNoteServiceImpl(clusterNoteRepository, clusterNoteHistoryService, logger) } diff --git a/pkg/cluster/ClusterService.go b/pkg/cluster/ClusterService.go index ebd3e646c4..c9cee9799a 100644 --- a/pkg/cluster/ClusterService.go +++ b/pkg/cluster/ClusterService.go @@ -69,8 +69,6 @@ type ClusterBean struct { HasConfigOrUrlChanged bool `json:"-"` ErrorInConnecting string `json:"errorInConnecting,omitempty"` IsCdArgoSetup bool `json:"isCdArgoSetup"` - CreatedBy int `json:"cluster_created_by"` - CreatedOn time.Time `json:"cluster_created_on"` } type PrometheusAuth struct { @@ -372,8 +370,6 @@ func (impl *ClusterServiceImpl) FindById(id int) (*ClusterBean, error) { Active: model.Active, Config: model.Config, K8sVersion: model.K8sVersion, - CreatedOn: model.CreatedOn, - CreatedBy: int(model.CreatedBy), } prometheusAuth := &PrometheusAuth{ UserName: model.PUserName, diff --git a/pkg/cluster/repository/ClusterDescriptionRepository.go b/pkg/cluster/repository/ClusterDescriptionRepository.go new file mode 100644 index 0000000000..0267bd57dc --- /dev/null +++ b/pkg/cluster/repository/ClusterDescriptionRepository.go @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020 Devtron Labs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package repository + +import ( + "fmt" + "github.com/devtron-labs/devtron/pkg/sql" + "github.com/go-pg/pg" + "go.uber.org/zap" + "time" +) + +type ClusterDescription struct { + ClusterId int `sql:"cluster_id"` + ClusterName string `sql:"cluster_name"` + ClusterCreatedOn time.Time `sql:"cluster_created_on"` + ClusterCreatedBy int32 `sql:"cluster_created_by"` + NoteId int `sql:"note_id,pk"` + Description string `sql:"description"` + sql.AuditLog +} + +type ClusterDescriptionRepository interface { + FindByClusterIdWithClusterDetails(id int) (*ClusterDescription, error) +} + +func NewClusterDescriptionRepositoryImpl(dbConnection *pg.DB, logger *zap.SugaredLogger) *ClusterDescriptionRepositoryImpl { + return &ClusterDescriptionRepositoryImpl{ + dbConnection: dbConnection, + logger: logger, + } +} + +type ClusterDescriptionRepositoryImpl struct { + dbConnection *pg.DB + logger *zap.SugaredLogger +} + +func (impl ClusterDescriptionRepositoryImpl) FindByClusterIdWithClusterDetails(id int) (*ClusterDescription, error) { + clusterDescription := &ClusterDescription{} + query := fmt.Sprintf("select cl.id as cluster_id, cl.cluster_name as cluster_name, cl.created_on as cluster_created_on, cl.created_by as cluster_created_by, cln.id as note_id, cln.description, cln.created_by, cln.created_on, cln.updated_by, cln.updated_on from cluster cl left join cluster_note cln on cl.id=cln.cluster_id where cl.id=%d and cl.active=true limit 1 offset 0;", id) + _, err := impl.dbConnection.Query(clusterDescription, query) + return clusterDescription, err +} diff --git a/pkg/cluster/repository/ClusterNoteRepository.go b/pkg/cluster/repository/ClusterNoteRepository.go index c33c348800..e9c8726204 100644 --- a/pkg/cluster/repository/ClusterNoteRepository.go +++ b/pkg/cluster/repository/ClusterNoteRepository.go @@ -24,17 +24,16 @@ import ( ) type ClusterNote struct { - tableName struct{} `sql:"cluster_note" pg:",discard_unknown_columns"` - Id int `sql:"id,pk"` - ClusterId int `sql:"cluster_id"` - Description string `sql:"description"` + tableName struct{} `sql:"cluster_note" pg:",discard_unknown_columns"` + Id int `sql:"id,pk"` + ClusterId int `sql:"cluster_id"` + Description string `sql:"description"` sql.AuditLog } type ClusterNoteRepository interface { Save(model *ClusterNote) error FindByClusterId(id int) (*ClusterNote, error) - FindByClusterIds(id []int) ([]*ClusterNote, error) Update(model *ClusterNote) error } @@ -64,15 +63,6 @@ func (impl ClusterNoteRepositoryImpl) FindByClusterId(id int) (*ClusterNote, err return clusterNote, err } -func (impl ClusterNoteRepositoryImpl) FindByClusterIds(ids []int) ([]*ClusterNote, error) { - var clusterNotes []*ClusterNote - err := impl.dbConnection. - Model(&clusterNotes). - Where("cluster_id in(?)", pg.In(ids)). - Select() - return clusterNotes, err -} - func (impl ClusterNoteRepositoryImpl) Update(model *ClusterNote) error { return impl.dbConnection.Update(model) } diff --git a/scripts/sql/133_alter_cluster_details.up.sql b/scripts/sql/133_alter_cluster_details.up.sql index 78b01f0fb0..b68ec14e20 100644 --- a/scripts/sql/133_alter_cluster_details.up.sql +++ b/scripts/sql/133_alter_cluster_details.up.sql @@ -14,13 +14,12 @@ CREATE TABLE IF NOT EXISTS public.cluster_note "created_by" int4 NOT NULL, "updated_on" timestamptz, "updated_by" int4, - PRIMARY KEY ("id") + PRIMARY KEY ("id"), + CONSTRAINT cluster_note_cluster_id_fkey + FOREIGN KEY(cluster_id) + REFERENCES public.cluster(id) ); --- add foreign key -ALTER TABLE "public"."cluster_note" - ADD FOREIGN KEY ("cluster_id") REFERENCES "public"."cluster" ("id"); - -- cluster_note_history Table Definition CREATE TABLE IF NOT EXISTS public.cluster_note_history ( @@ -31,9 +30,8 @@ CREATE TABLE IF NOT EXISTS public.cluster_note_history "created_by" int4 NOT NULL, "updated_on" timestamptz, "updated_by" int4, - PRIMARY KEY ("id") -); - --- add foreign key -ALTER TABLE "public"."cluster_note_history" - ADD FOREIGN KEY ("note_id") REFERENCES "public"."cluster_note" ("id"); \ No newline at end of file + PRIMARY KEY ("id"), + CONSTRAINT cluster_note_history_cluster_note_id_fkey + FOREIGN KEY(note_id) + REFERENCES public.cluster_note(id) +); \ No newline at end of file diff --git a/wire_gen.go b/wire_gen.go index b36268139d..440e833b18 100644 --- a/wire_gen.go +++ b/wire_gen.go @@ -470,8 +470,11 @@ func InitializeApp() (*App, error) { environmentRouterImpl := cluster3.NewEnvironmentRouterImpl(environmentRestHandlerImpl) clusterNoteRepositoryImpl := repository2.NewClusterNoteRepositoryImpl(db, sugaredLogger) clusterNoteHistoryRepositoryImpl := repository2.NewClusterNoteHistoryRepositoryImpl(db, sugaredLogger) - clusterNoteServiceImpl := cluster2.NewClusterNoteServiceImpl(clusterNoteRepositoryImpl, clusterNoteHistoryRepositoryImpl, userRepositoryImpl, sugaredLogger) - clusterRestHandlerImpl := cluster3.NewClusterRestHandlerImpl(clusterServiceImplExtended, clusterNoteServiceImpl, sugaredLogger, userServiceImpl, validate, enforcerImpl, deleteServiceExtendedImpl, argoUserServiceImpl) + clusterNoteHistoryServiceImpl := cluster2.NewClusterNoteHistoryServiceImpl(clusterNoteHistoryRepositoryImpl, sugaredLogger) + clusterNoteServiceImpl := cluster2.NewClusterNoteServiceImpl(clusterNoteRepositoryImpl, clusterNoteHistoryServiceImpl, sugaredLogger) + clusterDescriptionRepositoryImpl := repository2.NewClusterDescriptionRepositoryImpl(db, sugaredLogger) + clusterDescriptionServiceImpl := cluster2.NewClusterDescriptionServiceImpl(clusterDescriptionRepositoryImpl, userRepositoryImpl, sugaredLogger) + clusterRestHandlerImpl := cluster3.NewClusterRestHandlerImpl(clusterServiceImplExtended, clusterNoteServiceImpl, clusterDescriptionServiceImpl, sugaredLogger, userServiceImpl, validate, enforcerImpl, deleteServiceExtendedImpl, argoUserServiceImpl) clusterRouterImpl := cluster3.NewClusterRouterImpl(clusterRestHandlerImpl) gitWebhookRepositoryImpl := repository.NewGitWebhookRepositoryImpl(db) gitWebhookServiceImpl := git.NewGitWebhookServiceImpl(sugaredLogger, ciHandlerImpl, gitWebhookRepositoryImpl) From f04e98201846308c6aac63f190d37a78656592ba Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Mon, 1 May 2023 01:49:01 +0530 Subject: [PATCH 15/19] updated intigration test --- pkg/cluster/ClusterNoteService_test.go | 141 ++++++++++++++++++++----- 1 file changed, 117 insertions(+), 24 deletions(-) diff --git a/pkg/cluster/ClusterNoteService_test.go b/pkg/cluster/ClusterNoteService_test.go index 98816cbc13..f747f6095c 100644 --- a/pkg/cluster/ClusterNoteService_test.go +++ b/pkg/cluster/ClusterNoteService_test.go @@ -37,7 +37,7 @@ func TestClusterNoteService_Save(t *testing.T) { name: "TEST : successfully save the note", input: &ClusterNoteBean{ Id: 0, - ClusterId: 1, + ClusterId: 10000, Description: "Test Note", UpdatedBy: 1, UpdatedOn: time.Now(), @@ -48,7 +48,7 @@ func TestClusterNoteService_Save(t *testing.T) { name: "TEST : error while saving the existing note", input: &ClusterNoteBean{ Id: 0, - ClusterId: 1, + ClusterId: 10000, Description: "Test Note", UpdatedBy: 1, UpdatedOn: time.Now(), @@ -79,7 +79,7 @@ func TestClusterNoteServiceImpl_Update_InvalidFields(t *testing.T) { initialiseDb(t) // insert a cluster note in the database which will be updated later note := &ClusterNoteBean{ - ClusterId: 100, + ClusterId: 10001, Description: "test note", UpdatedBy: 1, } @@ -89,16 +89,41 @@ func TestClusterNoteServiceImpl_Update_InvalidFields(t *testing.T) { } // define input for update function - input := &ClusterNoteBean{ - Id: 1, - ClusterId: 100, + testCases := []struct { + name string + input *ClusterNoteBean + expectedErr bool + }{ + { + name: "TEST : error while updating the existing note", + input: &ClusterNoteBean{ + Id: 1, + ClusterId: 100, + }, + expectedErr: true, + }, + { + name: "TEST : successfully update the note", + input: &ClusterNoteBean{ + Description: "Updated Text", + ClusterId: 10001, + }, + expectedErr: false, + }, } - // try updating the record with invalid fields and check if it returns error - _, err = clusterNoteService.Update(input, 1) - if err == nil { - t.Fatal("Expected an error on updating record with invalid fields, but got nil") + for _, tc := range testCases { + t.Run(tc.name, func(tt *testing.T) { + res, err := clusterNoteService.Update(tc.input, 1) + if tc.expectedErr { + assert.NotNil(tt, err) + } else { + assert.Nil(tt, err) + assert.NotEqual(tt, res.Id, 0) + } + }) } + //clean data in db cleanDb(t) } @@ -134,33 +159,102 @@ func cleanDb(tt *testing.T) { } } +func createClusterData(DB *pg.DB, bean *ClusterBean) error { + model := &repository.Cluster{ + Id: bean.Id, + ClusterName: bean.ClusterName, + ServerUrl: bean.ServerUrl, + } + model.CreatedBy = 1 + model.UpdatedBy = 1 + model.CreatedOn = time.Now() + model.UpdatedOn = time.Now() + return DB.Insert(model) +} + func initialiseDb(tt *testing.T) { DB, _ := getDbConn() - query := "CREATE TABLE IF NOT EXISTS public.cluster (\n id integer NOT NULL PRIMARY KEY,\n cluster_name character varying(250) NOT NULL,\n active boolean NOT NULL,\n created_on timestamp with time zone NOT NULL,\n created_by integer NOT NULL,\n updated_on timestamp with time zone NOT NULL,\n updated_by integer NOT NULL,\n server_url character varying(250),\n config json,\n prometheus_endpoint character varying(250),\n cd_argo_setup boolean DEFAULT false,\n p_username character varying(250),\n p_password character varying(250),\n p_tls_client_cert text,\n p_tls_client_key text\n);\n\n\nALTER TABLE public.cluster OWNER TO postgres;" + query := "CREATE TABLE IF NOT EXISTS public.cluster (\n" + + " id integer NOT NULL PRIMARY KEY,\n" + + " cluster_name character varying(250) NOT NULL,\n" + + " active boolean NOT NULL,\n" + + " created_on timestamp with time zone NOT NULL,\n" + + " created_by integer NOT NULL,\n" + + " updated_on timestamp with time zone NOT NULL,\n" + + " updated_by integer NOT NULL,\n" + + " server_url character varying(250),\n" + + " config json,\n" + + " prometheus_endpoint character varying(250),\n" + + " cd_argo_setup boolean DEFAULT false,\n " + + " p_username character varying(250),\n" + + " p_password character varying(250),\n" + + " p_tls_client_cert text,\n" + + " p_tls_client_key text,\n" + + " agent_installation_stage int4 DEFAULT 0,\n" + + " error_in_connecting TEXT,\n" + + " k8s_version varchar(250)\n" + + ");\n\n\n" + + "ALTER TABLE public.cluster OWNER TO postgres;" _, err := DB.Exec(query) assert.Nil(tt, err) if err != nil { return } - query = "-- Sequence and defined type for cluster_note\nCREATE SEQUENCE IF NOT EXISTS id_seq_cluster_note;\n\n-- Sequence and defined type for cluster_note_history\nCREATE SEQUENCE IF NOT EXISTS id_seq_cluster_note_history;\n\n-- cluster_note Table Definition\nCREATE TABLE IF NOT EXISTS public.cluster_note\n(\n \"id\" int4 NOT NULL DEFAULT nextval('id_seq_cluster_note'::regclass),\n \"cluster_id\" int4 NOT NULL,\n \"description\" TEXT NOT NULL,\n \"created_on\" timestamptz NOT NULL,\n \"created_by\" int4 NOT NULL,\n \"updated_on\" timestamptz,\n \"updated_by\" int4,\n PRIMARY KEY (\"id\")\n);\n\n-- add foreign key\nALTER TABLE \"public\".\"cluster_note\"\n ADD FOREIGN KEY (\"cluster_id\") REFERENCES \"public\".\"cluster\" (\"id\");\n\n-- cluster_note_history Table Definition\nCREATE TABLE IF NOT EXISTS public.cluster_note_history\n(\n \"id\" int4 NOT NULL DEFAULT nextval('id_seq_cluster_note_history'::regclass),\n \"note_id\" int4 NOT NULL,\n \"description\" TEXT NOT NULL,\n \"created_on\" timestamptz NOT NULL,\n \"created_by\" int4 NOT NULL,\n \"updated_on\" timestamptz,\n \"updated_by\" int4,\n PRIMARY KEY (\"id\")\n);\n\n-- add foreign key\nALTER TABLE \"public\".\"cluster_note_history\"\n ADD FOREIGN KEY (\"note_id\") REFERENCES \"public\".\"cluster_note\" (\"id\");" + query = "-- Sequence and defined type for cluster_note\n" + + "CREATE SEQUENCE IF NOT EXISTS id_seq_cluster_note;\n\n" + + "-- Sequence and defined type for cluster_note_history\n" + + "CREATE SEQUENCE IF NOT EXISTS id_seq_cluster_note_history;\n\n" + + "-- cluster_note Table Definition\n" + + "CREATE TABLE IF NOT EXISTS public.cluster_note\n(\n" + + " \"id\" int4 NOT NULL DEFAULT nextval('id_seq_cluster_note'::regclass),\n" + + " \"cluster_id\" int4 NOT NULL,\n" + + " \"description\" TEXT NOT NULL,\n" + + " \"created_on\" timestamptz NOT NULL,\n" + + " \"created_by\" int4 NOT NULL,\n" + + " \"updated_on\" timestamptz,\n" + + " \"updated_by\" int4,\n" + + " PRIMARY KEY (\"id\")\n);\n\n" + + "-- add foreign key\n" + + "ALTER TABLE \"public\".\"cluster_note\"\n" + + " ADD FOREIGN KEY (\"cluster_id\") REFERENCES \"public\".\"cluster\" (\"id\");\n\n" + + "-- cluster_note_history Table Definition\n" + + "CREATE TABLE IF NOT EXISTS public.cluster_note_history\n" + + "(\n" + + " \"id\" int4 NOT NULL DEFAULT nextval('id_seq_cluster_note_history'::regclass),\n" + + " \"note_id\" int4 NOT NULL,\n" + + " \"description\" TEXT NOT NULL,\n" + + " \"created_on\" timestamptz NOT NULL,\n" + + " \"created_by\" int4 NOT NULL,\n" + + " \"updated_on\" timestamptz,\n" + + " \"updated_by\" int4,\n" + + " PRIMARY KEY (\"id\")\n);\n\n" + + "-- add foreign key\n" + + "ALTER TABLE \"public\".\"cluster_note_history\"\n" + + " ADD FOREIGN KEY (\"note_id\") REFERENCES \"public\".\"cluster_note\" (\"id\");" _, err = DB.Exec(query) assert.Nil(tt, err) if err != nil { return } - query = "INSERT INTO public.cluster (\nid, cluster_name, active, created_on, created_by, updated_on, updated_by) VALUES (\n'1'::integer, 'test'::character varying, true::boolean, '2009-10-31T01:48:52Z '::timestamp with time zone, '1'::integer, '2009-10-31T01:48:52Z '::timestamp with time zone, '1'::integer)\n returning id;" - _, err = DB.Exec(query) - assert.Nil(tt, err) - if err != nil { - return + clusters := []ClusterBean{ + { + Id: 10000, + ClusterName: "test-cluster-1", + ServerUrl: "https://test1.cluster", + }, + { + Id: 10001, + ClusterName: "test-cluster-2", + ServerUrl: "https://test2.cluster", + }, } - query = "INSERT INTO public.cluster (\nid, cluster_name, active, created_on, created_by, updated_on, updated_by) VALUES (\n'100'::integer, 'test-cluster'::character varying, true::boolean, '2009-10-31T01:48:52Z '::timestamp with time zone, '1'::integer, '2009-10-31T01:48:52Z '::timestamp with time zone, '1'::integer)\n returning id;" - _, err = DB.Exec(query) - assert.Nil(tt, err) - if err != nil { - return + for _, cluster := range clusters { + err = createClusterData(DB, &cluster) + assert.Nil(tt, err) + if err != nil { + return + } } - } func InitClusterNoteService() { @@ -179,6 +273,5 @@ func InitClusterNoteService() { clusterNoteHistoryRepository := repository.NewClusterNoteHistoryRepositoryImpl(conn, logger) clusterNoteRepository := repository.NewClusterNoteRepositoryImpl(conn, logger) clusterNoteHistoryService := NewClusterNoteHistoryServiceImpl(clusterNoteHistoryRepository, logger) - clusterNoteService = NewClusterNoteServiceImpl(clusterNoteRepository, clusterNoteHistoryService, logger) } From 3de0ed75757aa101bb1f842d92571441350bf291 Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Mon, 1 May 2023 11:58:51 +0530 Subject: [PATCH 16/19] updated wire_gen --- cmd/external-app/wire_gen.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cmd/external-app/wire_gen.go b/cmd/external-app/wire_gen.go index f7635c593a..b6d8ae48c2 100644 --- a/cmd/external-app/wire_gen.go +++ b/cmd/external-app/wire_gen.go @@ -177,11 +177,17 @@ func InitializeApp() (*App, error) { roleGroupServiceImpl := user.NewRoleGroupServiceImpl(userAuthRepositoryImpl, sugaredLogger, userRepositoryImpl, roleGroupRepositoryImpl, userCommonServiceImpl) userRestHandlerImpl := user2.NewUserRestHandlerImpl(userServiceImpl, validate, sugaredLogger, enforcerImpl, roleGroupServiceImpl, userCommonServiceImpl) userRouterImpl := user2.NewUserRouterImpl(userRestHandlerImpl) + clusterNoteRepositoryImpl := repository2.NewClusterNoteRepositoryImpl(db, sugaredLogger) + clusterNoteHistoryRepositoryImpl := repository2.NewClusterNoteHistoryRepositoryImpl(db, sugaredLogger) + clusterNoteHistoryServiceImpl := cluster.NewClusterNoteHistoryServiceImpl(clusterNoteHistoryRepositoryImpl, sugaredLogger) + clusterNoteServiceImpl := cluster.NewClusterNoteServiceImpl(clusterNoteRepositoryImpl, clusterNoteHistoryServiceImpl, sugaredLogger) + clusterDescriptionRepositoryImpl := repository2.NewClusterDescriptionRepositoryImpl(db, sugaredLogger) + clusterDescriptionServiceImpl := cluster.NewClusterDescriptionServiceImpl(clusterDescriptionRepositoryImpl, userRepositoryImpl, sugaredLogger) helmUserServiceImpl, err := argo.NewHelmUserServiceImpl(sugaredLogger) if err != nil { return nil, err } - clusterRestHandlerImpl := cluster2.NewClusterRestHandlerImpl(clusterServiceImpl, sugaredLogger, userServiceImpl, validate, enforcerImpl, deleteServiceImpl, helmUserServiceImpl) + clusterRestHandlerImpl := cluster2.NewClusterRestHandlerImpl(clusterServiceImpl, clusterNoteServiceImpl, clusterDescriptionServiceImpl, sugaredLogger, userServiceImpl, validate, enforcerImpl, deleteServiceImpl, helmUserServiceImpl) clusterRouterImpl := cluster2.NewClusterRouterImpl(clusterRestHandlerImpl) dashboardConfig, err := dashboard.GetConfig() if err != nil { From cc183f3ace4f4a77c3116b4f7729a43e1cb7fbce Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Mon, 1 May 2023 12:37:58 +0530 Subject: [PATCH 17/19] updated integration test case --- pkg/cluster/ClusterNoteService_test.go | 76 +++----------------------- 1 file changed, 8 insertions(+), 68 deletions(-) diff --git a/pkg/cluster/ClusterNoteService_test.go b/pkg/cluster/ClusterNoteService_test.go index f747f6095c..1a86979795 100644 --- a/pkg/cluster/ClusterNoteService_test.go +++ b/pkg/cluster/ClusterNoteService_test.go @@ -17,7 +17,7 @@ type Config struct { Port string `env:"TEST_PG_PORT" envDefault:"5432"` User string `env:"TEST_PG_USER" envDefault:"postgres"` Password string `env:"TEST_PG_PASSWORD" envDefault:"postgrespw" secretData:"-"` - Database string `env:"TEST_PG_DATABASE" envDefault:"postgres"` + Database string `env:"TEST_PG_DATABASE" envDefault:"orchestrator"` LogQuery bool `env:"TEST_PG_LOG_QUERY" envDefault:"true"` } @@ -72,7 +72,7 @@ func TestClusterNoteService_Save(t *testing.T) { cleanDb(t) } -func TestClusterNoteServiceImpl_Update_InvalidFields(t *testing.T) { +func TestClusterNoteServiceImpl_Update(t *testing.T) { if clusterNoteService == nil { InitClusterNoteService() } @@ -145,13 +145,15 @@ func getDbConn() (*pg.DB, error) { Password: cfg.Password, Database: cfg.Database, } - dbConnection := pg.Connect(&options) - return dbConnection, nil + db = pg.Connect(&options) + return db, nil } func cleanDb(tt *testing.T) { DB, _ := getDbConn() - query := "truncate cluster cascade;" + query := "DELETE FROM cluster_note_history WHERE note_id IN (SELECT id FROM cluster_note);\n" + + "DELETE FROM cluster_note WHERE cluster_id IN (SELECT id FROM cluster);\n" + + "DELETE FROM cluster WHERE id=10000 OR id=10001;\n" _, err := DB.Exec(query) assert.Nil(tt, err) if err != nil { @@ -174,68 +176,6 @@ func createClusterData(DB *pg.DB, bean *ClusterBean) error { func initialiseDb(tt *testing.T) { DB, _ := getDbConn() - query := "CREATE TABLE IF NOT EXISTS public.cluster (\n" + - " id integer NOT NULL PRIMARY KEY,\n" + - " cluster_name character varying(250) NOT NULL,\n" + - " active boolean NOT NULL,\n" + - " created_on timestamp with time zone NOT NULL,\n" + - " created_by integer NOT NULL,\n" + - " updated_on timestamp with time zone NOT NULL,\n" + - " updated_by integer NOT NULL,\n" + - " server_url character varying(250),\n" + - " config json,\n" + - " prometheus_endpoint character varying(250),\n" + - " cd_argo_setup boolean DEFAULT false,\n " + - " p_username character varying(250),\n" + - " p_password character varying(250),\n" + - " p_tls_client_cert text,\n" + - " p_tls_client_key text,\n" + - " agent_installation_stage int4 DEFAULT 0,\n" + - " error_in_connecting TEXT,\n" + - " k8s_version varchar(250)\n" + - ");\n\n\n" + - "ALTER TABLE public.cluster OWNER TO postgres;" - _, err := DB.Exec(query) - assert.Nil(tt, err) - if err != nil { - return - } - query = "-- Sequence and defined type for cluster_note\n" + - "CREATE SEQUENCE IF NOT EXISTS id_seq_cluster_note;\n\n" + - "-- Sequence and defined type for cluster_note_history\n" + - "CREATE SEQUENCE IF NOT EXISTS id_seq_cluster_note_history;\n\n" + - "-- cluster_note Table Definition\n" + - "CREATE TABLE IF NOT EXISTS public.cluster_note\n(\n" + - " \"id\" int4 NOT NULL DEFAULT nextval('id_seq_cluster_note'::regclass),\n" + - " \"cluster_id\" int4 NOT NULL,\n" + - " \"description\" TEXT NOT NULL,\n" + - " \"created_on\" timestamptz NOT NULL,\n" + - " \"created_by\" int4 NOT NULL,\n" + - " \"updated_on\" timestamptz,\n" + - " \"updated_by\" int4,\n" + - " PRIMARY KEY (\"id\")\n);\n\n" + - "-- add foreign key\n" + - "ALTER TABLE \"public\".\"cluster_note\"\n" + - " ADD FOREIGN KEY (\"cluster_id\") REFERENCES \"public\".\"cluster\" (\"id\");\n\n" + - "-- cluster_note_history Table Definition\n" + - "CREATE TABLE IF NOT EXISTS public.cluster_note_history\n" + - "(\n" + - " \"id\" int4 NOT NULL DEFAULT nextval('id_seq_cluster_note_history'::regclass),\n" + - " \"note_id\" int4 NOT NULL,\n" + - " \"description\" TEXT NOT NULL,\n" + - " \"created_on\" timestamptz NOT NULL,\n" + - " \"created_by\" int4 NOT NULL,\n" + - " \"updated_on\" timestamptz,\n" + - " \"updated_by\" int4,\n" + - " PRIMARY KEY (\"id\")\n);\n\n" + - "-- add foreign key\n" + - "ALTER TABLE \"public\".\"cluster_note_history\"\n" + - " ADD FOREIGN KEY (\"note_id\") REFERENCES \"public\".\"cluster_note\" (\"id\");" - _, err = DB.Exec(query) - assert.Nil(tt, err) - if err != nil { - return - } clusters := []ClusterBean{ { Id: 10000, @@ -249,7 +189,7 @@ func initialiseDb(tt *testing.T) { }, } for _, cluster := range clusters { - err = createClusterData(DB, &cluster) + err := createClusterData(DB, &cluster) assert.Nil(tt, err) if err != nil { return From 2da511ad19f686c92f1feacbc133ef7785c1128d Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Mon, 1 May 2023 17:38:21 +0530 Subject: [PATCH 18/19] updated Rbac and audit save bug --- api/cluster/ClusterRestHandler.go | 66 +++++++++++++++++++----- cmd/external-app/wire_gen.go | 2 +- pkg/cluster/ClusterNoteHistoryService.go | 8 +-- pkg/cluster/ClusterNoteService.go | 4 ++ wire_gen.go | 2 +- 5 files changed, 64 insertions(+), 18 deletions(-) diff --git a/api/cluster/ClusterRestHandler.go b/api/cluster/ClusterRestHandler.go index caf651d3bf..ae54088a9e 100644 --- a/api/cluster/ClusterRestHandler.go +++ b/api/cluster/ClusterRestHandler.go @@ -65,6 +65,7 @@ type ClusterRestHandlerImpl struct { enforcer casbin.Enforcer deleteService delete2.DeleteService argoUserService argo.ArgoUserService + environmentService cluster.EnvironmentService } func NewClusterRestHandlerImpl(clusterService cluster.ClusterService, @@ -75,7 +76,8 @@ func NewClusterRestHandlerImpl(clusterService cluster.ClusterService, validator *validator.Validate, enforcer casbin.Enforcer, deleteService delete2.DeleteService, - argoUserService argo.ArgoUserService) *ClusterRestHandlerImpl { + argoUserService argo.ArgoUserService, + environmentService cluster.EnvironmentService) *ClusterRestHandlerImpl { return &ClusterRestHandlerImpl{ clusterService: clusterService, clusterNoteService: clusterNoteService, @@ -86,6 +88,7 @@ func NewClusterRestHandlerImpl(clusterService cluster.ClusterService, enforcer: enforcer, deleteService: deleteService, argoUserService: argoUserService, + environmentService: environmentService, } } @@ -215,31 +218,30 @@ func (impl ClusterRestHandlerImpl) FindNoteByClusterId(w http.ResponseWriter, r common.WriteJsonResp(w, err, nil, http.StatusBadRequest) return } - - clusterBean, err := impl.clusterService.FindByIdWithoutConfig(i) + bean, err := impl.clusterDescriptionService.FindByClusterIdWithClusterDetails(i) if err != nil { if err == pg.ErrNoRows { - impl.logger.Errorw("cluster id not found, FindById", "err", err, "clusterId", i) + impl.logger.Errorw("cluster not found, FindById", "err", err, "clusterId", id) common.WriteJsonResp(w, errors.New("invalid cluster id"), nil, http.StatusNotFound) return } - impl.logger.Errorw("cluster service err, FindById", "err", err, "clusterId", i) + impl.logger.Errorw("service err, FindById", "err", err, "clusterId", id) common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) return } // RBAC enforcer applying token := r.Header.Get("token") - if ok := impl.enforcer.Enforce(token, casbin.ResourceCluster, casbin.ActionGet, strings.ToLower(clusterBean.ClusterName)); !ok { - common.WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden) - return - } - //RBAC enforcer Ends - bean, err := impl.clusterDescriptionService.FindByClusterIdWithClusterDetails(i) + authenticated, err := impl.CheckRbacForClusterDetails(bean.ClusterId, token) if err != nil { - impl.logger.Errorw("cluster note service err, FindById", "err", err, "clusterId", id) + impl.logger.Errorw("error in checking rbac for cluster", "err", err, "clusterId", bean.ClusterId) common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) return } + if !authenticated { + common.WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden) + return + } + //RBAC enforcer Ends common.WriteJsonResp(w, err, bean, http.StatusOK) } @@ -535,3 +537,43 @@ func (impl ClusterRestHandlerImpl) FindAllForClusterPermission(w http.ResponseWr } common.WriteJsonResp(w, err, clusterList, http.StatusOK) } + +func (impl *ClusterRestHandlerImpl) CheckRbacForClusterDetails(clusterId int, token string) (authenticated bool, err error) { + //getting all environments for this cluster + envs, err := impl.environmentService.GetByClusterId(clusterId) + if err != nil { + impl.logger.Errorw("error in getting environments by clusterId", "err", err, "clusterId", clusterId) + return false, err + } + if len(envs) == 0 { + if ok := impl.enforcer.Enforce(token, casbin.ResourceGlobal, casbin.ActionGet, "*"); !ok { + return false, nil + } + return true, nil + } + emailId, err := impl.userService.GetEmailFromToken(token) + if err != nil { + impl.logger.Errorw("error in getting emailId from token", "err", err) + return false, err + } + + var envIdentifierList []string + envIdentifierMap := make(map[string]bool) + for _, env := range envs { + envIdentifier := strings.ToLower(env.EnvironmentIdentifier) + envIdentifierList = append(envIdentifierList, envIdentifier) + envIdentifierMap[envIdentifier] = true + } + if len(envIdentifierList) == 0 { + return false, errors.New("environment identifier list for rbac batch enforcing contains zero environments") + } + // RBAC enforcer applying + rbacResultMap := impl.enforcer.EnforceByEmailInBatch(emailId, casbin.ResourceGlobalEnvironment, casbin.ActionGet, envIdentifierList) + for envIdentifier, _ := range envIdentifierMap { + if rbacResultMap[envIdentifier] { + //if user has view permission to even one environment of this cluster, authorise the request + return true, nil + } + } + return false, nil +} diff --git a/cmd/external-app/wire_gen.go b/cmd/external-app/wire_gen.go index b6d8ae48c2..cf12c8182a 100644 --- a/cmd/external-app/wire_gen.go +++ b/cmd/external-app/wire_gen.go @@ -187,7 +187,7 @@ func InitializeApp() (*App, error) { if err != nil { return nil, err } - clusterRestHandlerImpl := cluster2.NewClusterRestHandlerImpl(clusterServiceImpl, clusterNoteServiceImpl, clusterDescriptionServiceImpl, sugaredLogger, userServiceImpl, validate, enforcerImpl, deleteServiceImpl, helmUserServiceImpl) + clusterRestHandlerImpl := cluster2.NewClusterRestHandlerImpl(clusterServiceImpl, clusterNoteServiceImpl, clusterDescriptionServiceImpl, sugaredLogger, userServiceImpl, validate, enforcerImpl, deleteServiceImpl, helmUserServiceImpl, environmentServiceImpl) clusterRouterImpl := cluster2.NewClusterRouterImpl(clusterRestHandlerImpl) dashboardConfig, err := dashboard.GetConfig() if err != nil { diff --git a/pkg/cluster/ClusterNoteHistoryService.go b/pkg/cluster/ClusterNoteHistoryService.go index e341992b99..54b88e8a1f 100644 --- a/pkg/cluster/ClusterNoteHistoryService.go +++ b/pkg/cluster/ClusterNoteHistoryService.go @@ -28,8 +28,8 @@ type ClusterNoteHistoryBean struct { Id int `json:"id" validate:"number"` NoteId int `json:"noteId" validate:"required"` Description string `json:"description" validate:"required"` - CreatedBy int `json:"createdBy"` - CreatedOn time.Time `json:"createdOn"` + CreatedBy int32 `json:"createdBy" validate:"number"` + CreatedOn time.Time `json:"createdOn" validate:"required"` } type ClusterNoteHistoryService interface { @@ -54,9 +54,9 @@ func (impl *ClusterNoteHistoryServiceImpl) Save(bean *ClusterNoteHistoryBean, us NoteId: bean.NoteId, Description: bean.Description, } - clusterAudit.CreatedBy = userId + clusterAudit.CreatedBy = bean.CreatedBy + clusterAudit.CreatedOn = bean.CreatedOn clusterAudit.UpdatedBy = userId - clusterAudit.CreatedOn = time.Now() clusterAudit.UpdatedOn = time.Now() err := impl.clusterNoteHistoryRepository.SaveHistory(clusterAudit) if err != nil { diff --git a/pkg/cluster/ClusterNoteService.go b/pkg/cluster/ClusterNoteService.go index a2630ab370..e1b6c54349 100644 --- a/pkg/cluster/ClusterNoteService.go +++ b/pkg/cluster/ClusterNoteService.go @@ -101,6 +101,8 @@ func (impl *ClusterNoteServiceImpl) Save(bean *ClusterNoteBean, userId int32) (* clusterAudit := &ClusterNoteHistoryBean{ NoteId: bean.Id, Description: bean.Description, + CreatedOn: model.CreatedOn, + CreatedBy: model.CreatedBy, } _, _ = impl.clusterNoteHistoryService.Save(clusterAudit, userId) return bean, err @@ -137,6 +139,8 @@ func (impl *ClusterNoteServiceImpl) Update(bean *ClusterNoteBean, userId int32) clusterAudit := &ClusterNoteHistoryBean{ NoteId: bean.Id, Description: bean.Description, + CreatedOn: model.CreatedOn, + CreatedBy: model.CreatedBy, } _, _ = impl.clusterNoteHistoryService.Save(clusterAudit, userId) return bean, err diff --git a/wire_gen.go b/wire_gen.go index 78569f324c..471c46263e 100644 --- a/wire_gen.go +++ b/wire_gen.go @@ -474,7 +474,7 @@ func InitializeApp() (*App, error) { clusterNoteServiceImpl := cluster2.NewClusterNoteServiceImpl(clusterNoteRepositoryImpl, clusterNoteHistoryServiceImpl, sugaredLogger) clusterDescriptionRepositoryImpl := repository2.NewClusterDescriptionRepositoryImpl(db, sugaredLogger) clusterDescriptionServiceImpl := cluster2.NewClusterDescriptionServiceImpl(clusterDescriptionRepositoryImpl, userRepositoryImpl, sugaredLogger) - clusterRestHandlerImpl := cluster3.NewClusterRestHandlerImpl(clusterServiceImplExtended, clusterNoteServiceImpl, clusterDescriptionServiceImpl, sugaredLogger, userServiceImpl, validate, enforcerImpl, deleteServiceExtendedImpl, argoUserServiceImpl) + clusterRestHandlerImpl := cluster3.NewClusterRestHandlerImpl(clusterServiceImplExtended, clusterNoteServiceImpl, clusterDescriptionServiceImpl, sugaredLogger, userServiceImpl, validate, enforcerImpl, deleteServiceExtendedImpl, argoUserServiceImpl, environmentServiceImpl) clusterRouterImpl := cluster3.NewClusterRouterImpl(clusterRestHandlerImpl) gitWebhookRepositoryImpl := repository.NewGitWebhookRepositoryImpl(db) gitWebhookServiceImpl := git.NewGitWebhookServiceImpl(sugaredLogger, ciHandlerImpl, gitWebhookRepositoryImpl) From 2cf4dde100f008cfd0939af943f4f4fb4e40d8b0 Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Tue, 2 May 2023 14:11:03 +0530 Subject: [PATCH 19/19] updated migration count --- ...luster_details.down.sql => 134_alter_cluster_details.down.sql} | 0 ...er_cluster_details.up.sql => 134_alter_cluster_details.up.sql} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename scripts/sql/{133_alter_cluster_details.down.sql => 134_alter_cluster_details.down.sql} (100%) rename scripts/sql/{133_alter_cluster_details.up.sql => 134_alter_cluster_details.up.sql} (100%) diff --git a/scripts/sql/133_alter_cluster_details.down.sql b/scripts/sql/134_alter_cluster_details.down.sql similarity index 100% rename from scripts/sql/133_alter_cluster_details.down.sql rename to scripts/sql/134_alter_cluster_details.down.sql diff --git a/scripts/sql/133_alter_cluster_details.up.sql b/scripts/sql/134_alter_cluster_details.up.sql similarity index 100% rename from scripts/sql/133_alter_cluster_details.up.sql rename to scripts/sql/134_alter_cluster_details.up.sql