diff --git a/internal/delivery/http/policy-template.go b/internal/delivery/http/policy-template.go index cfb7a29e..caf54f5c 100644 --- a/internal/delivery/http/policy-template.go +++ b/internal/delivery/http/policy-template.go @@ -261,10 +261,18 @@ func (h *PolicyTemplateHandler) Admin_GetPolicyTemplate(w http.ResponseWriter, r log.Error(r.Context(), err) } - if err = h.usecase.FillPermittedOrganizations(r.Context(), policyTemplate, &out.PolicyTemplate); err != nil { - log.Error(r.Context(), err) + out.PolicyTemplate.PermittedOrganizations = make([]domain.SimpleOrganizationResponse, len(policyTemplate.PermittedOrganizations)) + for i, organization := range policyTemplate.PermittedOrganizations { + if err := serializer.Map(r.Context(), organization, &out.PolicyTemplate.PermittedOrganizations[i]); err != nil { + log.Info(r.Context(), err) + continue + } } + // if err = h.usecase.FillPermittedOrganizations(r.Context(), policyTemplate, &out.PolicyTemplate); err != nil { + // log.Error(r.Context(), err) + // } + ResponseJSON(w, r, http.StatusOK, out) } @@ -301,12 +309,21 @@ func (h *PolicyTemplateHandler) Admin_ListPolicyTemplate(w http.ResponseWriter, log.Info(r.Context(), err) continue } - } - if err = h.usecase.FillPermittedOrganizationsForList(r.Context(), &policyTemplates, &out.PolicyTemplates); err != nil { - log.Error(r.Context(), err) + out.PolicyTemplates[i].PermittedOrganizations = make([]domain.SimpleOrganizationResponse, len(policyTemplate.PermittedOrganizations)) + for j, organization := range policyTemplate.PermittedOrganizations { + if err := serializer.Map(r.Context(), organization, &out.PolicyTemplates[i].PermittedOrganizations[j]); err != nil { + log.Info(r.Context(), err) + continue + } + } + } + // if err = h.usecase.FillPermittedOrganizationsForList(r.Context(), &policyTemplates, &out.PolicyTemplates); err != nil { + // log.Error(r.Context(), err) + // } + if out.Pagination, err = pg.Response(r.Context()); err != nil { log.Info(r.Context(), err) } @@ -554,10 +571,19 @@ func (h *PolicyTemplateHandler) Admin_GetPolicyTemplateVersion(w http.ResponseWr log.Error(r.Context(), err) } - if err = h.usecase.FillPermittedOrganizations(r.Context(), policyTemplate, &out.PolicyTemplate); err != nil { - log.Error(r.Context(), err) + out.PolicyTemplate.PermittedOrganizations = make([]domain.SimpleOrganizationResponse, len(policyTemplate.PermittedOrganizations)) + + for i, organization := range policyTemplate.PermittedOrganizations { + if err := serializer.Map(r.Context(), organization, &out.PolicyTemplate.PermittedOrganizations[i]); err != nil { + log.Info(r.Context(), err) + continue + } } + // if err = h.usecase.FillPermittedOrganizations(r.Context(), policyTemplate, &out.PolicyTemplate); err != nil { + // log.Error(r.Context(), err) + // } + ResponseJSON(w, r, http.StatusOK, out) } diff --git a/internal/repository/policy-template.go b/internal/repository/policy-template.go index c075189b..c06a7cae 100644 --- a/internal/repository/policy-template.go +++ b/internal/repository/policy-template.go @@ -50,7 +50,19 @@ func NewPolicyTemplateRepository(db *gorm.DB) IPolicyTemplateRepository { } func (r *PolicyTemplateRepository) Create(ctx context.Context, dto model.PolicyTemplate) (policyTemplateId uuid.UUID, err error) { - err = r.db.WithContext(ctx).Create(&dto).Error + err = r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { + // 이미 org가 존재하므로 many2many 레코드를 추가하지 않고 관계만 업데이트하도록 보장 + if err := tx.Omit("PermittedOrganizations").Create(&dto).Error; err != nil { + return err + } + + if err := tx.Model(&dto).Association("PermittedOrganizations"). + Append(dto.PermittedOrganizations); err != nil { + return err + } + + return nil + }) if err != nil { return uuid.Nil, err @@ -67,7 +79,7 @@ func (r *PolicyTemplateRepository) Update(ctx context.Context, policyTemplateId return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { if permittedOrganizations != nil { - err = r.db.WithContext(ctx).Model(&policyTemplate).Limit(1). + err = tx.WithContext(ctx).Model(&policyTemplate).Limit(1). Association("PermittedOrganizations").Replace(permittedOrganizations) if err != nil { @@ -76,7 +88,7 @@ func (r *PolicyTemplateRepository) Update(ctx context.Context, policyTemplateId } if len(updateMap) > 0 { - err = r.db.WithContext(ctx).Model(&policyTemplate).Limit(1). + err = tx.WithContext(ctx).Model(&policyTemplate).Limit(1). Where("id = ?", policyTemplateId).Where("type = ?", "tks"). Updates(updateMap).Error diff --git a/internal/repository/policy.go b/internal/repository/policy.go index 966ab5b8..7b1be877 100644 --- a/internal/repository/policy.go +++ b/internal/repository/policy.go @@ -48,7 +48,19 @@ func NewPolicyRepository(db *gorm.DB) IPolicyRepository { } func (r *PolicyRepository) Create(ctx context.Context, dto model.Policy) (policyId uuid.UUID, err error) { - err = r.db.WithContext(ctx).Create(&dto).Error + err = r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { + // 이미 org가 존재하므로 many2many 레코드를 추가하지 않고 관계만 업데이트하도록 보장 + if err := tx.Omit("TargetClusters").Create(&dto).Error; err != nil { + return err + } + + if err := tx.Model(&dto).Association("TargetClusters"). + Append(dto.TargetClusters); err != nil { + return err + } + + return nil + }) if err != nil { return uuid.Nil, err diff --git a/internal/usecase/policy-template.go b/internal/usecase/policy-template.go index dbcd774e..b235e781 100644 --- a/internal/usecase/policy-template.go +++ b/internal/usecase/policy-template.go @@ -5,10 +5,8 @@ import ( "fmt" "strings" - admin_domain "github.com/openinfradev/tks-api/pkg/domain/admin" "github.com/openinfradev/tks-api/pkg/log" - mapset "github.com/deckarep/golang-set/v2" "github.com/google/uuid" "github.com/openinfradev/tks-api/internal/middleware/auth/request" "github.com/openinfradev/tks-api/internal/model" @@ -35,10 +33,10 @@ type IPolicyTemplateUsecase interface { RegoCompile(request *domain.RegoCompileRequest, parseParameter bool) (response *domain.RegoCompileResponse, err error) - FillPermittedOrganizations(ctx context.Context, - policyTemplate *model.PolicyTemplate, out *admin_domain.PolicyTemplateResponse) error - FillPermittedOrganizationsForList(ctx context.Context, - policyTemplates *[]model.PolicyTemplate, outs *[]admin_domain.PolicyTemplateResponse) error + // FillPermittedOrganizations(ctx context.Context, + // policyTemplate *model.PolicyTemplate, out *admin_domain.PolicyTemplateResponse) error + // FillPermittedOrganizationsForList(ctx context.Context, + // policyTemplates *[]model.PolicyTemplate, outs *[]admin_domain.PolicyTemplateResponse) error ListPolicyTemplateStatistics(ctx context.Context, organizationId *string, policyTemplateId uuid.UUID) (statistics []model.UsageCount, err error) GetPolicyTemplateDeploy(ctx context.Context, organizationId *string, policyTemplateId uuid.UUID) (deployInfo domain.GetPolicyTemplateDeployResponse, err error) @@ -102,15 +100,18 @@ func (u *PolicyTemplateUsecase) Create(ctx context.Context, dto model.PolicyTemp // TKS 템블릿이면 dto.Mandatory = false dto.OrganizationId = nil + dto.PermittedOrganizations = make([]model.Organization, len(dto.PermittedOrganizationIds)) - for _, organizationId := range dto.PermittedOrganizationIds { - _, err := u.organizationRepo.Get(ctx, organizationId) + for i, organizationId := range dto.PermittedOrganizationIds { + organization, err := u.organizationRepo.Get(ctx, organizationId) if err != nil { return uuid.Nil, httpErrors.NewBadRequestError(fmt.Errorf("invalid organizationId"), "C_INVALID_ORGANIZATION_ID", "") } + dto.PermittedOrganizations[i] = organization } } else { dto.PermittedOrganizationIds = make([]string, 0) + dto.PermittedOrganizations = make([]model.Organization, 0) } userId := user.GetUserId() @@ -127,71 +128,93 @@ func (u *PolicyTemplateUsecase) Create(ctx context.Context, dto model.PolicyTemp func (u *PolicyTemplateUsecase) Fetch(ctx context.Context, organizationId *string, pg *pagination.Pagination) (policyTemplates []model.PolicyTemplate, err error) { if organizationId == nil { - return u.repo.Fetch(ctx, pg) + policyTemplates, err = u.repo.Fetch(ctx, pg) + } else { + policyTemplates, err = u.repo.FetchForOrganization(ctx, *organizationId, pg) } - return u.repo.FetchForOrganization(ctx, *organizationId, pg) -} + if err != nil { + log.Errorf(ctx, "error is :%s(%T)", err.Error(), err) + } -func (u *PolicyTemplateUsecase) FillPermittedOrganizations(ctx context.Context, - policyTemplate *model.PolicyTemplate, out *admin_domain.PolicyTemplateResponse) error { organizations, err := u.organizationRepo.Fetch(ctx, nil) if err != nil { - return err + log.Errorf(ctx, "error is :%s(%T)", err.Error(), err) } - u.fillPermittedOrganizations(ctx, organizations, policyTemplate, out) + for i := range policyTemplates { + // 단순히 참조하면 업데이트가 안되므로 pointer derefrencing + policyTemplate := &policyTemplates[i] + if policyTemplate.IsTksTemplate() && len(policyTemplate.PermittedOrganizations) == 0 { + if organizations != nil { + (*policyTemplate).PermittedOrganizations = *organizations + } + } + } - return nil + return policyTemplates, err } -func (u *PolicyTemplateUsecase) FillPermittedOrganizationsForList(ctx context.Context, - policyTemplates *[]model.PolicyTemplate, outs *[]admin_domain.PolicyTemplateResponse) error { +// func (u *PolicyTemplateUsecase) FillPermittedOrganizations(ctx context.Context, +// policyTemplate *model.PolicyTemplate, out *admin_domain.PolicyTemplateResponse) error { +// organizations, err := u.organizationRepo.Fetch(ctx, nil) - organizations, err := u.organizationRepo.Fetch(ctx, nil) +// if err != nil { +// return err +// } - if err != nil { - return err - } +// u.fillPermittedOrganizations(ctx, organizations, policyTemplate, out) - results := *outs +// return nil +// } - for i, policyTemplate := range *policyTemplates { - u.fillPermittedOrganizations(ctx, organizations, &policyTemplate, &results[i]) - } +// func (u *PolicyTemplateUsecase) FillPermittedOrganizationsForList(ctx context.Context, +// policyTemplates *[]model.PolicyTemplate, outs *[]admin_domain.PolicyTemplateResponse) error { - return nil -} +// organizations, err := u.organizationRepo.Fetch(ctx, nil) -// 모든 조직 목록에 대해 허용 여부 업데이트 -func (u *PolicyTemplateUsecase) fillPermittedOrganizations(_ context.Context, organizations *[]model.Organization, policyTemplate *model.PolicyTemplate, out *admin_domain.PolicyTemplateResponse) { - if policyTemplate == nil || organizations == nil || out == nil { - return - } +// if err != nil { +// return err +// } - if policyTemplate.IsOrganizationTemplate() { - return - } +// results := *outs - // 정책 템플릿에서 허용된 조직 목록이 없다는 것은 모든 조직이 사용할 수 있음을 의미함 - allPermitted := len(policyTemplate.PermittedOrganizationIds) == 0 +// for i, policyTemplate := range *policyTemplates { +// u.fillPermittedOrganizations(ctx, organizations, &policyTemplate, &results[i]) +// } - // 허용된 조직 포함 여부를 효율적으로 처리하기 위해 ID 리스트를 셋으로 변환 - permittedOrganizationIdSet := mapset.NewSet(policyTemplate.PermittedOrganizationIds...) +// return nil +// } - out.PermittedOrganizations = make([]admin_domain.PermittedOrganization, len(*organizations)) +// // 모든 조직 목록에 대해 허용 여부 업데이트 +// func (u *PolicyTemplateUsecase) fillPermittedOrganizations(_ context.Context, organizations *[]model.Organization, policyTemplate *model.PolicyTemplate, out *admin_domain.PolicyTemplateResponse) { +// if policyTemplate == nil || organizations == nil || out == nil { +// return +// } - for i, organization := range *organizations { - permitted := allPermitted || permittedOrganizationIdSet.ContainsOne(organization.ID) +// if policyTemplate.IsOrganizationTemplate() { +// return +// } - out.PermittedOrganizations[i] = admin_domain.PermittedOrganization{ - OrganizationId: organization.ID, - OrganizationName: organization.Name, - Permitted: permitted, - } - } -} +// // 정책 템플릿에서 허용된 조직 목록이 없다는 것은 모든 조직이 사용할 수 있음을 의미함 +// allPermitted := len(policyTemplate.PermittedOrganizationIds) == 0 + +// // 허용된 조직 포함 여부를 효율적으로 처리하기 위해 ID 리스트를 셋으로 변환 +// permittedOrganizationIdSet := mapset.NewSet(policyTemplate.PermittedOrganizationIds...) + +// out.PermittedOrganizations = make([]admin_domain.PermittedOrganization, len(*organizations)) + +// for i, organization := range *organizations { +// permitted := allPermitted || permittedOrganizationIdSet.ContainsOne(organization.ID) + +// out.PermittedOrganizations[i] = admin_domain.PermittedOrganization{ +// OrganizationId: organization.ID, +// OrganizationName: organization.Name, +// Permitted: permitted, +// } +// } +// } func (u *PolicyTemplateUsecase) Get(ctx context.Context, organizationId *string, policyTemplateID uuid.UUID) (policyTemplates *model.PolicyTemplate, err error) { policyTemplate, err := u.repo.GetByID(ctx, policyTemplateID) @@ -206,6 +229,16 @@ func (u *PolicyTemplateUsecase) Get(ctx context.Context, organizationId *string, "PT_NOT_FOUND_POLICY_TEMPLATE", "") } + if policyTemplate.IsTksTemplate() && len(policyTemplate.PermittedOrganizations) == 0 { + organizations, err := u.organizationRepo.Fetch(ctx, nil) + + if err != nil { + log.Errorf(ctx, "error is :%s(%T)", err.Error(), err) + } else if organizations != nil { + policyTemplate.PermittedOrganizations = *organizations + } + } + return policyTemplate, nil } @@ -357,6 +390,16 @@ func (u *PolicyTemplateUsecase) GetPolicyTemplateVersion(ctx context.Context, or "PT_NOT_FOUND_POLICY_TEMPLATE", "") } + if policyTemplate.IsTksTemplate() && len(policyTemplate.PermittedOrganizations) == 0 { + organizations, err := u.organizationRepo.Fetch(ctx, nil) + + if err != nil { + log.Errorf(ctx, "error is :%s(%T)", err.Error(), err) + } else if organizations != nil { + policyTemplate.PermittedOrganizations = *organizations + } + } + return policyTemplate, nil } diff --git a/pkg/domain/admin/policy-template.go b/pkg/domain/admin/policy-template.go index ab13594c..413609a3 100644 --- a/pkg/domain/admin/policy-template.go +++ b/pkg/domain/admin/policy-template.go @@ -6,11 +6,11 @@ import ( "github.com/openinfradev/tks-api/pkg/domain" ) -type PermittedOrganization struct { - OrganizationId string `json:"organizationId"` - OrganizationName string `json:"organizationName"` - Permitted bool `json:"permitted"` -} +// type PermittedOrganization struct { +// OrganizationId string `json:"organizationId"` +// OrganizationName string `json:"organizationName"` +// Permitted bool `json:"permitted"` +// } type PolicyTemplateResponse struct { ID string `json:"id" example:"d98ef5f1-4a68-4047-a446-2207787ce3ff"` @@ -30,7 +30,7 @@ type PolicyTemplateResponse struct { Rego string `json:"rego" example:"rego 코드"` Libs []string `json:"libs" example:"rego 코드"` - PermittedOrganizations []PermittedOrganization `json:"permittedOrganizations"` + PermittedOrganizations []domain.SimpleOrganizationResponse `json:"permittedOrganizations"` } type SimplePolicyTemplateResponse struct {