From 3b4baa3196a51c0629889a9d8fcf741de37bd146 Mon Sep 17 00:00:00 2001 From: michalkrzyz Date: Mon, 18 Nov 2024 16:59:23 +0100 Subject: [PATCH] feat(authN): Add to all DB entries 'Modified_by'... (#81) (#230) * feat(authN): Add to all DB entries 'Modified_by'... (#81) Move 'CreatedAt', 'DeletedAt' and 'UpdatedAt' to common entity.Info struct Add 'CreatedBy' and 'UpdatedBy' to common entity.Info struct Add metadata for user Add tests Add metadata for activity, IssueVariant and IssueRepository Add metadata for component Add metadata for componentInstance, componentVersion Add metadata for evidence Issue Metadata rename to IssueMetadata, because now metadata means data related to creation time, creation user, update time and update user Add Metadata for Issue Add metadata for IssueMatch Add Metadata for IssueMatchChange, Service and SupportGroup Refactor and review fixes Test foreign key Add Foreign Key changed issueMetadata and serviceMetadata to objectMetadata * chore: bumping for re-trigger * Automatic application of license header --------- Co-authored-by: David Rochow Co-authored-by: License Bot --- README.md | 1 - go.mod | 2 +- .../api/graphql/graph/baseResolver/common.go | 2 +- internal/api/graphql/graph/model/models.go | 89 +++--- .../componentInstance/directRelations.graphql | 8 +- .../queryCollection/issue/create.graphql | 2 +- .../issue/directRelations.graphql | 24 +- .../queryCollection/issue/listIssues.graphql | 28 ++ ...ata.graphql => withObjectMetadata.graphql} | 2 +- .../issueRepository/directRelations.graphql | 22 +- .../issueVariant/directRelations.graphql | 18 +- .../service/directRelations.graphql | 12 +- ...ata.graphql => withObjectMetadata.graphql} | 4 +- .../queryCollection/user/listUsers.graphql | 27 ++ .../graphql/graph/schema/activity.graphqls | 4 +- .../api/graphql/graph/schema/common.graphqls | 10 +- .../graphql/graph/schema/component.graphqls | 3 +- .../graph/schema/component_instance.graphqls | 5 +- .../graph/schema/component_version.graphqls | 3 +- .../graphql/graph/schema/evidence.graphqls | 3 +- .../api/graphql/graph/schema/issue.graphqls | 3 +- .../graphql/graph/schema/issue_match.graphqls | 1 + .../graph/schema/issue_match_change.graphqls | 1 + .../graph/schema/issue_repository.graphqls | 8 +- .../graph/schema/issue_variant.graphqls | 8 +- .../api/graphql/graph/schema/service.graphqls | 4 +- .../graph/schema/support_group.graphqls | 3 +- .../api/graphql/graph/schema/user.graphqls | 1 + internal/app/activity/activity_handler.go | 16 +- .../app/activity/activity_handler_test.go | 3 + internal/app/common/user_id.go | 26 ++ internal/app/component/component_handler.go | 16 +- .../app/component/component_handler_test.go | 3 + .../component_instance_handler.go | 16 +- .../component_instance_handler_test.go | 3 + .../component_version_handler.go | 16 +- .../component_version_handler_test.go | 3 + internal/app/evidence/evidence_handler.go | 16 +- .../app/evidence/evidence_handler_test.go | 3 + internal/app/issue/issue_handler.go | 16 +- internal/app/issue/issue_handler_test.go | 3 + .../app/issue_match/issue_match_handler.go | 16 +- .../issue_match/issue_match_handler_test.go | 2 + .../issue_match_change_handler.go | 16 +- .../issue_match_change_handler_test.go | 3 + .../issue_repository_handler.go | 16 +- .../issue_repository_handler_events.go | 2 +- .../issue_repository_handler_test.go | 3 + .../issue_variant/issue_variant_handler.go | 16 +- .../issue_variant_handler_test.go | 3 + internal/app/service/service_handler.go | 16 +- internal/app/service/service_handler_test.go | 3 + .../support_group/support_group_handler.go | 16 +- .../support_group_handler_test.go | 3 + internal/app/user/user_handler.go | 16 +- internal/app/user/user_handler_test.go | 3 + internal/database/mariadb/activity.go | 9 +- internal/database/mariadb/component.go | 9 +- .../database/mariadb/component_instance.go | 10 +- .../database/mariadb/component_version.go | 9 +- internal/database/mariadb/entity.go | 275 +++++++++++++----- internal/database/mariadb/evidence.go | 9 +- internal/database/mariadb/init/schema.sql | 149 +++++++--- internal/database/mariadb/issue.go | 9 +- internal/database/mariadb/issue_match.go | 9 +- .../database/mariadb/issue_match_change.go | 9 +- internal/database/mariadb/issue_repository.go | 9 +- internal/database/mariadb/issue_variant.go | 9 +- internal/database/mariadb/service.go | 9 +- .../mariadb/service_issue_variant_test.go | 8 +- internal/database/mariadb/service_test.go | 4 +- internal/database/mariadb/support_group.go | 9 +- .../database/mariadb/test/database_manager.go | 1 + internal/database/mariadb/test/fixture.go | 65 +++-- internal/database/mariadb/user.go | 10 +- internal/database/mariadb/user_test.go | 17 +- internal/e2e/common/issue.go | 104 +++++++ internal/e2e/common/user.go | 169 +++++++++++ internal/e2e/issue_query_test.go | 14 +- internal/e2e/metadata_test.go | 123 ++++++++ internal/e2e/service_filter_query_test.go | 13 +- internal/e2e/service_query_test.go | 6 +- internal/e2e/user_query_test.go | 76 +---- internal/entity/activity.go | 14 +- internal/entity/common.go | 22 +- internal/entity/component.go | 12 +- internal/entity/component_instance.go | 9 +- internal/entity/component_version.go | 9 +- internal/entity/evidence.go | 7 +- internal/entity/issue.go | 4 +- internal/entity/issue_match.go | 4 +- internal/entity/issue_match_change.go | 8 +- internal/entity/issue_repository.go | 6 +- internal/entity/issue_repository_service.go | 12 +- internal/entity/issue_variant.go | 6 +- internal/entity/service.go | 6 +- internal/entity/support_group.go | 10 +- internal/entity/support_group_service.go | 10 +- internal/entity/support_group_user.go | 10 +- internal/entity/test/activity.go | 8 +- internal/entity/test/component.go | 14 +- internal/entity/test/component_instance.go | 8 +- internal/entity/test/component_version.go | 8 +- internal/entity/test/evidence.go | 8 +- internal/entity/test/issue.go | 8 +- internal/entity/test/issue_match.go | 8 +- internal/entity/test/issue_match_change.go | 8 +- internal/entity/test/issue_repository.go | 14 +- internal/entity/test/issue_variant.go | 8 +- internal/entity/test/service.go | 8 +- internal/entity/test/support_group.go | 12 +- internal/entity/test/user.go | 8 +- internal/entity/user.go | 14 +- 113 files changed, 1510 insertions(+), 488 deletions(-) create mode 100644 internal/api/graphql/graph/queryCollection/issue/listIssues.graphql rename internal/api/graphql/graph/queryCollection/issue/{withMetadata.graphql => withObjectMetadata.graphql} (97%) rename internal/api/graphql/graph/queryCollection/service/{withMetadata.graphql => withObjectMetadata.graphql} (96%) create mode 100644 internal/api/graphql/graph/queryCollection/user/listUsers.graphql create mode 100644 internal/app/common/user_id.go create mode 100644 internal/e2e/common/issue.go create mode 100644 internal/e2e/common/user.go create mode 100644 internal/e2e/metadata_test.go diff --git a/README.md b/README.md index febbc260..dd538cb1 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,6 @@ For a detailed understanding of Heureka's architecture and design, refer to the - [High-Level Architecture Diagram](https://github.com/cloudoperators/heureka/blob/main/docs/product_design_documentation.md#high-level-features): This provides a visual representation of the overall system architecture. - [High-Level Features](https://github.com/cloudoperators/heureka/blob/main/docs/product_design_documentation.md#high-level-features): A high-level overview of Heureka's functionalities. - ## Requirements and Setup The application can be configured using environment variables. These variables are stored in a `.env` file at the root of the project. diff --git a/go.mod b/go.mod index 3dd6a656..03f36829 100644 --- a/go.mod +++ b/go.mod @@ -22,6 +22,7 @@ require ( github.com/samber/lo v1.47.0 github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.9.0 + github.com/vektah/gqlparser/v2 v2.5.19 golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 ) @@ -85,7 +86,6 @@ require ( github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect github.com/urfave/cli/v2 v2.27.5 // indirect - github.com/vektah/gqlparser/v2 v2.5.19 // indirect github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect go.opentelemetry.io/otel v1.24.0 // indirect diff --git a/internal/api/graphql/graph/baseResolver/common.go b/internal/api/graphql/graph/baseResolver/common.go index dcb162b5..1e83a5fd 100644 --- a/internal/api/graphql/graph/baseResolver/common.go +++ b/internal/api/graphql/graph/baseResolver/common.go @@ -102,6 +102,6 @@ func GetListOptions(requestedFields []string) *entity.ListOptions { return &entity.ListOptions{ ShowTotalCount: lo.Contains(requestedFields, "totalCount"), ShowPageInfo: lo.Contains(requestedFields, "pageInfo"), - IncludeAggregations: lo.Contains(requestedFields, "edges.node.metadata"), + IncludeAggregations: lo.Contains(requestedFields, "edges.node.objectMetadata"), } } diff --git a/internal/api/graphql/graph/model/models.go b/internal/api/graphql/graph/model/models.go index 4fe2052a..7089bd5f 100644 --- a/internal/api/graphql/graph/model/models.go +++ b/internal/api/graphql/graph/model/models.go @@ -15,6 +15,18 @@ import ( ) // add custom models here +func getModelMetadata(em entity.Metadata) *Metadata { + createdAt := em.CreatedAt.String() + deletedAt := em.DeletedAt.String() + updatedAt := em.UpdatedAt.String() + return &Metadata{ + CreatedAt: util.Ptr(createdAt), + CreatedBy: util.Ptr(fmt.Sprintf("%d", em.CreatedBy)), + DeletedAt: util.Ptr(deletedAt), + UpdatedAt: util.Ptr(updatedAt), + UpdatedBy: util.Ptr(fmt.Sprintf("%d", em.UpdatedBy)), + } +} var AllSeverityValuesOrdered = []SeverityValues{ SeverityValuesCritical, @@ -160,6 +172,7 @@ func NewIssue(issue *entity.Issue) Issue { Type: &issueType, Description: &issue.Description, LastModified: &lastModified, + Metadata: getModelMetadata(issue.Metadata), } } @@ -167,10 +180,10 @@ func NewIssueWithAggregations(issue *entity.IssueResult) Issue { lastModified := issue.Issue.UpdatedAt.String() issueType := IssueTypes(issue.Type.String()) - var metadata IssueMetadata + var objectMetadata IssueMetadata if issue.IssueAggregations != nil { - metadata = IssueMetadata{ + objectMetadata = IssueMetadata{ ServiceCount: int(issue.IssueAggregations.AffectedServices), ActivityCount: int(issue.IssueAggregations.Activities), IssueMatchCount: int(issue.IssueAggregations.IssueMatches), @@ -182,11 +195,13 @@ func NewIssueWithAggregations(issue *entity.IssueResult) Issue { } return Issue{ - ID: fmt.Sprintf("%d", issue.Issue.Id), - PrimaryName: &issue.Issue.PrimaryName, - Type: &issueType, - LastModified: &lastModified, - Metadata: &metadata, + ID: fmt.Sprintf("%d", issue.Issue.Id), + PrimaryName: &issue.Issue.PrimaryName, + Type: &issueType, + Description: &issue.Issue.Description, + LastModified: &lastModified, + ObjectMetadata: &objectMetadata, + Metadata: getModelMetadata(issue.Issue.Metadata), } } @@ -218,6 +233,7 @@ func NewIssueMatch(im *entity.IssueMatch) IssueMatch { IssueID: util.Ptr(fmt.Sprintf("%d", im.IssueId)), ComponentInstanceID: util.Ptr(fmt.Sprintf("%d", im.ComponentInstanceId)), UserID: util.Ptr(fmt.Sprintf("%d", im.UserId)), + Metadata: getModelMetadata(im.Metadata), } } @@ -240,7 +256,7 @@ func NewIssueMatchEntity(im *IssueMatchInput) entity.IssueMatch { IssueId: issueId, ComponentInstanceId: ciId, UserId: userId, - CreatedAt: createdAt, + Metadata: entity.Metadata{CreatedAt: createdAt}, } } @@ -253,6 +269,7 @@ func NewIssueMatchChange(imc *entity.IssueMatchChange) IssueMatchChange { IssueMatch: nil, ActivityID: util.Ptr(fmt.Sprintf("%d", imc.ActivityId)), Activity: nil, + Metadata: getModelMetadata(imc.Metadata), } } @@ -268,16 +285,13 @@ func NewIssueMatchChangeEntity(imc *IssueMatchChangeInput) entity.IssueMatchChan } func NewIssueRepository(repo *entity.IssueRepository) IssueRepository { - createdAt := repo.BaseIssueRepository.CreatedAt.String() - updatedAt := repo.BaseIssueRepository.UpdatedAt.String() return IssueRepository{ ID: fmt.Sprintf("%d", repo.Id), Name: &repo.Name, URL: &repo.Url, Services: nil, IssueVariants: nil, - CreatedAt: &createdAt, - UpdatedAt: &updatedAt, + Metadata: getModelMetadata(repo.BaseIssueRepository.Metadata), } } @@ -295,8 +309,6 @@ func NewIssueVariant(issueVariant *entity.IssueVariant) IssueVariant { if issueVariant.IssueRepository != nil { repo = NewIssueRepository(issueVariant.IssueRepository) } - createdAt := issueVariant.CreatedAt.String() - updatedAt := issueVariant.UpdatedAt.String() return IssueVariant{ ID: fmt.Sprintf("%d", issueVariant.Id), SecondaryName: &issueVariant.SecondaryName, @@ -305,20 +317,16 @@ func NewIssueVariant(issueVariant *entity.IssueVariant) IssueVariant { IssueID: util.Ptr(fmt.Sprintf("%d", issueVariant.IssueId)), IssueRepositoryID: util.Ptr(fmt.Sprintf("%d", issueVariant.IssueRepositoryId)), IssueRepository: &repo, - CreatedAt: &createdAt, - UpdatedAt: &updatedAt, + Metadata: getModelMetadata(issueVariant.Metadata), } } func NewIssueVariantEdge(issueVariant *entity.IssueVariant) IssueVariantEdge { iv := NewIssueVariant(issueVariant) - edgeCreationDate := issueVariant.CreatedAt.String() - edgeUpdateDate := issueVariant.UpdatedAt.String() issueVariantEdge := IssueVariantEdge{ - Node: &iv, - Cursor: &iv.ID, - CreatedAt: &edgeCreationDate, - UpdatedAt: &edgeUpdateDate, + Node: &iv, + Cursor: &iv.ID, + Metadata: getModelMetadata(issueVariant.Metadata), } return issueVariantEdge } @@ -341,6 +349,7 @@ func NewUser(user *entity.User) User { UniqueUserID: &user.UniqueUserID, Name: &user.Name, Type: int(user.Type), + Metadata: getModelMetadata(user.Metadata), } } @@ -354,25 +363,27 @@ func NewUserEntity(user *UserInput) entity.User { func NewService(s *entity.Service) Service { return Service{ - ID: fmt.Sprintf("%d", s.Id), - Ccrn: &s.CCRN, + ID: fmt.Sprintf("%d", s.Id), + Ccrn: &s.CCRN, + Metadata: getModelMetadata(s.BaseService.Metadata), } } func NewServiceWithAggregations(service *entity.ServiceResult) Service { - var metadata ServiceMetadata + var objectMetadata ServiceMetadata if service.ServiceAggregations != nil { - metadata = ServiceMetadata{ + objectMetadata = ServiceMetadata{ IssueMatchCount: int(service.ServiceAggregations.IssueMatches), ComponentInstanceCount: int(service.ServiceAggregations.ComponentInstances), } } return Service{ - ID: fmt.Sprintf("%d", service.Id), - Ccrn: &service.CCRN, - Metadata: &metadata, + ID: fmt.Sprintf("%d", service.Id), + Ccrn: &service.CCRN, + ObjectMetadata: &objectMetadata, + Metadata: getModelMetadata(service.BaseService.Metadata), } } @@ -386,8 +397,9 @@ func NewServiceEntity(service *ServiceInput) entity.Service { func NewSupportGroup(supportGroup *entity.SupportGroup) SupportGroup { return SupportGroup{ - ID: fmt.Sprintf("%d", supportGroup.Id), - Ccrn: &supportGroup.CCRN, + ID: fmt.Sprintf("%d", supportGroup.Id), + Ccrn: &supportGroup.CCRN, + Metadata: getModelMetadata(supportGroup.Metadata), } } @@ -400,8 +412,9 @@ func NewSupportGroupEntity(supportGroup *SupportGroupInput) entity.SupportGroup func NewActivity(activity *entity.Activity) Activity { status := ActivityStatusValues(activity.Status.String()) return Activity{ - ID: fmt.Sprintf("%d", activity.Id), - Status: &status, + ID: fmt.Sprintf("%d", activity.Id), + Status: &status, + Metadata: getModelMetadata(activity.Metadata), } } @@ -429,6 +442,7 @@ func NewEvidence(evidence *entity.Evidence) Evidence { Vector: severity.Cvss.Vector, Type: &t, RaaEnd: &raaEnd, + Metadata: getModelMetadata(evidence.Metadata), } } @@ -451,9 +465,10 @@ func NewEvidenceEntity(evidence *EvidenceInput) entity.Evidence { func NewComponent(component *entity.Component) Component { componentType, _ := ComponentTypeValue(component.Type) return Component{ - ID: fmt.Sprintf("%d", component.Id), - Ccrn: &component.CCRN, - Type: &componentType, + ID: fmt.Sprintf("%d", component.Id), + Ccrn: &component.CCRN, + Type: &componentType, + Metadata: getModelMetadata(component.Metadata), } } @@ -473,6 +488,7 @@ func NewComponentVersion(componentVersion *entity.ComponentVersion) ComponentVer ID: fmt.Sprintf("%d", componentVersion.Id), Version: &componentVersion.Version, ComponentID: util.Ptr(fmt.Sprintf("%d", componentVersion.ComponentId)), + Metadata: getModelMetadata(componentVersion.Metadata), } } @@ -495,6 +511,7 @@ func NewComponentInstance(componentInstance *entity.ComponentInstance) Component Count: &count, ComponentVersionID: util.Ptr(fmt.Sprintf("%d", componentInstance.ComponentVersionId)), ServiceID: util.Ptr(fmt.Sprintf("%d", componentInstance.ServiceId)), + Metadata: getModelMetadata(componentInstance.Metadata), } } diff --git a/internal/api/graphql/graph/queryCollection/componentInstance/directRelations.graphql b/internal/api/graphql/graph/queryCollection/componentInstance/directRelations.graphql index 1ef71306..62194d34 100644 --- a/internal/api/graphql/graph/queryCollection/componentInstance/directRelations.graphql +++ b/internal/api/graphql/graph/queryCollection/componentInstance/directRelations.graphql @@ -25,8 +25,10 @@ query ($filter: ComponentInstanceFilter, $first: Int, $after: String) { id ccrn } - createdAt - updatedAt + metadata { + created_at + updated_at + } issueMatches { totalCount edges { @@ -57,4 +59,4 @@ query ($filter: ComponentInstanceFilter, $first: Int, $after: String) { } } } -} \ No newline at end of file +} diff --git a/internal/api/graphql/graph/queryCollection/issue/create.graphql b/internal/api/graphql/graph/queryCollection/issue/create.graphql index 33383af3..7e1ebf78 100644 --- a/internal/api/graphql/graph/queryCollection/issue/create.graphql +++ b/internal/api/graphql/graph/queryCollection/issue/create.graphql @@ -10,4 +10,4 @@ mutation ($input: IssueInput!) { description type } -} \ No newline at end of file +} diff --git a/internal/api/graphql/graph/queryCollection/issue/directRelations.graphql b/internal/api/graphql/graph/queryCollection/issue/directRelations.graphql index 31c599d7..8dc0c8a7 100644 --- a/internal/api/graphql/graph/queryCollection/issue/directRelations.graphql +++ b/internal/api/graphql/graph/queryCollection/issue/directRelations.graphql @@ -33,16 +33,22 @@ query ($filter: IssueFilter, $first: Int, $after: String) { id name url + metadata { + created_at + updated_at + } + } + issueId + metadata { created_at updated_at } - issueId + } + cursor + metadata { created_at updated_at } - cursor - created_at - updated_at } pageInfo { hasNextPage @@ -61,8 +67,10 @@ query ($filter: IssueFilter, $first: Int, $after: String) { componentInstance { id count - createdAt - updatedAt + metadata { + created_at + updated_at + } ccrn } } @@ -73,7 +81,7 @@ query ($filter: IssueFilter, $first: Int, $after: String) { nextPageAfter } } - metadata { + objectMetadata { serviceCount activityCount issueMatchCount @@ -98,4 +106,4 @@ query ($filter: IssueFilter, $first: Int, $after: String) { } } } -} \ No newline at end of file +} diff --git a/internal/api/graphql/graph/queryCollection/issue/listIssues.graphql b/internal/api/graphql/graph/queryCollection/issue/listIssues.graphql new file mode 100644 index 00000000..318e8b22 --- /dev/null +++ b/internal/api/graphql/graph/queryCollection/issue/listIssues.graphql @@ -0,0 +1,28 @@ +# SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors +# SPDX-License-Identifier: Apache-2.0 + +query ($filter: IssueFilter, $first: Int, $after: String) { + Issues ( + filter: $filter, + first: $first, + after: $after + ) { + totalCount + edges { + node { + id + primaryName + type + description + metadata { + created_at + created_by + deleted_at + updated_at + updated_by + } + } + cursor + } + } +} diff --git a/internal/api/graphql/graph/queryCollection/issue/withMetadata.graphql b/internal/api/graphql/graph/queryCollection/issue/withObjectMetadata.graphql similarity index 97% rename from internal/api/graphql/graph/queryCollection/issue/withMetadata.graphql rename to internal/api/graphql/graph/queryCollection/issue/withObjectMetadata.graphql index 669a1022..0cfce82d 100644 --- a/internal/api/graphql/graph/queryCollection/issue/withMetadata.graphql +++ b/internal/api/graphql/graph/queryCollection/issue/withObjectMetadata.graphql @@ -12,7 +12,7 @@ query ($filter: IssueFilter, $first: Int, $after: String) { node { id lastModified - metadata { + objectMetadata { serviceCount activityCount issueMatchCount diff --git a/internal/api/graphql/graph/queryCollection/issueRepository/directRelations.graphql b/internal/api/graphql/graph/queryCollection/issueRepository/directRelations.graphql index db574c98..411f5ca4 100644 --- a/internal/api/graphql/graph/queryCollection/issueRepository/directRelations.graphql +++ b/internal/api/graphql/graph/queryCollection/issueRepository/directRelations.graphql @@ -23,12 +23,16 @@ query ($filter: IssueRepositoryFilter, $first: Int, $after: String) { description issueRepositoryId issueId + metadata { + created_at + updated_at + } + } + cursor + metadata { created_at updated_at } - cursor - created_at - updated_at } pageInfo { hasNextPage @@ -50,12 +54,16 @@ query ($filter: IssueRepositoryFilter, $first: Int, $after: String) { nextPageAfter } } + metadata { + created_at + updated_at + } + } + cursor + metadata { created_at updated_at } - cursor - created_at - updated_at } pageInfo { hasNextPage @@ -71,4 +79,4 @@ query ($filter: IssueRepositoryFilter, $first: Int, $after: String) { } } } -} \ No newline at end of file +} diff --git a/internal/api/graphql/graph/queryCollection/issueVariant/directRelations.graphql b/internal/api/graphql/graph/queryCollection/issueVariant/directRelations.graphql index f2402acd..a9c1bae3 100644 --- a/internal/api/graphql/graph/queryCollection/issueVariant/directRelations.graphql +++ b/internal/api/graphql/graph/queryCollection/issueVariant/directRelations.graphql @@ -23,20 +23,26 @@ query ($filter: IssueVariantFilter, $first: Int, $after: String) { id name url - created_at - updated_at + metadata { + created_at + updated_at + } } issueId issue { id lastModified } + metadata { + created_at + updated_at + } + } + cursor + metadata { created_at updated_at } - cursor - created_at - updated_at } pageInfo { hasNextPage @@ -52,4 +58,4 @@ query ($filter: IssueVariantFilter, $first: Int, $after: String) { } } } -} \ No newline at end of file +} diff --git a/internal/api/graphql/graph/queryCollection/service/directRelations.graphql b/internal/api/graphql/graph/queryCollection/service/directRelations.graphql index 3b1f6b75..eecf91c9 100644 --- a/internal/api/graphql/graph/queryCollection/service/directRelations.graphql +++ b/internal/api/graphql/graph/queryCollection/service/directRelations.graphql @@ -63,13 +63,17 @@ query ($filter: ServiceFilter, $first: Int, $after: String) { id name url - created_at - updated_at + metadata { + created_at + updated_at + } } cursor priority - created_at - updated_at + metadata { + created_at + updated_at + } } pageInfo { hasNextPage diff --git a/internal/api/graphql/graph/queryCollection/service/withMetadata.graphql b/internal/api/graphql/graph/queryCollection/service/withObjectMetadata.graphql similarity index 96% rename from internal/api/graphql/graph/queryCollection/service/withMetadata.graphql rename to internal/api/graphql/graph/queryCollection/service/withObjectMetadata.graphql index ae54a716..aaa17253 100644 --- a/internal/api/graphql/graph/queryCollection/service/withMetadata.graphql +++ b/internal/api/graphql/graph/queryCollection/service/withObjectMetadata.graphql @@ -22,7 +22,7 @@ query ($filter: ServiceFilter, $first: Int, $after: String) { } } } - metadata { + objectMetadata { issueMatchCount componentInstanceCount } @@ -30,4 +30,4 @@ query ($filter: ServiceFilter, $first: Int, $after: String) { cursor } } -} \ No newline at end of file +} diff --git a/internal/api/graphql/graph/queryCollection/user/listUsers.graphql b/internal/api/graphql/graph/queryCollection/user/listUsers.graphql new file mode 100644 index 00000000..9fd813a3 --- /dev/null +++ b/internal/api/graphql/graph/queryCollection/user/listUsers.graphql @@ -0,0 +1,27 @@ +# SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors +# SPDX-License-Identifier: Apache-2.0 + +query ($filter: UserFilter, $first: Int, $after: String) { + Users ( + filter: $filter, + first: $first, + after: $after + ) { + totalCount + edges { + node { + id + name + type + metadata { + created_at + created_by + deleted_at + updated_at + updated_by + } + } + cursor + } + } +} diff --git a/internal/api/graphql/graph/schema/activity.graphqls b/internal/api/graphql/graph/schema/activity.graphqls index 0b4dd782..c7029148 100644 --- a/internal/api/graphql/graph/schema/activity.graphqls +++ b/internal/api/graphql/graph/schema/activity.graphqls @@ -8,6 +8,7 @@ type Activity implements Node { issues(filter: IssueFilter, first: Int, after: String): IssueConnection evidences(filter: EvidenceFilter, first: Int, after: String): EvidenceConnection issueMatchChanges(filter: IssueMatchChangeFilter, first: Int, after: String): IssueMatchChangeConnection + metadata: Metadata } input ActivityInput { @@ -23,6 +24,7 @@ type ActivityConnection implements Connection { type ActivityEdge implements Edge { node: Activity! cursor: String + metadata: Metadata } input ActivityFilter { @@ -34,4 +36,4 @@ enum ActivityStatusValues { open, closed, in_progress -} \ No newline at end of file +} diff --git a/internal/api/graphql/graph/schema/common.graphqls b/internal/api/graphql/graph/schema/common.graphqls index 9a97275c..ee15d2b7 100644 --- a/internal/api/graphql/graph/schema/common.graphqls +++ b/internal/api/graphql/graph/schema/common.graphqls @@ -104,4 +104,12 @@ type FilterItem { displayName: String filterName: String values: [String] -} \ No newline at end of file +} + +type Metadata { + created_at: DateTime + created_by: String + deleted_at: DateTime + updated_at: DateTime + updated_by: String +} diff --git a/internal/api/graphql/graph/schema/component.graphqls b/internal/api/graphql/graph/schema/component.graphqls index 025601e1..302322da 100644 --- a/internal/api/graphql/graph/schema/component.graphqls +++ b/internal/api/graphql/graph/schema/component.graphqls @@ -6,6 +6,7 @@ type Component implements Node { ccrn: String type: ComponentTypeValues componentVersions(filter: ComponentVersionFilter, first: Int, after: String): ComponentVersionConnection + metadata: Metadata } input ComponentInput { @@ -32,4 +33,4 @@ type ComponentConnection implements Connection { type ComponentEdge implements Edge { node: Component! cursor: String -} \ No newline at end of file +} diff --git a/internal/api/graphql/graph/schema/component_instance.graphqls b/internal/api/graphql/graph/schema/component_instance.graphqls index 66d25d28..3d909907 100644 --- a/internal/api/graphql/graph/schema/component_instance.graphqls +++ b/internal/api/graphql/graph/schema/component_instance.graphqls @@ -10,8 +10,7 @@ type ComponentInstance implements Node { issueMatches(filter: IssueMatchFilter, first: Int, after: String): IssueMatchConnection serviceId: String service: Service - createdAt: DateTime - updatedAt: DateTime + metadata: Metadata } input ComponentInstanceInput { @@ -37,4 +36,4 @@ input ComponentInstanceFilter { ccrn: [String], supportGroup: [String], search:[String], -} \ No newline at end of file +} diff --git a/internal/api/graphql/graph/schema/component_version.graphqls b/internal/api/graphql/graph/schema/component_version.graphqls index 597292a5..36fe0026 100644 --- a/internal/api/graphql/graph/schema/component_version.graphqls +++ b/internal/api/graphql/graph/schema/component_version.graphqls @@ -8,6 +8,7 @@ type ComponentVersion implements Node { component: Component issues(first: Int, after: String): IssueConnection componentInstances(first: Int, after: String): ComponentInstanceConnection + metadata: Metadata } input ComponentVersionInput { @@ -31,4 +32,4 @@ input ComponentVersionFilter { componentCcrn: [String] issueId: [String] version: [String] -} \ No newline at end of file +} diff --git a/internal/api/graphql/graph/schema/evidence.graphqls b/internal/api/graphql/graph/schema/evidence.graphqls index 9f76a0ed..faee3485 100644 --- a/internal/api/graphql/graph/schema/evidence.graphqls +++ b/internal/api/graphql/graph/schema/evidence.graphqls @@ -13,6 +13,7 @@ type Evidence implements Node { activityId: String activity: Activity issueMatches(filter: IssueMatchFilter, first: Int, after: String): IssueMatchConnection + metadata: Metadata } input EvidenceInput { @@ -37,4 +38,4 @@ type EvidenceEdge implements Edge { input EvidenceFilter { placeholder: [Boolean] -} \ No newline at end of file +} diff --git a/internal/api/graphql/graph/schema/issue.graphqls b/internal/api/graphql/graph/schema/issue.graphqls index 5236b9f8..370f5a80 100644 --- a/internal/api/graphql/graph/schema/issue.graphqls +++ b/internal/api/graphql/graph/schema/issue.graphqls @@ -13,7 +13,8 @@ type Issue implements Node { activities(filter: ActivityFilter, first: Int, after: String): ActivityConnection issueMatches(filter: IssueMatchFilter, first: Int, after: String): IssueMatchConnection componentVersions(filter: ComponentVersionFilter, first: Int, after: String): ComponentVersionConnection - metadata: IssueMetadata + objectMetadata: IssueMetadata + metadata: Metadata } type IssueMetadata { diff --git a/internal/api/graphql/graph/schema/issue_match.graphqls b/internal/api/graphql/graph/schema/issue_match.graphqls index 5ca68780..70108ed7 100644 --- a/internal/api/graphql/graph/schema/issue_match.graphqls +++ b/internal/api/graphql/graph/schema/issue_match.graphqls @@ -17,6 +17,7 @@ type IssueMatch implements Node { componentInstanceId: String componentInstance: ComponentInstance! issueMatchChanges(filter: IssueMatchChangeFilter, first: Int, after: String): IssueMatchChangeConnection + metadata: Metadata } input IssueMatchInput { diff --git a/internal/api/graphql/graph/schema/issue_match_change.graphqls b/internal/api/graphql/graph/schema/issue_match_change.graphqls index 84724ac0..65385d01 100644 --- a/internal/api/graphql/graph/schema/issue_match_change.graphqls +++ b/internal/api/graphql/graph/schema/issue_match_change.graphqls @@ -9,6 +9,7 @@ type IssueMatchChange implements Node { issueMatch: IssueMatch! activityId: String activity: Activity! + metadata: Metadata } input IssueMatchChangeInput { diff --git a/internal/api/graphql/graph/schema/issue_repository.graphqls b/internal/api/graphql/graph/schema/issue_repository.graphqls index f34eef63..eb4cae34 100644 --- a/internal/api/graphql/graph/schema/issue_repository.graphqls +++ b/internal/api/graphql/graph/schema/issue_repository.graphqls @@ -7,8 +7,7 @@ type IssueRepository implements Node { url: String issueVariants(filter: IssueVariantFilter, first: Int, after: String): IssueVariantConnection services(filter: ServiceFilter, first: Int, after: String): ServiceConnection - created_at: DateTime - updated_at: DateTime + metadata: Metadata } input IssueRepositoryInput { @@ -26,12 +25,11 @@ type IssueRepositoryEdge implements Edge { node: IssueRepository! cursor: String priority: Int - created_at: DateTime - updated_at: DateTime + metadata: Metadata } input IssueRepositoryFilter { serviceCcrn: [String] serviceId: [String] name: [String] -} \ No newline at end of file +} diff --git a/internal/api/graphql/graph/schema/issue_variant.graphqls b/internal/api/graphql/graph/schema/issue_variant.graphqls index f6ffc280..8f688f65 100644 --- a/internal/api/graphql/graph/schema/issue_variant.graphqls +++ b/internal/api/graphql/graph/schema/issue_variant.graphqls @@ -10,8 +10,7 @@ type IssueVariant implements Node { issueRepository: IssueRepository issueId: String issue: Issue - created_at: DateTime - updated_at: DateTime + metadata: Metadata } input IssueVariantInput { @@ -31,10 +30,9 @@ type IssueVariantConnection implements Connection { type IssueVariantEdge implements Edge { node: IssueVariant! cursor: String - created_at: DateTime - updated_at: DateTime + metadata: Metadata } input IssueVariantFilter { secondaryName: [String] -} \ No newline at end of file +} diff --git a/internal/api/graphql/graph/schema/service.graphqls b/internal/api/graphql/graph/schema/service.graphqls index 219596da..2a36af8c 100644 --- a/internal/api/graphql/graph/schema/service.graphqls +++ b/internal/api/graphql/graph/schema/service.graphqls @@ -9,7 +9,9 @@ type Service implements Node { activities(filter: ActivityFilter, first: Int, after: String): ActivityConnection issueRepositories(filter: IssueRepositoryFilter, first: Int, after: String): IssueRepositoryConnection componentInstances(filter: ComponentInstanceFilter, first: Int, after: String): ComponentInstanceConnection - metadata: ServiceMetadata + objectMetadata: ServiceMetadata + metadata: Metadata + } type ServiceMetadata { diff --git a/internal/api/graphql/graph/schema/support_group.graphqls b/internal/api/graphql/graph/schema/support_group.graphqls index 90060247..b66d4e0f 100644 --- a/internal/api/graphql/graph/schema/support_group.graphqls +++ b/internal/api/graphql/graph/schema/support_group.graphqls @@ -6,6 +6,7 @@ type SupportGroup implements Node { ccrn: String users(filter: UserFilter, first: Int, after: String): UserConnection services(filter: ServiceFilter, first: Int, after: String): ServiceConnection + metadata: Metadata } input SupportGroupInput { @@ -26,4 +27,4 @@ type SupportGroupEdge implements Edge { input SupportGroupFilter { supportGroupCcrn: [String], userIds: [String], -} \ No newline at end of file +} diff --git a/internal/api/graphql/graph/schema/user.graphqls b/internal/api/graphql/graph/schema/user.graphqls index 91b7d12a..2cd19c19 100644 --- a/internal/api/graphql/graph/schema/user.graphqls +++ b/internal/api/graphql/graph/schema/user.graphqls @@ -8,6 +8,7 @@ type User implements Node { name: String supportGroups(filter: SupportGroupFilter, first: Int, after: String): SupportGroupConnection services(filter: ServiceFilter, first: Int, after: String): ServiceConnection + metadata: Metadata } input UserInput { diff --git a/internal/app/activity/activity_handler.go b/internal/app/activity/activity_handler.go index b85dd821..00b3d0bb 100644 --- a/internal/app/activity/activity_handler.go +++ b/internal/app/activity/activity_handler.go @@ -137,6 +137,13 @@ func (a *activityHandler) CreateActivity(activity *entity.Activity) (*entity.Act "object": activity, }) + var err error + activity.CreatedBy, err = common.GetCurrentUserId(a.database) + if err != nil { + l.Error(err) + return nil, NewActivityHandlerError("Internal error while creating activity (GetUserId).") + } + newActivity, err := a.database.CreateActivity(activity) if err != nil { @@ -157,7 +164,14 @@ func (a *activityHandler) UpdateActivity(activity *entity.Activity) (*entity.Act "object": activity, }) - err := a.database.UpdateActivity(activity) + var err error + activity.UpdatedBy, err = common.GetCurrentUserId(a.database) + if err != nil { + l.Error(err) + return nil, NewActivityHandlerError("Internal error while updating activity (GetUserId).") + } + + err = a.database.UpdateActivity(activity) if err != nil { l.Error(err) diff --git a/internal/app/activity/activity_handler_test.go b/internal/app/activity/activity_handler_test.go index 208970c7..f768d6fe 100644 --- a/internal/app/activity/activity_handler_test.go +++ b/internal/app/activity/activity_handler_test.go @@ -17,6 +17,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/samber/lo" + mock "github.com/stretchr/testify/mock" ) func TestActivityHandler(t *testing.T) { @@ -114,6 +115,7 @@ var _ = Describe("When creating Activity", Label("app", "CreateActivity"), func( }) It("creates activity", func() { + db.On("GetAllUserIds", mock.Anything).Return([]int64{}, nil) db.On("CreateActivity", &activity).Return(&activity, nil) activityHandler = a.NewActivityHandler(db, er) newActivity, err := activityHandler.CreateActivity(&activity) @@ -147,6 +149,7 @@ var _ = Describe("When updating Activity", Label("app", "UpdateService"), func() }) It("updates activity", func() { + db.On("GetAllUserIds", mock.Anything).Return([]int64{}, nil) db.On("UpdateActivity", &activity).Return(nil) activityHandler = a.NewActivityHandler(db, er) if activity.Status.String() == entity.ActivityStatusValuesOpen.String() { diff --git a/internal/app/common/user_id.go b/internal/app/common/user_id.go new file mode 100644 index 00000000..173dd0ba --- /dev/null +++ b/internal/app/common/user_id.go @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors +// SPDX-License-Identifier: Apache-2.0 + +package common + +import ( + "fmt" + + "github.com/cloudoperators/heureka/internal/database" + "github.com/cloudoperators/heureka/internal/entity" +) + +func GetCurrentUserId(db database.Database) (int64, error) { + return getUserIdFromDb(db, "S0000000") +} + +func getUserIdFromDb(db database.Database, uniqueUserId string) (int64, error) { + filter := &entity.UserFilter{UniqueUserID: []*string{&uniqueUserId}} + ids, err := db.GetAllUserIds(filter) + if err != nil { + return 0, fmt.Errorf("Unable to get user ids %w", err) + } else if len(ids) < 1 { + return 0, nil + } + return ids[0], nil +} diff --git a/internal/app/component/component_handler.go b/internal/app/component/component_handler.go index 6afae4e8..975635c6 100644 --- a/internal/app/component/component_handler.go +++ b/internal/app/component/component_handler.go @@ -115,6 +115,13 @@ func (cs *componentHandler) CreateComponent(component *entity.Component) (*entit "filter": f, }) + var err error + component.CreatedBy, err = common.GetCurrentUserId(cs.database) + if err != nil { + l.Error(err) + return nil, NewUserHandlerError("Internal error while creating component (GetUserId).") + } + components, err := cs.ListComponents(f, &entity.ListOptions{}) if err != nil { @@ -144,7 +151,14 @@ func (cs *componentHandler) UpdateComponent(component *entity.Component) (*entit "object": component, }) - err := cs.database.UpdateComponent(component) + var err error + component.UpdatedBy, err = common.GetCurrentUserId(cs.database) + if err != nil { + l.Error(err) + return nil, NewUserHandlerError("Internal error while updating component (GetUserId).") + } + + err = cs.database.UpdateComponent(component) if err != nil { l.Error(err) diff --git a/internal/app/component/component_handler_test.go b/internal/app/component/component_handler_test.go index 335337d1..4dee1a12 100644 --- a/internal/app/component/component_handler_test.go +++ b/internal/app/component/component_handler_test.go @@ -16,6 +16,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/samber/lo" + mock "github.com/stretchr/testify/mock" ) func TestComponentHandler(t *testing.T) { @@ -125,6 +126,7 @@ var _ = Describe("When creating Component", Label("app", "CreateComponent"), fun It("creates component", func() { filter.CCRN = []*string{&component.CCRN} + db.On("GetAllUserIds", mock.Anything).Return([]int64{}, nil) db.On("CreateComponent", &component).Return(&component, nil) db.On("GetComponents", filter).Return([]entity.Component{}, nil) componentHandler = c.NewComponentHandler(db, er) @@ -161,6 +163,7 @@ var _ = Describe("When updating Component", Label("app", "UpdateComponent"), fun }) It("updates component", func() { + db.On("GetAllUserIds", mock.Anything).Return([]int64{}, nil) db.On("UpdateComponent", &component).Return(nil) componentHandler = c.NewComponentHandler(db, er) component.CCRN = "NewComponent" diff --git a/internal/app/component_instance/component_instance_handler.go b/internal/app/component_instance/component_instance_handler.go index 446a157b..129c361d 100644 --- a/internal/app/component_instance/component_instance_handler.go +++ b/internal/app/component_instance/component_instance_handler.go @@ -116,6 +116,13 @@ func (ci *componentInstanceHandler) CreateComponentInstance(componentInstance *e "object": componentInstance, }) + var err error + componentInstance.CreatedBy, err = common.GetCurrentUserId(ci.database) + if err != nil { + l.Error(err) + return nil, NewComponentInstanceHandlerError("Internal error while creating componentInstance (GetUserId).") + } + newComponentInstance, err := ci.database.CreateComponentInstance(componentInstance) if err != nil { @@ -136,7 +143,14 @@ func (ci *componentInstanceHandler) UpdateComponentInstance(componentInstance *e "object": componentInstance, }) - err := ci.database.UpdateComponentInstance(componentInstance) + var err error + componentInstance.UpdatedBy, err = common.GetCurrentUserId(ci.database) + if err != nil { + l.Error(err) + return nil, NewComponentInstanceHandlerError("Internal error while updating componentInstance (GetUserId).") + } + + err = ci.database.UpdateComponentInstance(componentInstance) if err != nil { l.Error(err) diff --git a/internal/app/component_instance/component_instance_handler_test.go b/internal/app/component_instance/component_instance_handler_test.go index e87dccd5..a5a1d470 100644 --- a/internal/app/component_instance/component_instance_handler_test.go +++ b/internal/app/component_instance/component_instance_handler_test.go @@ -15,6 +15,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/samber/lo" + mock "github.com/stretchr/testify/mock" ) func TestComponentInstanceHandler(t *testing.T) { @@ -121,6 +122,7 @@ var _ = Describe("When creating ComponentInstance", Label("app", "CreateComponen }) It("creates componentInstance", func() { + db.On("GetAllUserIds", mock.Anything).Return([]int64{}, nil) db.On("CreateComponentInstance", &componentInstance).Return(&componentInstance, nil) componentInstanceHandler = ci.NewComponentInstanceHandler(db, er) newComponentInstance, err := componentInstanceHandler.CreateComponentInstance(&componentInstance) @@ -158,6 +160,7 @@ var _ = Describe("When updating ComponentInstance", Label("app", "UpdateComponen }) It("updates componentInstance", func() { + db.On("GetAllUserIds", mock.Anything).Return([]int64{}, nil) db.On("UpdateComponentInstance", &componentInstance).Return(nil) componentInstanceHandler = ci.NewComponentInstanceHandler(db, er) componentInstance.CCRN = "NewCCRN" diff --git a/internal/app/component_version/component_version_handler.go b/internal/app/component_version/component_version_handler.go index 47cadc33..1ae6b932 100644 --- a/internal/app/component_version/component_version_handler.go +++ b/internal/app/component_version/component_version_handler.go @@ -114,6 +114,13 @@ func (cv *componentVersionHandler) CreateComponentVersion(componentVersion *enti "object": componentVersion, }) + var err error + componentVersion.CreatedBy, err = common.GetCurrentUserId(cv.database) + if err != nil { + l.Error(err) + return nil, NewComponentVersionHandlerError("Internal error while creating componentVersion (GetUserId).") + } + newComponent, err := cv.database.CreateComponentVersion(componentVersion) if err != nil { @@ -138,7 +145,14 @@ func (cv *componentVersionHandler) UpdateComponentVersion(componentVersion *enti "object": componentVersion, }) - err := cv.database.UpdateComponentVersion(componentVersion) + var err error + componentVersion.UpdatedBy, err = common.GetCurrentUserId(cv.database) + if err != nil { + l.Error(err) + return nil, NewComponentVersionHandlerError("Internal error while updating componentVersion (GetUserId).") + } + + err = cv.database.UpdateComponentVersion(componentVersion) if err != nil { l.Error(err) diff --git a/internal/app/component_version/component_version_handler_test.go b/internal/app/component_version/component_version_handler_test.go index 88d31e00..71c948b3 100644 --- a/internal/app/component_version/component_version_handler_test.go +++ b/internal/app/component_version/component_version_handler_test.go @@ -15,6 +15,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/samber/lo" + mock "github.com/stretchr/testify/mock" ) func TestComponentVersionHandler(t *testing.T) { @@ -111,6 +112,7 @@ var _ = Describe("When creating ComponentVersion", Label("app", "CreateComponent }) It("creates componentVersion", func() { + db.On("GetAllUserIds", mock.Anything).Return([]int64{}, nil) db.On("CreateComponentVersion", &componentVersion).Return(&componentVersion, nil) componenVersionService = cv.NewComponentVersionHandler(db, er) newComponentVersion, err := componenVersionService.CreateComponentVersion(&componentVersion) @@ -146,6 +148,7 @@ var _ = Describe("When updating ComponentVersion", Label("app", "UpdateComponent }) It("updates componentVersion", func() { + db.On("GetAllUserIds", mock.Anything).Return([]int64{}, nil) db.On("UpdateComponentVersion", &componentVersion).Return(nil) componenVersionService = cv.NewComponentVersionHandler(db, er) componentVersion.Version = "7.3.3.1" diff --git a/internal/app/evidence/evidence_handler.go b/internal/app/evidence/evidence_handler.go index f3a8eb21..6363d608 100644 --- a/internal/app/evidence/evidence_handler.go +++ b/internal/app/evidence/evidence_handler.go @@ -109,6 +109,13 @@ func (e *evidenceHandler) CreateEvidence(evidence *entity.Evidence) (*entity.Evi "object": evidence, }) + var err error + evidence.CreatedBy, err = common.GetCurrentUserId(e.database) + if err != nil { + l.Error(err) + return nil, NewEvidenceHandlerError("Internal error while creating evidence (GetUserId).") + } + newEvidence, err := e.database.CreateEvidence(evidence) if err != nil { @@ -127,7 +134,14 @@ func (e *evidenceHandler) UpdateEvidence(evidence *entity.Evidence) (*entity.Evi "object": evidence, }) - err := e.database.UpdateEvidence(evidence) + var err error + evidence.UpdatedBy, err = common.GetCurrentUserId(e.database) + if err != nil { + l.Error(err) + return nil, NewEvidenceHandlerError("Internal error while updating evidence (GetUserId).") + } + + err = e.database.UpdateEvidence(evidence) if err != nil { l.Error(err) diff --git a/internal/app/evidence/evidence_handler_test.go b/internal/app/evidence/evidence_handler_test.go index abad38df..1c2c5dbd 100644 --- a/internal/app/evidence/evidence_handler_test.go +++ b/internal/app/evidence/evidence_handler_test.go @@ -15,6 +15,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/samber/lo" + mock "github.com/stretchr/testify/mock" ) func TestEvidenceHandler(t *testing.T) { @@ -119,6 +120,7 @@ var _ = Describe("When creating Evidence", Label("app", "CreateEvidence"), func( }) It("creates evidence", func() { + db.On("GetAllUserIds", mock.Anything).Return([]int64{}, nil) db.On("CreateEvidence", &evidence).Return(&evidence, nil) evidenceHandler = es.NewEvidenceHandler(db, er) newEvidence, err := evidenceHandler.CreateEvidence(&evidence) @@ -158,6 +160,7 @@ var _ = Describe("When updating Evidence", Label("app", "UpdateEvidence"), func( }) It("updates evidence", func() { + db.On("GetAllUserIds", mock.Anything).Return([]int64{}, nil) db.On("UpdateEvidence", &evidence).Return(nil) evidenceHandler = es.NewEvidenceHandler(db, er) evidence.Description = "New Description" diff --git a/internal/app/issue/issue_handler.go b/internal/app/issue/issue_handler.go index 2c5aae5f..be19aff1 100644 --- a/internal/app/issue/issue_handler.go +++ b/internal/app/issue/issue_handler.go @@ -170,6 +170,13 @@ func (is *issueHandler) CreateIssue(issue *entity.Issue) (*entity.Issue, error) "filter": f, }) + var err error + issue.CreatedBy, err = common.GetCurrentUserId(is.database) + if err != nil { + l.Error(err) + return nil, NewIssueHandlerError("Internal error while creating issue (GetUserId).") + } + issues, err := is.ListIssues(f, &entity.IssueListOptions{}) if err != nil { @@ -198,7 +205,14 @@ func (is *issueHandler) UpdateIssue(issue *entity.Issue) (*entity.Issue, error) "object": issue, }) - err := is.database.UpdateIssue(issue) + var err error + issue.UpdatedBy, err = common.GetCurrentUserId(is.database) + if err != nil { + l.Error(err) + return nil, NewIssueHandlerError("Internal error while updating issue (GetUserId).") + } + + err = is.database.UpdateIssue(issue) if err != nil { l.Error(err) diff --git a/internal/app/issue/issue_handler_test.go b/internal/app/issue/issue_handler_test.go index 3ea773da..76100094 100644 --- a/internal/app/issue/issue_handler_test.go +++ b/internal/app/issue/issue_handler_test.go @@ -16,6 +16,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/samber/lo" + mock "github.com/stretchr/testify/mock" ) func TestIssueHandler(t *testing.T) { @@ -238,6 +239,7 @@ var _ = Describe("When creating Issue", Label("app", "CreateIssue"), func() { It("creates issue", func() { filter.PrimaryName = []*string{&issueEntity.PrimaryName} + db.On("GetAllUserIds", mock.Anything).Return([]int64{}, nil) db.On("CreateIssue", &issueEntity).Return(&issueEntity, nil) db.On("GetIssues", filter).Return([]entity.Issue{}, nil) issueHandler = issue.NewIssueHandler(db, er) @@ -275,6 +277,7 @@ var _ = Describe("When updating Issue", Label("app", "UpdateIssue"), func() { }) It("updates issueEntity", func() { + db.On("GetAllUserIds", mock.Anything).Return([]int64{}, nil) db.On("UpdateIssue", &issueEntity).Return(nil) issueHandler = issue.NewIssueHandler(db, er) issueEntity.Description = "New Description" diff --git a/internal/app/issue_match/issue_match_handler.go b/internal/app/issue_match/issue_match_handler.go index 49f4de05..834a0fb8 100644 --- a/internal/app/issue_match/issue_match_handler.go +++ b/internal/app/issue_match/issue_match_handler.go @@ -141,6 +141,13 @@ func (im *issueMatchHandler) CreateIssueMatch(issueMatch *entity.IssueMatch) (*e "object": issueMatch, }) + var err error + issueMatch.CreatedBy, err = common.GetCurrentUserId(im.database) + if err != nil { + l.Error(err) + return nil, NewIssueMatchHandlerError("Internal error while retrieving effective severity (GetUserId).") + } + severityFilter := &entity.SeverityFilter{ IssueId: []*int64{&issueMatch.IssueId}, } @@ -175,7 +182,14 @@ func (im *issueMatchHandler) UpdateIssueMatch(issueMatch *entity.IssueMatch) (*e "object": issueMatch, }) - err := im.database.UpdateIssueMatch(issueMatch) + var err error + issueMatch.UpdatedBy, err = common.GetCurrentUserId(im.database) + if err != nil { + l.Error(err) + return nil, NewIssueMatchHandlerError("Internal error while retrieving effective severity (GetUserId).") + } + + err = im.database.UpdateIssueMatch(issueMatch) if err != nil { l.Error(err) diff --git a/internal/app/issue_match/issue_match_handler_test.go b/internal/app/issue_match/issue_match_handler_test.go index 9f10e321..5155e289 100644 --- a/internal/app/issue_match/issue_match_handler_test.go +++ b/internal/app/issue_match/issue_match_handler_test.go @@ -196,6 +196,7 @@ var _ = Describe("When creating IssueMatch", Label("app", "CreateIssueMatch"), f irFilter.Id = []*int64{&repositories[0].Id} ivFilter.IssueId = []*int64{&issueMatch.IssueId} issueMatch.Severity = issueVariants[0].Severity + db.On("GetAllUserIds", mock.Anything).Return([]int64{}, nil) db.On("CreateIssueMatch", &issueMatch).Return(&issueMatch, nil) db.On("GetIssueVariants", ivFilter).Return(issueVariants, nil) db.On("GetIssueRepositories", irFilter).Return(repositories, nil) @@ -240,6 +241,7 @@ var _ = Describe("When updating IssueMatch", Label("app", "UpdateIssueMatch"), f }) It("updates issueMatch", func() { + db.On("GetAllUserIds", mock.Anything).Return([]int64{}, nil) db.On("UpdateIssueMatch", &issueMatch).Return(nil) issueMatchHandler = im.NewIssueMatchHandler(db, er, nil) if issueMatch.Status == entity.NewIssueMatchStatusValue("new") { diff --git a/internal/app/issue_match_change/issue_match_change_handler.go b/internal/app/issue_match_change/issue_match_change_handler.go index 876a235c..e2b32ef0 100644 --- a/internal/app/issue_match_change/issue_match_change_handler.go +++ b/internal/app/issue_match_change/issue_match_change_handler.go @@ -113,6 +113,13 @@ func (imc *issueMatchChangeHandler) CreateIssueMatchChange(issueMatchChange *ent "object": issueMatchChange, }) + var err error + issueMatchChange.CreatedBy, err = common.GetCurrentUserId(imc.database) + if err != nil { + l.Error(err) + return nil, NewIssueMatchChangeHandlerError("Internal error while creating issueMatchChange (GetUserId).") + } + newIssueMatchChange, err := imc.database.CreateIssueMatchChange(issueMatchChange) if err != nil { @@ -133,7 +140,14 @@ func (imc *issueMatchChangeHandler) UpdateIssueMatchChange(issueMatchChange *ent "object": issueMatchChange, }) - err := imc.database.UpdateIssueMatchChange(issueMatchChange) + var err error + issueMatchChange.UpdatedBy, err = common.GetCurrentUserId(imc.database) + if err != nil { + l.Error(err) + return nil, NewIssueMatchChangeHandlerError("Internal error while updating issueMatchChange (GetUserId).") + } + + err = imc.database.UpdateIssueMatchChange(issueMatchChange) if err != nil { l.Error(err) diff --git a/internal/app/issue_match_change/issue_match_change_handler_test.go b/internal/app/issue_match_change/issue_match_change_handler_test.go index 6d1e7705..48ffc9a7 100644 --- a/internal/app/issue_match_change/issue_match_change_handler_test.go +++ b/internal/app/issue_match_change/issue_match_change_handler_test.go @@ -15,6 +15,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/samber/lo" + mock "github.com/stretchr/testify/mock" ) func TestIssueHandler(t *testing.T) { @@ -115,6 +116,7 @@ var _ = Describe("When creating IssueMatchChange", Label("app", "CreateIssueMatc }) It("creates issueMatchChange", func() { + db.On("GetAllUserIds", mock.Anything).Return([]int64{}, nil) db.On("CreateIssueMatchChange", &issueMatchChange).Return(&issueMatchChange, nil) issueMatchChangeHandler = imc.NewIssueMatchChangeHandler(db, er) newIssueMatchChange, err := issueMatchChangeHandler.CreateIssueMatchChange(&issueMatchChange) @@ -149,6 +151,7 @@ var _ = Describe("When updating IssueMatchChange", Label("app", "UpdateIssueMatc }) It("updates issueMatchChange", func() { + db.On("GetAllUserIds", mock.Anything).Return([]int64{}, nil) db.On("UpdateIssueMatchChange", &issueMatchChange).Return(nil) issueMatchChangeHandler = imc.NewIssueMatchChangeHandler(db, er) if issueMatchChange.Action == entity.IssueMatchChangeActionAdd.String() { diff --git a/internal/app/issue_repository/issue_repository_handler.go b/internal/app/issue_repository/issue_repository_handler.go index bc38f1b7..f6e4fded 100644 --- a/internal/app/issue_repository/issue_repository_handler.go +++ b/internal/app/issue_repository/issue_repository_handler.go @@ -112,6 +112,13 @@ func (ir *issueRepositoryHandler) CreateIssueRepository(issueRepository *entity. "filter": f, }) + var err error + issueRepository.BaseIssueRepository.CreatedBy, err = common.GetCurrentUserId(ir.database) + if err != nil { + l.Error(err) + return nil, NewIssueRepositoryHandlerError("Internal error while creating issueRepository (GetUserId).") + } + issueRepositories, err := ir.ListIssueRepositories(f, &entity.ListOptions{}) if err != nil { @@ -142,7 +149,14 @@ func (ir *issueRepositoryHandler) UpdateIssueRepository(issueRepository *entity. "object": issueRepository, }) - err := ir.database.UpdateIssueRepository(issueRepository) + var err error + issueRepository.BaseIssueRepository.UpdatedBy, err = common.GetCurrentUserId(ir.database) + if err != nil { + l.Error(err) + return nil, NewIssueRepositoryHandlerError("Internal error while updating issueRepository (GetUserId).") + } + + err = ir.database.UpdateIssueRepository(issueRepository) if err != nil { l.Error(err) diff --git a/internal/app/issue_repository/issue_repository_handler_events.go b/internal/app/issue_repository/issue_repository_handler_events.go index ccc0e3f0..a64b8203 100644 --- a/internal/app/issue_repository/issue_repository_handler_events.go +++ b/internal/app/issue_repository/issue_repository_handler_events.go @@ -4,10 +4,10 @@ package issue_repository import ( - "github.com/sirupsen/logrus" "github.com/cloudoperators/heureka/internal/app/event" "github.com/cloudoperators/heureka/internal/database" "github.com/cloudoperators/heureka/internal/entity" + "github.com/sirupsen/logrus" ) const ( diff --git a/internal/app/issue_repository/issue_repository_handler_test.go b/internal/app/issue_repository/issue_repository_handler_test.go index 2a22fb57..70e1cb60 100644 --- a/internal/app/issue_repository/issue_repository_handler_test.go +++ b/internal/app/issue_repository/issue_repository_handler_test.go @@ -15,6 +15,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/samber/lo" + mock "github.com/stretchr/testify/mock" ) func TestIssueRepositoryHandler(t *testing.T) { @@ -132,6 +133,7 @@ var _ = Describe("When creating IssueRepository", Label("app", "CreateIssueRepos It("creates issueRepository", func() { filter.Name = []*string{&issueRepository.Name} + db.On("GetAllUserIds", mock.Anything).Return([]int64{}, nil) db.On("CreateIssueRepository", &issueRepository).Return(&issueRepository, nil) db.On("GetIssueRepositories", filter).Return([]entity.IssueRepository{}, nil) issueRepositoryHandler = ir.NewIssueRepositoryHandler(db, er) @@ -192,6 +194,7 @@ var _ = Describe("When updating IssueRepository", Label("app", "UpdateIssueRepos }) It("updates issueRepository", func() { + db.On("GetAllUserIds", mock.Anything).Return([]int64{}, nil) db.On("UpdateIssueRepository", &issueRepository).Return(nil) issueRepositoryHandler = ir.NewIssueRepositoryHandler(db, er) issueRepository.Name = "SecretRepository" diff --git a/internal/app/issue_variant/issue_variant_handler.go b/internal/app/issue_variant/issue_variant_handler.go index 6ac751e8..7f8bfd1f 100644 --- a/internal/app/issue_variant/issue_variant_handler.go +++ b/internal/app/issue_variant/issue_variant_handler.go @@ -178,6 +178,13 @@ func (iv *issueVariantHandler) CreateIssueVariant(issueVariant *entity.IssueVari "filter": f, }) + var err error + issueVariant.CreatedBy, err = common.GetCurrentUserId(iv.database) + if err != nil { + l.Error(err) + return nil, NewIssueVariantHandlerError("Internal error while creating issueVariant (GetUserId).") + } + issueVariants, err := iv.ListIssueVariants(f, &entity.ListOptions{}) if err != nil { @@ -208,7 +215,14 @@ func (iv *issueVariantHandler) UpdateIssueVariant(issueVariant *entity.IssueVari "object": issueVariant, }) - err := iv.database.UpdateIssueVariant(issueVariant) + var err error + issueVariant.UpdatedBy, err = common.GetCurrentUserId(iv.database) + if err != nil { + l.Error(err) + return nil, NewIssueVariantHandlerError("Internal error while updating issueVariant (GetUserId).") + } + + err = iv.database.UpdateIssueVariant(issueVariant) if err != nil { l.Error(err) diff --git a/internal/app/issue_variant/issue_variant_handler_test.go b/internal/app/issue_variant/issue_variant_handler_test.go index 8c2b620a..12190e1f 100644 --- a/internal/app/issue_variant/issue_variant_handler_test.go +++ b/internal/app/issue_variant/issue_variant_handler_test.go @@ -16,6 +16,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/samber/lo" + mock "github.com/stretchr/testify/mock" ) func TestIssueVariantHandler(t *testing.T) { @@ -230,6 +231,7 @@ var _ = Describe("When creating IssueVariant", Label("app", "CreateIssueVariant" It("creates issueVariant", func() { filter.SecondaryName = []*string{&issueVariant.SecondaryName} + db.On("GetAllUserIds", mock.Anything).Return([]int64{}, nil) db.On("CreateIssueVariant", &issueVariant).Return(&issueVariant, nil) db.On("GetIssueVariants", filter).Return([]entity.IssueVariant{}, nil) issueVariantHandler = iv.NewIssueVariantHandler(db, er, rs) @@ -273,6 +275,7 @@ var _ = Describe("When updating IssueVariant", Label("app", "UpdateIssueVariant" }) It("updates issueVariant", func() { + db.On("GetAllUserIds", mock.Anything).Return([]int64{}, nil) db.On("UpdateIssueVariant", &issueVariant).Return(nil) issueVariantHandler = iv.NewIssueVariantHandler(db, er, rs) issueVariant.SecondaryName = "SecretAdvisory" diff --git a/internal/app/service/service_handler.go b/internal/app/service/service_handler.go index 8429cbf1..72a31f72 100644 --- a/internal/app/service/service_handler.go +++ b/internal/app/service/service_handler.go @@ -164,6 +164,13 @@ func (s *serviceHandler) CreateService(service *entity.Service) (*entity.Service "filter": f, }) + var err error + service.BaseService.CreatedBy, err = common.GetCurrentUserId(s.database) + if err != nil { + l.Error(err) + return nil, NewServiceHandlerError("Internal error while creating service (GetUserId).") + } + services, err := s.ListServices(f, &entity.ListOptions{}) if err != nil { @@ -193,7 +200,14 @@ func (s *serviceHandler) UpdateService(service *entity.Service) (*entity.Service "object": service, }) - err := s.database.UpdateService(service) + var err error + service.BaseService.UpdatedBy, err = common.GetCurrentUserId(s.database) + if err != nil { + l.Error(err) + return nil, NewServiceHandlerError("Internal error while updating service (GetUserId).") + } + + err = s.database.UpdateService(service) if err != nil { l.Error(err) diff --git a/internal/app/service/service_handler_test.go b/internal/app/service/service_handler_test.go index a3690bca..74de1554 100644 --- a/internal/app/service/service_handler_test.go +++ b/internal/app/service/service_handler_test.go @@ -18,6 +18,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/samber/lo" + mock "github.com/stretchr/testify/mock" ) func TestServiceHandler(t *testing.T) { @@ -225,6 +226,7 @@ var _ = Describe("When creating Service", Label("app", "CreateService"), func() It("creates service", func() { filter.CCRN = []*string{&service.CCRN} + db.On("GetAllUserIds", mock.Anything).Return([]int64{}, nil) db.On("CreateService", &service).Return(&service, nil) db.On("GetServices", filter).Return([]entity.Service{}, nil) @@ -335,6 +337,7 @@ var _ = Describe("When updating Service", Label("app", "UpdateService"), func() }) It("updates service", func() { + db.On("GetAllUserIds", mock.Anything).Return([]int64{}, nil) db.On("UpdateService", &service).Return(nil) serviceHandler = s.NewServiceHandler(db, er) service.CCRN = "SecretService" diff --git a/internal/app/support_group/support_group_handler.go b/internal/app/support_group/support_group_handler.go index 47b6e316..7c3e68c6 100644 --- a/internal/app/support_group/support_group_handler.go +++ b/internal/app/support_group/support_group_handler.go @@ -142,6 +142,13 @@ func (sg *supportGroupHandler) CreateSupportGroup(supportGroup *entity.SupportGr CCRN: []*string{&supportGroup.CCRN}, } + var err error + supportGroup.CreatedBy, err = common.GetCurrentUserId(sg.database) + if err != nil { + l.Error(err) + return nil, NewSupportGroupHandlerError("Internal error while creating supportGroup (GetUserId).") + } + supportGroups, err := sg.ListSupportGroups(f, &entity.ListOptions{}) if err != nil { @@ -173,7 +180,14 @@ func (sg *supportGroupHandler) UpdateSupportGroup(supportGroup *entity.SupportGr "object": supportGroup, }) - err := sg.database.UpdateSupportGroup(supportGroup) + var err error + supportGroup.UpdatedBy, err = common.GetCurrentUserId(sg.database) + if err != nil { + l.Error(err) + return nil, NewSupportGroupHandlerError("Internal error while updating supportGroup (GetUserId).") + } + + err = sg.database.UpdateSupportGroup(supportGroup) if err != nil { l.Error(err) diff --git a/internal/app/support_group/support_group_handler_test.go b/internal/app/support_group/support_group_handler_test.go index 859ddacd..9c622bcc 100644 --- a/internal/app/support_group/support_group_handler_test.go +++ b/internal/app/support_group/support_group_handler_test.go @@ -15,6 +15,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/samber/lo" + mock "github.com/stretchr/testify/mock" ) func TestSupportGroupHandler(t *testing.T) { @@ -122,6 +123,7 @@ var _ = Describe("When creating SupportGroup", Label("app", "CreateSupportGroup" It("creates supportGroup", func() { filter.CCRN = []*string{&supportGroup.CCRN} + db.On("GetAllUserIds", mock.Anything).Return([]int64{}, nil) db.On("CreateSupportGroup", &supportGroup).Return(&supportGroup, nil) db.On("GetSupportGroups", filter).Return([]entity.SupportGroup{}, nil) supportGroupHandler = sg.NewSupportGroupHandler(db, er) @@ -157,6 +159,7 @@ var _ = Describe("When updating SupportGroup", Label("app", "UpdateSupportGroup" }) It("updates supportGroup", func() { + db.On("GetAllUserIds", mock.Anything).Return([]int64{}, nil) db.On("UpdateSupportGroup", &supportGroup).Return(nil) supportGroupHandler = sg.NewSupportGroupHandler(db, er) supportGroup.CCRN = "Team Alone" diff --git a/internal/app/user/user_handler.go b/internal/app/user/user_handler.go index 19abd432..e8ad6461 100644 --- a/internal/app/user/user_handler.go +++ b/internal/app/user/user_handler.go @@ -112,6 +112,13 @@ func (u *userHandler) CreateUser(user *entity.User) (*entity.User, error) { "object": user, }) + var err error + user.CreatedBy, err = common.GetCurrentUserId(u.database) + if err != nil { + l.Error(err) + return nil, NewUserHandlerError("Internal error while creating user (GetUserId).") + } + users, err := u.ListUsers(f, &entity.ListOptions{}) if err != nil { @@ -141,7 +148,14 @@ func (u *userHandler) UpdateUser(user *entity.User) (*entity.User, error) { "object": user, }) - err := u.database.UpdateUser(user) + var err error + user.UpdatedBy, err = common.GetCurrentUserId(u.database) + if err != nil { + l.Error(err) + return nil, NewUserHandlerError("Internal error while updating user (GetUserId).") + } + + err = u.database.UpdateUser(user) if err != nil { l.Error(err) diff --git a/internal/app/user/user_handler_test.go b/internal/app/user/user_handler_test.go index 582c47e6..106ff4cd 100644 --- a/internal/app/user/user_handler_test.go +++ b/internal/app/user/user_handler_test.go @@ -15,6 +15,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/samber/lo" + mock "github.com/stretchr/testify/mock" ) func TestUserHandler(t *testing.T) { @@ -125,6 +126,7 @@ var _ = Describe("When creating User", Label("app", "CreateUser"), func() { It("creates user", func() { filter.UniqueUserID = []*string{&user.UniqueUserID} + db.On("GetAllUserIds", mock.Anything).Return([]int64{}, nil) db.On("CreateUser", &user).Return(&user, nil) db.On("GetUsers", filter).Return([]entity.User{}, nil) userHandler = u.NewUserHandler(db, er) @@ -161,6 +163,7 @@ var _ = Describe("When updating User", Label("app", "UpdateUser"), func() { }) It("updates user", func() { + db.On("GetAllUserIds", mock.Anything).Return([]int64{}, nil) db.On("UpdateUser", &user).Return(nil) userHandler = u.NewUserHandler(db, er) user.Name = "Sauron" diff --git a/internal/database/mariadb/activity.go b/internal/database/mariadb/activity.go index 4f6e1c5f..2dd69c64 100644 --- a/internal/database/mariadb/activity.go +++ b/internal/database/mariadb/activity.go @@ -68,6 +68,9 @@ func (s *SqlDatabase) getActivityUpdateFields(activity *entity.Activity) string if activity.Status != "" { fl = append(fl, "activity_status = :activity_status") } + if activity.UpdatedBy != 0 { + fl = append(fl, "activity_updated_by = :activity_updated_by") + } return strings.Join(fl, ", ") } @@ -208,9 +211,11 @@ func (s *SqlDatabase) CreateActivity(activity *entity.Activity) (*entity.Activit query := ` INSERT INTO Activity ( - activity_status + activity_status, + activity_created_by ) VALUES ( - :activity_status + :activity_status, + :activity_created_by ) ` diff --git a/internal/database/mariadb/component.go b/internal/database/mariadb/component.go index cffb0c87..ddfc1601 100644 --- a/internal/database/mariadb/component.go +++ b/internal/database/mariadb/component.go @@ -64,6 +64,9 @@ func (s *SqlDatabase) getComponentUpdateFields(component *entity.Component) stri if component.Type != "" { fl = append(fl, "component_type = :component_type") } + if component.UpdatedBy != 0 { + fl = append(fl, "component_updated_by = :component_updated_by") + } return strings.Join(fl, ", ") } @@ -202,10 +205,12 @@ func (s *SqlDatabase) CreateComponent(component *entity.Component) (*entity.Comp query := ` INSERT INTO Component ( component_ccrn, - component_type + component_type, + component_created_by ) VALUES ( :component_ccrn, - :component_type + :component_type, + :component_created_by ) ` diff --git a/internal/database/mariadb/component_instance.go b/internal/database/mariadb/component_instance.go index 3b965aa1..a2e66202 100644 --- a/internal/database/mariadb/component_instance.go +++ b/internal/database/mariadb/component_instance.go @@ -80,6 +80,10 @@ func (s *SqlDatabase) getComponentInstanceUpdateFields(componentInstance *entity if componentInstance.ServiceId != 0 { fl = append(fl, "componentinstance_service_id = :componentinstance_service_id") } + if componentInstance.UpdatedBy != 0 { + fl = append(fl, "componentinstance_updated_by = :componentinstance_updated_by") + } + return strings.Join(fl, ", ") } @@ -223,12 +227,14 @@ func (s *SqlDatabase) CreateComponentInstance(componentInstance *entity.Componen componentinstance_ccrn, componentinstance_count, componentinstance_component_version_id, - componentinstance_service_id + componentinstance_service_id, + componentinstance_created_by ) VALUES ( :componentinstance_ccrn, :componentinstance_count, :componentinstance_component_version_id, - :componentinstance_service_id + :componentinstance_service_id, + :componentinstance_created_by ) ` diff --git a/internal/database/mariadb/component_version.go b/internal/database/mariadb/component_version.go index 8f4ec7b5..4fc5e661 100644 --- a/internal/database/mariadb/component_version.go +++ b/internal/database/mariadb/component_version.go @@ -57,6 +57,9 @@ func (s *SqlDatabase) getComponentVersionUpdateFields(componentVersion *entity.C if componentVersion.ComponentId != 0 { fl = append(fl, "componentversion_component_id = :componentversion_component_id") } + if componentVersion.UpdatedBy != 0 { + fl = append(fl, "componentversion_updated_by = :componentversion_updated_by") + } return strings.Join(fl, ", ") } @@ -209,10 +212,12 @@ func (s *SqlDatabase) CreateComponentVersion(componentVersion *entity.ComponentV query := ` INSERT INTO ComponentVersion ( componentversion_component_id, - componentversion_version + componentversion_version, + componentversion_created_by ) VALUES ( :componentversion_component_id, - :componentversion_version + :componentversion_version, + :componentversion_created_by ) ` diff --git a/internal/database/mariadb/entity.go b/internal/database/mariadb/entity.go index c03c5577..0f9f78e8 100644 --- a/internal/database/mariadb/entity.go +++ b/internal/database/mariadb/entity.go @@ -87,8 +87,10 @@ type IssueRow struct { PrimaryName sql.NullString `db:"issue_primary_name" json:"primary_name"` Description sql.NullString `db:"issue_description" json:"description"` CreatedAt sql.NullTime `db:"issue_created_at" json:"created_at"` + CreatedBy sql.NullInt64 `db:"issue_created_by" json:"created_by"` DeletedAt sql.NullTime `db:"issue_deleted_at" json:"deleted_at,omitempty"` UpdatedAt sql.NullTime `db:"issue_updated_at" json:"updated_at"` + UpdatedBy sql.NullInt64 `db:"issue_updated_by" json:"updated_by"` } func (ir *IssueRow) AsIssue() entity.Issue { @@ -100,9 +102,13 @@ func (ir *IssueRow) AsIssue() entity.Issue { IssueVariants: []entity.IssueVariant{}, IssueMatches: []entity.IssueMatch{}, Activity: []entity.Activity{}, - CreatedAt: GetTimeValue(ir.CreatedAt), - DeletedAt: GetTimeValue(ir.DeletedAt), - UpdatedAt: GetTimeValue(ir.UpdatedAt), + Metadata: entity.Metadata{ + CreatedAt: GetTimeValue(ir.CreatedAt), + CreatedBy: GetInt64Value(ir.CreatedBy), + DeletedAt: GetTimeValue(ir.DeletedAt), + UpdatedAt: GetTimeValue(ir.UpdatedAt), + UpdatedBy: GetInt64Value(ir.UpdatedBy), + }, } } @@ -140,9 +146,13 @@ func (ibr *GetIssuesByRow) AsIssueWithAggregations() entity.IssueWithAggregation IssueVariants: []entity.IssueVariant{}, IssueMatches: []entity.IssueMatch{}, Activity: []entity.Activity{}, - CreatedAt: GetTimeValue(ibr.IssueRow.CreatedAt), - DeletedAt: GetTimeValue(ibr.IssueRow.DeletedAt), - UpdatedAt: GetTimeValue(ibr.IssueRow.UpdatedAt), + Metadata: entity.Metadata{ + CreatedAt: GetTimeValue(ibr.IssueRow.CreatedAt), + CreatedBy: GetInt64Value(ibr.IssueRow.CreatedBy), + DeletedAt: GetTimeValue(ibr.IssueRow.DeletedAt), + UpdatedAt: GetTimeValue(ibr.IssueRow.UpdatedAt), + UpdatedBy: GetInt64Value(ibr.IssueRow.UpdatedBy), + }, }, } } @@ -156,9 +166,13 @@ func (ibr *GetIssuesByRow) AsIssue() entity.Issue { IssueVariants: []entity.IssueVariant{}, IssueMatches: []entity.IssueMatch{}, Activity: []entity.Activity{}, - CreatedAt: GetTimeValue(ibr.IssueRow.CreatedAt), - DeletedAt: GetTimeValue(ibr.IssueRow.DeletedAt), - UpdatedAt: GetTimeValue(ibr.IssueRow.UpdatedAt), + Metadata: entity.Metadata{ + CreatedAt: GetTimeValue(ibr.IssueRow.CreatedAt), + CreatedBy: GetInt64Value(ibr.IssueRow.CreatedBy), + DeletedAt: GetTimeValue(ibr.IssueRow.DeletedAt), + UpdatedAt: GetTimeValue(ibr.IssueRow.UpdatedAt), + UpdatedBy: GetInt64Value(ibr.IssueRow.UpdatedBy), + }, } } @@ -180,8 +194,10 @@ func (ir *IssueRow) FromIssue(i *entity.Issue) { ir.Type = sql.NullString{String: i.Type.String(), Valid: true} ir.Description = sql.NullString{String: i.Description, Valid: true} ir.CreatedAt = sql.NullTime{Time: i.CreatedAt, Valid: true} + ir.CreatedBy = sql.NullInt64{Int64: i.CreatedBy, Valid: true} ir.DeletedAt = sql.NullTime{Time: i.DeletedAt, Valid: true} ir.UpdatedAt = sql.NullTime{Time: i.UpdatedAt, Valid: true} + ir.UpdatedBy = sql.NullInt64{Int64: i.UpdatedBy, Valid: true} } type IssueMatchRow struct { @@ -195,8 +211,10 @@ type IssueMatchRow struct { RemediationDate sql.NullTime `db:"issuematch_remediation_date" json:"remediation_date"` TargetRemediationDate sql.NullTime `db:"issuematch_target_remediation_date" json:"target_remediation_date"` CreatedAt sql.NullTime `db:"issuematch_created_at" json:"created_at"` + CreatedBy sql.NullInt64 `db:"issuematch_created_by" json:"created_by"` DeletedAt sql.NullTime `db:"issuematch_deleted_at" json:"deleted_at,omitempty"` UpdatedAt sql.NullTime `db:"issuematch_updated_at" json:"updated_at"` + UpdatedBy sql.NullInt64 `db:"issuematch_updated_by" json:"updated_by"` } func (imr IssueMatchRow) AsIssueMatch() entity.IssueMatch { @@ -212,9 +230,13 @@ func (imr IssueMatchRow) AsIssueMatch() entity.IssueMatch { RemediationDate: GetTimeValue(imr.RemediationDate), TargetRemediationDate: GetTimeValue(imr.TargetRemediationDate), Severity: entity.NewSeverity(GetStringValue(imr.Vector)), - CreatedAt: GetTimeValue(imr.CreatedAt), - DeletedAt: GetTimeValue(imr.DeletedAt), - UpdatedAt: GetTimeValue(imr.UpdatedAt), + Metadata: entity.Metadata{ + CreatedAt: GetTimeValue(imr.CreatedAt), + CreatedBy: GetInt64Value(imr.CreatedBy), + DeletedAt: GetTimeValue(imr.DeletedAt), + UpdatedAt: GetTimeValue(imr.UpdatedAt), + UpdatedBy: GetInt64Value(imr.UpdatedBy), + }, } } @@ -229,8 +251,10 @@ func (imr *IssueMatchRow) FromIssueMatch(im *entity.IssueMatch) { imr.RemediationDate = sql.NullTime{Time: im.RemediationDate, Valid: true} imr.TargetRemediationDate = sql.NullTime{Time: im.TargetRemediationDate, Valid: true} imr.CreatedAt = sql.NullTime{Time: im.CreatedAt, Valid: true} + imr.CreatedBy = sql.NullInt64{Int64: im.CreatedBy, Valid: true} imr.DeletedAt = sql.NullTime{Time: im.DeletedAt, Valid: true} imr.UpdatedAt = sql.NullTime{Time: im.UpdatedAt, Valid: true} + imr.UpdatedBy = sql.NullInt64{Int64: im.UpdatedBy, Valid: true} } type IssueRepositoryRow struct { @@ -243,8 +267,10 @@ type BaseIssueRepositoryRow struct { Name sql.NullString `db:"issuerepository_name"` Url sql.NullString `db:"issuerepository_url"` CreatedAt sql.NullTime `db:"issuerepository_created_at" json:"created_at"` + CreatedBy sql.NullInt64 `db:"issuerepository_created_by" json:"created_by"` DeletedAt sql.NullTime `db:"issuerepository_deleted_at" json:"deleted_at,omitempty"` UpdatedAt sql.NullTime `db:"issuerepository_updated_at" json:"updated_at"` + UpdatedBy sql.NullInt64 `db:"issuerepository_updated_by" json:"updated_by"` } func (irr *IssueRepositoryRow) FromIssueRepository(ir *entity.IssueRepository) { @@ -254,6 +280,11 @@ func (irr *IssueRepositoryRow) FromIssueRepository(ir *entity.IssueRepository) { irr.Priority = sql.NullInt64{Int64: ir.Priority, Valid: true} irr.ServiceId = sql.NullInt64{Int64: ir.ServiceId, Valid: true} irr.IssueRepositoryId = sql.NullInt64{Int64: ir.IssueRepositoryId, Valid: true} + irr.BaseIssueRepositoryRow.CreatedAt = sql.NullTime{Time: ir.BaseIssueRepository.CreatedAt, Valid: true} + irr.BaseIssueRepositoryRow.CreatedBy = sql.NullInt64{Int64: ir.BaseIssueRepository.CreatedBy, Valid: true} + irr.BaseIssueRepositoryRow.DeletedAt = sql.NullTime{Time: ir.BaseIssueRepository.DeletedAt, Valid: true} + irr.BaseIssueRepositoryRow.UpdatedAt = sql.NullTime{Time: ir.BaseIssueRepository.UpdatedAt, Valid: true} + irr.BaseIssueRepositoryRow.UpdatedBy = sql.NullInt64{Int64: ir.BaseIssueRepository.UpdatedBy, Valid: true} } func (birr *BaseIssueRepositoryRow) AsBaseIssueRepository() entity.BaseIssueRepository { @@ -263,9 +294,13 @@ func (birr *BaseIssueRepositoryRow) AsBaseIssueRepository() entity.BaseIssueRepo Url: GetStringValue(birr.Url), IssueVariants: nil, Services: nil, - CreatedAt: GetTimeValue(birr.CreatedAt), - DeletedAt: GetTimeValue(birr.DeletedAt), - UpdatedAt: GetTimeValue(birr.UpdatedAt), + Metadata: entity.Metadata{ + CreatedAt: GetTimeValue(birr.CreatedAt), + CreatedBy: GetInt64Value(birr.CreatedBy), + DeletedAt: GetTimeValue(birr.DeletedAt), + UpdatedAt: GetTimeValue(birr.UpdatedAt), + UpdatedBy: GetInt64Value(birr.UpdatedBy), + }, } } @@ -277,9 +312,13 @@ func (barr *BaseIssueRepositoryRow) AsIssueRepository() entity.IssueRepository { Url: GetStringValue(barr.Url), IssueVariants: nil, Services: nil, - CreatedAt: GetTimeValue(barr.CreatedAt), - DeletedAt: GetTimeValue(barr.DeletedAt), - UpdatedAt: GetTimeValue(barr.UpdatedAt), + Metadata: entity.Metadata{ + CreatedAt: GetTimeValue(barr.CreatedAt), + CreatedBy: GetInt64Value(barr.CreatedBy), + DeletedAt: GetTimeValue(barr.DeletedAt), + UpdatedAt: GetTimeValue(barr.UpdatedAt), + UpdatedBy: GetInt64Value(barr.UpdatedBy), + }, }, } } @@ -292,9 +331,13 @@ func (irr *IssueRepositoryRow) AsIssueRepository() entity.IssueRepository { Url: GetStringValue(irr.Url), IssueVariants: nil, Services: nil, - CreatedAt: GetTimeValue(irr.BaseIssueRepositoryRow.CreatedAt), - DeletedAt: GetTimeValue(irr.BaseIssueRepositoryRow.DeletedAt), - UpdatedAt: GetTimeValue(irr.BaseIssueRepositoryRow.UpdatedAt), + Metadata: entity.Metadata{ + CreatedAt: GetTimeValue(irr.BaseIssueRepositoryRow.CreatedAt), + CreatedBy: GetInt64Value(irr.BaseIssueRepositoryRow.CreatedBy), + DeletedAt: GetTimeValue(irr.BaseIssueRepositoryRow.DeletedAt), + UpdatedAt: GetTimeValue(irr.BaseIssueRepositoryRow.UpdatedAt), + UpdatedBy: GetInt64Value(irr.BaseIssueRepositoryRow.UpdatedBy), + }, }, IssueRepositoryService: entity.IssueRepositoryService{ ServiceId: GetInt64Value(irr.ServiceId), @@ -312,8 +355,10 @@ type IssueVariantRow struct { Rating sql.NullString `db:"issuevariant_rating" json:"rating"` Description sql.NullString `db:"issuevariant_description" json:"description"` CreatedAt sql.NullTime `db:"issuevariant_created_at" json:"created_at"` + CreatedBy sql.NullInt64 `db:"issuevariant_created_by" json:"created_by"` DeletedAt sql.NullTime `db:"issuevariant_deleted_at" json:"deleted_at,omitempty"` UpdatedAt sql.NullTime `db:"issuevariant_updated_at" json:"updated_at"` + UpdatedBy sql.NullInt64 `db:"issuevariant_updated_by" json:"updated_by"` } func (ivr *IssueVariantRow) AsIssueVariant(repository *entity.IssueRepository) entity.IssueVariant { @@ -326,9 +371,13 @@ func (ivr *IssueVariantRow) AsIssueVariant(repository *entity.IssueRepository) e Issue: nil, Severity: entity.NewSeverity(GetStringValue(ivr.Vector)), Description: GetStringValue(ivr.Description), - CreatedAt: GetTimeValue(ivr.CreatedAt), - DeletedAt: GetTimeValue(ivr.DeletedAt), - UpdatedAt: GetTimeValue(ivr.UpdatedAt), + Metadata: entity.Metadata{ + CreatedAt: GetTimeValue(ivr.CreatedAt), + CreatedBy: GetInt64Value(ivr.CreatedBy), + DeletedAt: GetTimeValue(ivr.DeletedAt), + UpdatedAt: GetTimeValue(ivr.UpdatedAt), + UpdatedBy: GetInt64Value(ivr.UpdatedBy), + }, } } @@ -341,8 +390,10 @@ func (ivr *IssueVariantRow) FromIssueVariant(iv *entity.IssueVariant) { ivr.Rating = sql.NullString{String: iv.Severity.Value, Valid: true} ivr.Description = sql.NullString{String: iv.Description, Valid: true} ivr.CreatedAt = sql.NullTime{Time: iv.CreatedAt, Valid: true} + ivr.CreatedBy = sql.NullInt64{Int64: iv.CreatedBy, Valid: true} ivr.DeletedAt = sql.NullTime{Time: iv.DeletedAt, Valid: true} ivr.UpdatedAt = sql.NullTime{Time: iv.UpdatedAt, Valid: true} + ivr.UpdatedBy = sql.NullInt64{Int64: iv.UpdatedBy, Valid: true} } type IssueVariantWithRepository struct { @@ -361,9 +412,13 @@ func (ivwr *IssueVariantWithRepository) AsIssueVariantEntry() entity.IssueVarian Issue: nil, Severity: entity.NewSeverity(GetStringValue(ivwr.Vector)), Description: GetStringValue(ivwr.Description), - CreatedAt: GetTimeValue(ivwr.IssueVariantRow.CreatedAt), - DeletedAt: GetTimeValue(ivwr.IssueVariantRow.DeletedAt), - UpdatedAt: GetTimeValue(ivwr.IssueVariantRow.UpdatedAt), + Metadata: entity.Metadata{ + CreatedAt: GetTimeValue(ivwr.IssueVariantRow.CreatedAt), + CreatedBy: GetInt64Value(ivwr.CreatedBy), + DeletedAt: GetTimeValue(ivwr.IssueVariantRow.DeletedAt), + UpdatedAt: GetTimeValue(ivwr.IssueVariantRow.UpdatedAt), + UpdatedBy: GetInt64Value(ivwr.UpdatedBy), + }, } } @@ -384,9 +439,13 @@ func (siv *ServiceIssueVariantRow) AsServiceIssueVariantEntry() entity.ServiceIs Issue: nil, Severity: entity.NewSeverity(GetStringValue(siv.Vector)), Description: GetStringValue(siv.Description), - CreatedAt: GetTimeValue(siv.IssueVariantRow.CreatedAt), - DeletedAt: GetTimeValue(siv.IssueVariantRow.DeletedAt), - UpdatedAt: GetTimeValue(siv.IssueVariantRow.UpdatedAt), + Metadata: entity.Metadata{ + CreatedAt: GetTimeValue(siv.IssueVariantRow.CreatedAt), + CreatedBy: GetInt64Value(siv.CreatedBy), + DeletedAt: GetTimeValue(siv.IssueVariantRow.DeletedAt), + UpdatedAt: GetTimeValue(siv.IssueVariantRow.UpdatedAt), + UpdatedBy: GetInt64Value(siv.UpdatedBy), + }, }, ServiceId: GetInt64Value(siv.IssueRepositoryServiceRow.ServiceId), Priority: GetInt64Value(siv.Priority), @@ -398,18 +457,24 @@ type ComponentRow struct { CCRN sql.NullString `db:"component_ccrn" json:"ccrn"` Type sql.NullString `db:"component_type" json:"type"` CreatedAt sql.NullTime `db:"component_created_at" json:"created_at"` + CreatedBy sql.NullInt64 `db:"component_created_by" json:"created_by"` DeletedAt sql.NullTime `db:"component_deleted_at" json:"deleted_at,omitempty"` UpdatedAt sql.NullTime `db:"component_updated_at" json:"updated_at"` + UpdatedBy sql.NullInt64 `db:"component_updated_by" json:"updated_by"` } func (cr *ComponentRow) AsComponent() entity.Component { return entity.Component{ - Id: GetInt64Value(cr.Id), - CCRN: GetStringValue(cr.CCRN), - Type: GetStringValue(cr.Type), - CreatedAt: GetTimeValue(cr.CreatedAt), - DeletedAt: GetTimeValue(cr.DeletedAt), - UpdatedAt: GetTimeValue(cr.UpdatedAt), + Id: GetInt64Value(cr.Id), + CCRN: GetStringValue(cr.CCRN), + Type: GetStringValue(cr.Type), + Metadata: entity.Metadata{ + CreatedAt: GetTimeValue(cr.CreatedAt), + CreatedBy: GetInt64Value(cr.CreatedBy), + DeletedAt: GetTimeValue(cr.DeletedAt), + UpdatedAt: GetTimeValue(cr.UpdatedAt), + UpdatedBy: GetInt64Value(cr.UpdatedBy), + }, } } @@ -418,8 +483,10 @@ func (cr *ComponentRow) FromComponent(c *entity.Component) { cr.CCRN = sql.NullString{String: c.CCRN, Valid: true} cr.Type = sql.NullString{String: c.Type, Valid: true} cr.CreatedAt = sql.NullTime{Time: c.CreatedAt, Valid: true} + cr.CreatedBy = sql.NullInt64{Int64: c.CreatedBy, Valid: true} cr.DeletedAt = sql.NullTime{Time: c.DeletedAt, Valid: true} cr.UpdatedAt = sql.NullTime{Time: c.UpdatedAt, Valid: true} + cr.UpdatedBy = sql.NullInt64{Int64: c.UpdatedBy, Valid: true} } type ComponentVersionRow struct { @@ -427,8 +494,10 @@ type ComponentVersionRow struct { Version sql.NullString `db:"componentversion_version" json:"version"` ComponentId sql.NullInt64 `db:"componentversion_component_id"` CreatedAt sql.NullTime `db:"componentversion_created_at" json:"created_at"` + CreatedBy sql.NullInt64 `db:"componentversion_created_by" json:"created_by"` DeletedAt sql.NullTime `db:"componentversion_deleted_at" json:"deleted_at,omitempty"` UpdatedAt sql.NullTime `db:"componentversion_updated_at" json:"updated_at"` + UpdatedBy sql.NullInt64 `db:"componentversion_updated_by" json:"updated_by"` } func (cvr *ComponentVersionRow) AsComponentVersion() entity.ComponentVersion { @@ -436,9 +505,13 @@ func (cvr *ComponentVersionRow) AsComponentVersion() entity.ComponentVersion { Id: GetInt64Value(cvr.Id), Version: GetStringValue(cvr.Version), ComponentId: GetInt64Value(cvr.ComponentId), - CreatedAt: GetTimeValue(cvr.CreatedAt), - DeletedAt: GetTimeValue(cvr.DeletedAt), - UpdatedAt: GetTimeValue(cvr.UpdatedAt), + Metadata: entity.Metadata{ + CreatedAt: GetTimeValue(cvr.CreatedAt), + CreatedBy: GetInt64Value(cvr.CreatedBy), + DeletedAt: GetTimeValue(cvr.DeletedAt), + UpdatedAt: GetTimeValue(cvr.UpdatedAt), + UpdatedBy: GetInt64Value(cvr.UpdatedBy), + }, } } @@ -447,25 +520,33 @@ func (cvr *ComponentVersionRow) FromComponentVersion(cv *entity.ComponentVersion cvr.Version = sql.NullString{String: cv.Version, Valid: true} cvr.ComponentId = sql.NullInt64{Int64: cv.ComponentId, Valid: true} cvr.CreatedAt = sql.NullTime{Time: cv.CreatedAt, Valid: true} + cvr.CreatedBy = sql.NullInt64{Int64: cv.CreatedBy, Valid: true} cvr.DeletedAt = sql.NullTime{Time: cv.DeletedAt, Valid: true} cvr.UpdatedAt = sql.NullTime{Time: cv.UpdatedAt, Valid: true} + cvr.UpdatedBy = sql.NullInt64{Int64: cv.UpdatedBy, Valid: true} } type SupportGroupRow struct { Id sql.NullInt64 `db:"supportgroup_id" json:"id"` CCRN sql.NullString `db:"supportgroup_ccrn" json:"ccrn"` CreatedAt sql.NullTime `db:"supportgroup_created_at" json:"created_at"` + CreatedBy sql.NullInt64 `db:"supportgroup_created_by" json:"created_by"` DeletedAt sql.NullTime `db:"supportgroup_deleted_at" json:"deleted_at,omitempty"` UpdatedAt sql.NullTime `db:"supportgroup_updated_at" json:"updated_at"` + UpdatedBy sql.NullInt64 `db:"supportgroup_updated_by" json:"updated_by"` } func (sgr *SupportGroupRow) AsSupportGroup() entity.SupportGroup { return entity.SupportGroup{ - Id: GetInt64Value(sgr.Id), - CCRN: GetStringValue(sgr.CCRN), - CreatedAt: GetTimeValue(sgr.CreatedAt), - DeletedAt: GetTimeValue(sgr.DeletedAt), - UpdatedAt: GetTimeValue(sgr.UpdatedAt), + Id: GetInt64Value(sgr.Id), + CCRN: GetStringValue(sgr.CCRN), + Metadata: entity.Metadata{ + CreatedAt: GetTimeValue(sgr.CreatedAt), + CreatedBy: GetInt64Value(sgr.CreatedBy), + DeletedAt: GetTimeValue(sgr.DeletedAt), + UpdatedAt: GetTimeValue(sgr.UpdatedAt), + UpdatedBy: GetInt64Value(sgr.UpdatedBy), + }, } } @@ -473,8 +554,10 @@ func (sgr *SupportGroupRow) FromSupportGroup(sg *entity.SupportGroup) { sgr.Id = sql.NullInt64{Int64: sg.Id, Valid: true} sgr.CCRN = sql.NullString{String: sg.CCRN, Valid: true} sgr.CreatedAt = sql.NullTime{Time: sg.CreatedAt, Valid: true} + sgr.CreatedBy = sql.NullInt64{Int64: sg.CreatedBy, Valid: true} sgr.DeletedAt = sql.NullTime{Time: sg.DeletedAt, Valid: true} sgr.UpdatedAt = sql.NullTime{Time: sg.UpdatedAt, Valid: true} + sgr.UpdatedBy = sql.NullInt64{Int64: sg.UpdatedBy, Valid: true} } type ServiceRow struct { @@ -486,8 +569,10 @@ type BaseServiceRow struct { Id sql.NullInt64 `db:"service_id" json:"id"` CCRN sql.NullString `db:"service_ccrn" json:"ccrn"` CreatedAt sql.NullTime `db:"service_created_at" json:"created_at"` + CreatedBy sql.NullInt64 `db:"service_created_by" json:"created_by"` DeletedAt sql.NullTime `db:"service_deleted_at" json:"deleted_at,omitempty"` UpdatedAt sql.NullTime `db:"service_updated_at" json:"updated_at"` + UpdatedBy sql.NullInt64 `db:"service_updated_by" json:"updated_by"` } func (bsr *BaseServiceRow) AsBaseService() entity.BaseService { @@ -496,9 +581,13 @@ func (bsr *BaseServiceRow) AsBaseService() entity.BaseService { CCRN: GetStringValue(bsr.CCRN), Owners: []entity.User{}, Activities: []entity.Activity{}, - CreatedAt: GetTimeValue(bsr.CreatedAt), - DeletedAt: GetTimeValue(bsr.DeletedAt), - UpdatedAt: GetTimeValue(bsr.UpdatedAt), + Metadata: entity.Metadata{ + CreatedAt: GetTimeValue(bsr.CreatedAt), + CreatedBy: GetInt64Value(bsr.CreatedBy), + DeletedAt: GetTimeValue(bsr.DeletedAt), + UpdatedAt: GetTimeValue(bsr.UpdatedAt), + UpdatedBy: GetInt64Value(bsr.UpdatedBy), + }, } } @@ -516,9 +605,13 @@ func (sr *ServiceRow) AsService() entity.Service { CCRN: GetStringValue(sr.CCRN), Owners: []entity.User{}, Activities: []entity.Activity{}, - CreatedAt: GetTimeValue(sr.BaseServiceRow.CreatedAt), - DeletedAt: GetTimeValue(sr.BaseServiceRow.DeletedAt), - UpdatedAt: GetTimeValue(sr.BaseServiceRow.UpdatedAt), + Metadata: entity.Metadata{ + CreatedAt: GetTimeValue(sr.BaseServiceRow.CreatedAt), + CreatedBy: GetInt64Value(sr.BaseServiceRow.CreatedBy), + DeletedAt: GetTimeValue(sr.BaseServiceRow.DeletedAt), + UpdatedAt: GetTimeValue(sr.BaseServiceRow.UpdatedAt), + UpdatedBy: GetInt64Value(sr.BaseServiceRow.UpdatedBy), + }, }, IssueRepositoryService: entity.IssueRepositoryService{ ServiceId: GetInt64Value(sr.ServiceId), @@ -531,8 +624,10 @@ func (sr *ServiceRow) FromService(s *entity.Service) { sr.Id = sql.NullInt64{Int64: s.Id, Valid: true} sr.CCRN = sql.NullString{String: s.CCRN, Valid: true} sr.BaseServiceRow.CreatedAt = sql.NullTime{Time: s.BaseService.CreatedAt, Valid: true} + sr.BaseServiceRow.CreatedBy = sql.NullInt64{Int64: s.BaseService.CreatedBy, Valid: true} sr.BaseServiceRow.DeletedAt = sql.NullTime{Time: s.BaseService.DeletedAt, Valid: true} sr.BaseServiceRow.UpdatedAt = sql.NullTime{Time: s.BaseService.UpdatedAt, Valid: true} + sr.BaseServiceRow.UpdatedBy = sql.NullInt64{Int64: s.BaseService.UpdatedBy, Valid: true} } type GetServicesByRow struct { @@ -557,9 +652,13 @@ func (sbr *GetServicesByRow) AsServiceWithAggregations() entity.ServiceWithAggre CCRN: GetStringValue(sbr.BaseServiceRow.CCRN), Owners: []entity.User{}, Activities: []entity.Activity{}, - CreatedAt: GetTimeValue(sbr.BaseServiceRow.CreatedAt), - DeletedAt: GetTimeValue(sbr.BaseServiceRow.DeletedAt), - UpdatedAt: GetTimeValue(sbr.BaseServiceRow.UpdatedAt), + Metadata: entity.Metadata{ + CreatedAt: GetTimeValue(sbr.BaseServiceRow.CreatedAt), + CreatedBy: GetInt64Value(sbr.BaseServiceRow.CreatedBy), + DeletedAt: GetTimeValue(sbr.BaseServiceRow.DeletedAt), + UpdatedAt: GetTimeValue(sbr.BaseServiceRow.UpdatedAt), + UpdatedBy: GetInt64Value(sbr.BaseServiceRow.UpdatedBy), + }, }, IssueRepositoryService: entity.IssueRepositoryService{ ServiceId: GetInt64Value(sbr.IssueRepositoryServiceRow.ServiceId), @@ -574,8 +673,10 @@ type ActivityRow struct { Id sql.NullInt64 `db:"activity_id" json:"id"` Status sql.NullString `db:"activity_status" json:"status"` CreatedAt sql.NullTime `db:"activity_created_at" json:"created_at"` + CreatedBy sql.NullInt64 `db:"activity_created_by" json:"created_by"` DeletedAt sql.NullTime `db:"activity_deleted_at" json:"deleted_at,omitempty"` UpdatedAt sql.NullTime `db:"activity_updated_at" json:"updated_at"` + UpdatedBy sql.NullInt64 `db:"activity_updated_by" json:"updated_by"` } func (ar *ActivityRow) AsActivity() entity.Activity { @@ -584,9 +685,13 @@ func (ar *ActivityRow) AsActivity() entity.Activity { Status: entity.ActivityStatusValue(GetStringValue(ar.Status)), Issues: []entity.Issue{}, Evidences: []entity.Evidence{}, - CreatedAt: GetTimeValue(ar.CreatedAt), - DeletedAt: GetTimeValue(ar.DeletedAt), - UpdatedAt: GetTimeValue(ar.UpdatedAt), + Metadata: entity.Metadata{ + CreatedAt: GetTimeValue(ar.CreatedAt), + CreatedBy: GetInt64Value(ar.CreatedBy), + DeletedAt: GetTimeValue(ar.DeletedAt), + UpdatedAt: GetTimeValue(ar.UpdatedAt), + UpdatedBy: GetInt64Value(ar.UpdatedBy), + }, } } @@ -594,8 +699,10 @@ func (ar *ActivityRow) FromActivity(a *entity.Activity) { ar.Id = sql.NullInt64{Int64: a.Id, Valid: true} ar.Status = sql.NullString{String: a.Status.String(), Valid: true} ar.CreatedAt = sql.NullTime{Time: a.CreatedAt, Valid: true} + ar.CreatedBy = sql.NullInt64{Int64: a.CreatedBy, Valid: true} ar.DeletedAt = sql.NullTime{Time: a.DeletedAt, Valid: true} ar.UpdatedAt = sql.NullTime{Time: a.UpdatedAt, Valid: true} + ar.UpdatedBy = sql.NullInt64{Int64: a.UpdatedBy, Valid: true} } type ComponentInstanceRow struct { @@ -605,8 +712,10 @@ type ComponentInstanceRow struct { ComponentVersionId sql.NullInt64 `db:"componentinstance_component_version_id"` ServiceId sql.NullInt64 `db:"componentinstance_service_id"` CreatedAt sql.NullTime `db:"componentinstance_created_at" json:"created_at"` + CreatedBy sql.NullInt64 `db:"componentinstance_created_by" json:"created_by"` DeletedAt sql.NullTime `db:"componentinstance_deleted_at" json:"deleted_at,omitempty"` UpdatedAt sql.NullTime `db:"componentinstance_updated_at" json:"updated_at"` + UpdatedBy sql.NullInt64 `db:"componentinstance_updated_by" json:"udpated_by"` } func (cir *ComponentInstanceRow) AsComponentInstance() entity.ComponentInstance { @@ -618,9 +727,13 @@ func (cir *ComponentInstanceRow) AsComponentInstance() entity.ComponentInstance ComponentVersionId: GetInt64Value(cir.ComponentVersionId), Service: nil, ServiceId: GetInt64Value(cir.ServiceId), - CreatedAt: GetTimeValue(cir.CreatedAt), - DeletedAt: GetTimeValue(cir.DeletedAt), - UpdatedAt: GetTimeValue(cir.UpdatedAt), + Metadata: entity.Metadata{ + CreatedAt: GetTimeValue(cir.CreatedAt), + CreatedBy: GetInt64Value(cir.CreatedBy), + DeletedAt: GetTimeValue(cir.DeletedAt), + UpdatedAt: GetTimeValue(cir.UpdatedAt), + UpdatedBy: GetInt64Value(cir.UpdatedBy), + }, } } @@ -631,8 +744,10 @@ func (cir *ComponentInstanceRow) FromComponentInstance(ci *entity.ComponentInsta cir.ComponentVersionId = sql.NullInt64{Int64: ci.ComponentVersionId, Valid: true} cir.ServiceId = sql.NullInt64{Int64: ci.ServiceId, Valid: true} cir.CreatedAt = sql.NullTime{Time: ci.CreatedAt, Valid: true} + cir.CreatedBy = sql.NullInt64{Int64: ci.CreatedBy, Valid: true} cir.DeletedAt = sql.NullTime{Time: ci.DeletedAt, Valid: true} cir.UpdatedAt = sql.NullTime{Time: ci.UpdatedAt, Valid: true} + cir.UpdatedBy = sql.NullInt64{Int64: ci.UpdatedBy, Valid: true} } type UserRow struct { @@ -641,8 +756,10 @@ type UserRow struct { UniqueUserID sql.NullString `db:"user_unique_user_id" json:"unique_user_id"` Type sql.NullInt64 `db:"user_type" json:"type"` CreatedAt sql.NullTime `db:"user_created_at" json:"created_at"` + CreatedBy sql.NullInt64 `db:"user_created_by" json:"created_by"` DeletedAt sql.NullTime `db:"user_deleted_at" json:"deleted_at,omitempty"` UpdatedAt sql.NullTime `db:"user_updated_at" json:"updated_at"` + UpdatedBy sql.NullInt64 `db:"user_updated_by" json:"Updated_by"` } func (ur *UserRow) AsUser() entity.User { @@ -651,9 +768,13 @@ func (ur *UserRow) AsUser() entity.User { Name: GetStringValue(ur.Name), UniqueUserID: GetStringValue(ur.UniqueUserID), Type: GetUserTypeValue(ur.Type), - CreatedAt: GetTimeValue(ur.CreatedAt), - DeletedAt: GetTimeValue(ur.DeletedAt), - UpdatedAt: GetTimeValue(ur.UpdatedAt), + Metadata: entity.Metadata{ + CreatedAt: GetTimeValue(ur.CreatedAt), + CreatedBy: GetInt64Value(ur.CreatedBy), + DeletedAt: GetTimeValue(ur.DeletedAt), + UpdatedAt: GetTimeValue(ur.UpdatedAt), + UpdatedBy: GetInt64Value(ur.UpdatedBy), + }, } } @@ -663,8 +784,10 @@ func (ur *UserRow) FromUser(u *entity.User) { ur.UniqueUserID = sql.NullString{String: u.UniqueUserID, Valid: true} ur.Type = sql.NullInt64{Int64: int64(u.Type), Valid: true} ur.CreatedAt = sql.NullTime{Time: u.CreatedAt, Valid: true} + ur.CreatedBy = sql.NullInt64{Int64: u.CreatedBy, Valid: true} ur.DeletedAt = sql.NullTime{Time: u.DeletedAt, Valid: true} ur.UpdatedAt = sql.NullTime{Time: u.UpdatedAt, Valid: true} + ur.UpdatedBy = sql.NullInt64{Int64: u.UpdatedBy, Valid: true} } type EvidenceRow struct { @@ -679,8 +802,10 @@ type EvidenceRow struct { Activity *ActivityRow `json:"activity,omitempty"` ActivityId sql.NullInt64 `db:"evidence_activity_id"` CreatedAt sql.NullTime `db:"evidence_created_at" json:"created_at"` + CreatedBy sql.NullInt64 `db:"evidence_created_by" json:"created_by"` DeletedAt sql.NullTime `db:"evidence_deleted_at" json:"deleted_at,omitempty"` UpdatedAt sql.NullTime `db:"evidence_updated_at" json:"updated_at"` + UpdatedBy sql.NullInt64 `db:"evidence_updated_by" json:"updated_by"` } func (er *EvidenceRow) AsEvidence() entity.Evidence { @@ -694,9 +819,13 @@ func (er *EvidenceRow) AsEvidence() entity.Evidence { UserId: GetInt64Value(er.UserId), Activity: nil, ActivityId: GetInt64Value(er.ActivityId), - CreatedAt: GetTimeValue(er.CreatedAt), - DeletedAt: GetTimeValue(er.DeletedAt), - UpdatedAt: GetTimeValue(er.UpdatedAt), + Metadata: entity.Metadata{ + CreatedAt: GetTimeValue(er.CreatedAt), + CreatedBy: GetInt64Value(er.CreatedBy), + DeletedAt: GetTimeValue(er.DeletedAt), + UpdatedAt: GetTimeValue(er.UpdatedAt), + UpdatedBy: GetInt64Value(er.UpdatedBy), + }, } } @@ -710,8 +839,10 @@ func (er *EvidenceRow) FromEvidence(e *entity.Evidence) { er.UserId = sql.NullInt64{Int64: e.UserId, Valid: true} er.ActivityId = sql.NullInt64{Int64: e.ActivityId, Valid: true} er.CreatedAt = sql.NullTime{Time: e.CreatedAt, Valid: true} + er.CreatedBy = sql.NullInt64{Int64: e.CreatedBy, Valid: true} er.DeletedAt = sql.NullTime{Time: e.DeletedAt, Valid: true} er.UpdatedAt = sql.NullTime{Time: e.UpdatedAt, Valid: true} + er.UpdatedBy = sql.NullInt64{Int64: e.UpdatedBy, Valid: true} } type IssueMatchChangeRow struct { @@ -720,8 +851,10 @@ type IssueMatchChangeRow struct { ActivityId sql.NullInt64 `db:"issuematchchange_activity_id" json:"activity_id"` Action sql.NullString `db:"issuematchchange_action" json:"action"` CreatedAt sql.NullTime `db:"issuematchchange_created_at" json:"created_at"` + CreatedBy sql.NullInt64 `db:"issuematchchange_created_by" json:"created_by"` DeletedAt sql.NullTime `db:"issuematchchange_deleted_at" json:"deleted_at,omitempty"` UpdatedAt sql.NullTime `db:"issuematchchange_updated_at" json:"updated_at"` + UpdatedBy sql.NullInt64 `db:"issuematchchange_updated_by" json:"updated_by"` } func (imcr *IssueMatchChangeRow) AsIssueMatchChange() entity.IssueMatchChange { @@ -730,9 +863,13 @@ func (imcr *IssueMatchChangeRow) AsIssueMatchChange() entity.IssueMatchChange { IssueMatchId: GetInt64Value(imcr.IssueMatchId), ActivityId: GetInt64Value(imcr.ActivityId), Action: GetStringValue(imcr.Action), - CreatedAt: GetTimeValue(imcr.CreatedAt), - DeletedAt: GetTimeValue(imcr.DeletedAt), - UpdatedAt: GetTimeValue(imcr.UpdatedAt), + Metadata: entity.Metadata{ + CreatedAt: GetTimeValue(imcr.CreatedAt), + CreatedBy: GetInt64Value(imcr.CreatedBy), + DeletedAt: GetTimeValue(imcr.DeletedAt), + UpdatedAt: GetTimeValue(imcr.UpdatedAt), + UpdatedBy: GetInt64Value(imcr.UpdatedBy), + }, } } @@ -742,8 +879,10 @@ func (imcr *IssueMatchChangeRow) FromIssueMatchChange(imc *entity.IssueMatchChan imcr.ActivityId = sql.NullInt64{Int64: imc.ActivityId, Valid: true} imcr.Action = sql.NullString{String: imc.Action, Valid: true} imcr.CreatedAt = sql.NullTime{Time: imc.CreatedAt, Valid: true} + imcr.CreatedBy = sql.NullInt64{Int64: imc.CreatedBy, Valid: true} imcr.DeletedAt = sql.NullTime{Time: imc.DeletedAt, Valid: true} imcr.UpdatedAt = sql.NullTime{Time: imc.UpdatedAt, Valid: true} + imcr.UpdatedBy = sql.NullInt64{Int64: imc.UpdatedBy, Valid: true} } type OwnerRow struct { diff --git a/internal/database/mariadb/evidence.go b/internal/database/mariadb/evidence.go index 73d7c693..8838826c 100644 --- a/internal/database/mariadb/evidence.go +++ b/internal/database/mariadb/evidence.go @@ -76,6 +76,9 @@ func (s *SqlDatabase) getEvidenceUpdateFields(evidence *entity.Evidence) string if !evidence.RaaEnd.IsZero() { fl = append(fl, "evidence_raa_end = :evidence_raa_end") } + if evidence.UpdatedBy != 0 { + fl = append(fl, "evidence_updated_by = :evidence_updated_by") + } return strings.Join(fl, ", ") } @@ -220,7 +223,8 @@ func (s *SqlDatabase) CreateEvidence(evidence *entity.Evidence) (*entity.Evidenc evidence_description, evidence_vector, evidence_rating, - evidence_raa_end + evidence_raa_end, + evidence_created_by ) VALUES ( :evidence_author_id, :evidence_activity_id, @@ -228,7 +232,8 @@ func (s *SqlDatabase) CreateEvidence(evidence *entity.Evidence) (*entity.Evidenc :evidence_description, :evidence_vector, :evidence_rating, - :evidence_raa_end + :evidence_raa_end, + :evidence_created_by ) ` diff --git a/internal/database/mariadb/init/schema.sql b/internal/database/mariadb/init/schema.sql index c8b59885..995d1fbe 100644 --- a/internal/database/mariadb/init/schema.sql +++ b/internal/database/mariadb/init/schema.sql @@ -5,6 +5,36 @@ create schema if not exists heureka; use heureka; +create table if not exists User +( + user_id int unsigned auto_increment + primary key, + user_name varchar(256) not null, + user_unique_user_id varchar(64) not null, + user_type int unsigned, + user_created_at timestamp default current_timestamp() not null, + user_created_by int unsigned null, + user_deleted_at timestamp null, + user_updated_at timestamp default current_timestamp() not null on update current_timestamp(), + user_updated_by int unsigned null, + constraint user_id_UNIQUE + unique (user_id), + constraint unique_user_id_UNIQUE + unique (user_unique_user_id), + constraint fk_user_created_by + foreign key (user_created_by) references User (user_id), + constraint fk_user_updated_by + foreign key (user_updated_by) references User (user_id) +); + +set @TechnicalUserType = 2; +set @SystemUserId = 1; +set @SystemUserName = 'systemuser'; +set @SystemUserUniqueUserId = 'S0000000'; +insert ignore into User (user_id, user_name, user_unique_user_id, user_type, user_created_at, user_created_by) + values + (@SystemUserId, @SystemUserName, @SystemUserUniqueUserId, @TechnicalUserType, current_timestamp(), @SystemUserId); + create table if not exists Component ( component_id int unsigned auto_increment @@ -12,12 +42,18 @@ create table if not exists Component component_ccrn varchar(256) not null, component_type varchar(256) not null, component_created_at timestamp default current_timestamp() not null, + component_created_by int unsigned null, component_deleted_at timestamp null, component_updated_at timestamp default current_timestamp() not null on update current_timestamp(), - constraint component_id_UNIQUE + component_updated_by int unsigned null, + constraint id_UNIQUE unique (component_id), constraint component_ccrn_UNIQUE - unique (component_ccrn) + unique (component_ccrn), + constraint fk_component_created_by + foreign key (component_created_by) references User (user_id), + constraint fk_component_updated_by + foreign key (component_updated_by) references User (user_id) ); create table if not exists ComponentVersion @@ -27,15 +63,21 @@ create table if not exists ComponentVersion componentversion_version varchar(256) not null, componentversion_component_id int unsigned not null, componentversion_created_at timestamp default current_timestamp() not null, + componentversion_created_by int unsigned null, componentversion_deleted_at timestamp null, componentversion_updated_at timestamp default current_timestamp() not null on update current_timestamp(), + componentversion_updated_by int unsigned null, constraint componentversion_id_UNIQUE unique (componentversion_id), constraint version_component_UNIQUE unique (componentversion_version, componentversion_component_id), constraint fk_component_version_component foreign key (componentversion_component_id) references Component (component_id) - on update cascade + on update cascade, + constraint fk_componentversion_created_by + foreign key (componentversion_created_by) references User (user_id), + constraint fk_componentversion_updated_by + foreign key (componentversion_updated_by) references User (user_id) ); create table if not exists SupportGroup @@ -44,12 +86,18 @@ create table if not exists SupportGroup primary key, supportgroup_ccrn varchar(256) not null, supportgroup_created_at timestamp default current_timestamp() not null, + supportgroup_created_by int unsigned null, supportgroup_deleted_at timestamp null, supportgroup_updated_at timestamp default current_timestamp() not null on update current_timestamp(), + supportgroup_updated_by int unsigned null, constraint supportgroup_id_UNIQUE unique (supportgroup_id), constraint supportgroup_ccrn_UNIQUE - unique (supportgroup_ccrn) + unique (supportgroup_ccrn), + constraint fk_supportgroup_created_by + foreign key (supportgroup_created_by) references User (user_id), + constraint fk_supportgroup_updated_by + foreign key (supportgroup_updated_by) references User (user_id) ); create table if not exists Service @@ -58,12 +106,18 @@ create table if not exists Service primary key, service_ccrn varchar(256) not null, service_created_at timestamp default current_timestamp() not null, + service_created_by int unsigned null, service_deleted_at timestamp null, service_updated_at timestamp default current_timestamp() not null on update current_timestamp(), + service_updated_by int unsigned null, constraint service_id_UNIQUE unique (service_id), constraint service_ccrn_UNIQUE - unique (service_ccrn) + unique (service_ccrn), + constraint fk_service_created_by + foreign key (service_created_by) references User (user_id), + constraint fk_service_updated_by + foreign key (service_updated_by) references User (user_id) ); create table if not exists SupportGroupService @@ -88,10 +142,16 @@ create table if not exists Activity primary key, activity_status enum ('open','closed','in_progress') not null, activity_created_at timestamp default current_timestamp() not null, + activity_created_by int unsigned null, activity_deleted_at timestamp null, activity_updated_at timestamp default current_timestamp() not null on update current_timestamp(), + activity_updated_by int unsigned null, constraint activity_id_UNIQUE - unique (activity_id) + unique (activity_id), + constraint fk_activity_created_by + foreign key (activity_created_by) references User (user_id), + constraint fk_activity_updated_by + foreign key (activity_updated_by) references User (user_id) ); create table if not exists ComponentInstance @@ -103,8 +163,10 @@ create table if not exists ComponentInstance componentinstance_component_version_id int unsigned not null, componentinstance_service_id int unsigned not null, componentinstance_created_at timestamp default current_timestamp() not null, + componentinstance_created_by int unsigned null, componentinstance_deleted_at timestamp null, componentinstance_updated_at timestamp default current_timestamp() not null on update current_timestamp(), + componentinstance_updated_by int unsigned null, constraint componentinstance_id_UNIQUE unique (componentinstance_id), constraint componentinstance_ccrn_service_id_unique @@ -114,25 +176,11 @@ create table if not exists ComponentInstance on update cascade, constraint fk_component_instance_service foreign key (componentinstance_service_id) references Service (service_id) - on update cascade -); - - - -create table if not exists User -( - user_id int unsigned auto_increment - primary key, - user_name varchar(256) not null, - user_unique_user_id varchar(64) not null, - user_type int unsigned, - user_created_at timestamp default current_timestamp() not null, - user_deleted_at timestamp null, - user_updated_at timestamp default current_timestamp() not null on update current_timestamp(), - constraint user_id_UNIQUE - unique (user_id), - constraint unique_user_id_UNIQUE - unique (user_unique_user_id) + on update cascade, + constraint fk_componentinstance_created_by + foreign key (componentinstance_created_by) references User (user_id), + constraint fk_componentinstance_updated_by + foreign key (componentinstance_updated_by) references User (user_id) ); create table if not exists Evidence @@ -147,8 +195,10 @@ create table if not exists Evidence evidence_rating enum ('None','Low','Medium','High','Critical') null, evidence_raa_end datetime null, evidence_created_at timestamp default current_timestamp() not null, + evidence_created_by int unsigned null, evidence_deleted_at timestamp null, evidence_updated_at timestamp default current_timestamp() not null on update current_timestamp(), + evidence_updated_by int unsigned null, constraint evidence_id_UNIQUE unique (evidence_id), constraint fk_evidence_user @@ -156,7 +206,11 @@ create table if not exists Evidence on update cascade, constraint fk_evidience_activity foreign key (evidence_activity_id) references Activity (activity_id) - on update cascade + on update cascade, + constraint fk_evidence_created_by + foreign key (evidence_created_by) references User (user_id), + constraint fk_evidence_updated_by + foreign key (evidence_updated_by) references User (user_id) ); @@ -201,12 +255,18 @@ create table if not exists IssueRepository issuerepository_name varchar(2048) not null, issuerepository_url varchar(2048) not null, issuerepository_created_at timestamp default current_timestamp() not null, + issuerepository_created_by int unsigned null, issuerepository_deleted_at timestamp null, issuerepository_updated_at timestamp default current_timestamp() not null on update current_timestamp(), + issuerepository_updated_by int unsigned null, constraint issuerepository_id_UNIQUE unique (issuerepository_id), constraint issuerepository_name_UNIQUE - unique (issuerepository_name) + unique (issuerepository_name), + constraint fk_issuerepository_created_by + foreign key (issuerepository_created_by) references User (user_id), + constraint fk_issuerepository_updated_by + foreign key (issuerepository_updated_by) references User (user_id) ); create table if not exists Issue @@ -217,12 +277,18 @@ create table if not exists Issue issue_primary_name varchar(256) not null, issue_description longtext not null, issue_created_at timestamp default current_timestamp() not null, + issue_created_by int unsigned null, issue_deleted_at timestamp null, issue_updated_at timestamp default current_timestamp() not null on update current_timestamp(), + issue_updated_by int unsigned null, constraint issue_id_UNIQUE unique (issue_id), constraint issue_primary_name_UNIQUE - unique (issue_primary_name) + unique (issue_primary_name), + constraint fk_issue_created_by + foreign key (issue_created_by) references User (user_id), + constraint fk_issue_updated_by + foreign key (issue_updated_by) references User (user_id) ); create table if not exists IssueVariant @@ -236,8 +302,10 @@ create table if not exists IssueVariant issuevariant_secondary_name varchar(256) not null, issuevariant_description longtext not null, issuevariant_created_at timestamp default current_timestamp() not null, + issuevariant_created_by int unsigned null, issuevariant_deleted_at timestamp null, issuevariant_updated_at timestamp default current_timestamp() not null on update current_timestamp(), + issuevariant_updated_by int unsigned null, constraint issuevariant_id_UNIQUE unique (issuevariant_id), constraint issuevariant_secondary_name_UNIQUE @@ -246,7 +314,11 @@ create table if not exists IssueVariant foreign key (issuevariant_issue_id) references Issue (issue_id), constraint fk_issuevariant_issuerepository foreign key (issuevariant_repository_id) references IssueRepository (issuerepository_id) - on update cascade + on update cascade, + constraint fk_issuevariant_created_by + foreign key (issuevariant_created_by) references User (user_id), + constraint fk_issuevariant_updated_by + foreign key (issuevariant_updated_by) references User (user_id) ); create table if not exists ActivityHasIssue @@ -293,8 +365,10 @@ create table if not exists IssueMatch issuematch_component_instance_id int unsigned not null, issuematch_created_at timestamp default current_timestamp() not null, + issuematch_created_by int unsigned null, issuematch_deleted_at timestamp null, issuematch_updated_at timestamp default current_timestamp() not null on update current_timestamp(), + issuematch_updated_by int unsigned null, constraint issuematch_id_UNIQUE unique (issuematch_id), constraint fk_issue_match_user_id @@ -305,7 +379,11 @@ create table if not exists IssueMatch on update cascade, constraint fk_issue_match_issue foreign key (issuematch_issue_id) references Issue (issue_id) - on update cascade + on update cascade, + constraint fk_issuematch_created_by + foreign key (issuematch_created_by) references User (user_id), + constraint fk_issuematch_updated_by + foreign key (issuematch_updated_by) references User (user_id) ); create table if not exists IssueMatchChange @@ -316,12 +394,18 @@ create table if not exists IssueMatchChange issuematchchange_issue_match_id int unsigned not null, issuematchchange_action enum ('add','remove') not null, issuematchchange_created_at timestamp default current_timestamp() not null, + issuematchchange_created_by int unsigned null, issuematchchange_deleted_at timestamp null, issuematchchange_updated_at timestamp default current_timestamp() not null on update current_timestamp(), + issuematchchange_updated_by int unsigned null, constraint fk_issuematchchange_activity foreign key (issuematchchange_activity_id) references Activity (activity_id), constraint fk_issuematchchange_issue_match - foreign key (issuematchchange_issue_match_id) references IssueMatch (issuematch_id) + foreign key (issuematchchange_issue_match_id) references IssueMatch (issuematch_id), + constraint fk_issuematchchange_created_by + foreign key (issuematchchange_created_by) references User (user_id), + constraint fk_issuematchchange_updated_by + foreign key (issuematchchange_updated_by) references User (user_id) ); create table if not exists ComponentVersionIssue @@ -358,9 +442,6 @@ create table if not exists IssueRepositoryService issuerepositoryservice_service_id int unsigned not null, issuerepositoryservice_issue_repository_id int unsigned not null, issuerepositoryservice_priority int unsigned not null, - issuerepositoryservice_created_at timestamp default current_timestamp() not null, - issuerepositoryservice_deleted_at timestamp null, - issuerepositoryservice_updated_at timestamp default current_timestamp() not null on update current_timestamp(), primary key (issuerepositoryservice_service_id, issuerepositoryservice_issue_repository_id), constraint fk_issue_repository_service foreign key (issuerepositoryservice_issue_repository_id) references IssueRepository (issuerepository_id) diff --git a/internal/database/mariadb/issue.go b/internal/database/mariadb/issue.go index ebfb98c7..88e995ac 100644 --- a/internal/database/mariadb/issue.go +++ b/internal/database/mariadb/issue.go @@ -134,6 +134,9 @@ func (s *SqlDatabase) getIssueUpdateFields(issue *entity.Issue) string { if issue.Description != "" { fl = append(fl, "issue_description = :issue_description") } + if issue.UpdatedBy != 0 { + fl = append(fl, "issue_updated_by = :issue_updated_by") + } return strings.Join(fl, ", ") } @@ -404,11 +407,13 @@ func (s *SqlDatabase) CreateIssue(issue *entity.Issue) (*entity.Issue, error) { INSERT INTO Issue ( issue_primary_name, issue_type, - issue_description + issue_description, + issue_created_by ) VALUES ( :issue_primary_name, :issue_type, - :issue_description + :issue_description, + :issue_created_by ) ` diff --git a/internal/database/mariadb/issue_match.go b/internal/database/mariadb/issue_match.go index 015845d6..9e5d1c6b 100644 --- a/internal/database/mariadb/issue_match.go +++ b/internal/database/mariadb/issue_match.go @@ -122,6 +122,9 @@ func (s *SqlDatabase) getIssueMatchUpdateFields(issueMatch *entity.IssueMatch) s if !issueMatch.TargetRemediationDate.IsZero() { fl = append(fl, "issuematch_target_remediation_date = :issuematch_target_remediation_date") } + if issueMatch.UpdatedBy != 0 { + fl = append(fl, "issuematch_updated_by = :issuematch_updated_by") + } return strings.Join(fl, ", ") } @@ -270,7 +273,8 @@ func (s *SqlDatabase) CreateIssueMatch(issueMatch *entity.IssueMatch) (*entity.I issuematch_rating, issuematch_user_id, issuematch_component_instance_id, - issuematch_issue_id + issuematch_issue_id, + issuematch_created_by ) VALUES ( :issuematch_status, :issuematch_remediation_date, @@ -279,7 +283,8 @@ func (s *SqlDatabase) CreateIssueMatch(issueMatch *entity.IssueMatch) (*entity.I :issuematch_rating, :issuematch_user_id, :issuematch_component_instance_id, - :issuematch_issue_id + :issuematch_issue_id, + :issuematch_created_by ) ` diff --git a/internal/database/mariadb/issue_match_change.go b/internal/database/mariadb/issue_match_change.go index 264d295b..f2273254 100644 --- a/internal/database/mariadb/issue_match_change.go +++ b/internal/database/mariadb/issue_match_change.go @@ -46,6 +46,9 @@ func (s *SqlDatabase) getIssueMatchChangeUpdateFields(imc *entity.IssueMatchChan if imc.Action != "" { fl = append(fl, "issuematchchange_action = :issuematchchange_action") } + if imc.UpdatedBy != 0 { + fl = append(fl, "issuematchchange_updated_by = :issuematchchange_updated_by") + } return strings.Join(fl, ", ") } @@ -181,11 +184,13 @@ func (s *SqlDatabase) CreateIssueMatchChange(imc *entity.IssueMatchChange) (*ent INSERT INTO IssueMatchChange ( issuematchchange_action, issuematchchange_activity_id, - issuematchchange_issue_match_id + issuematchchange_issue_match_id, + issuematchchange_created_by ) VALUES ( :issuematchchange_action, :issuematchchange_activity_id, - :issuematchchange_issue_match_id + :issuematchchange_issue_match_id, + :issuematchchange_created_by ) ` diff --git a/internal/database/mariadb/issue_repository.go b/internal/database/mariadb/issue_repository.go index e9f8eef5..74117308 100644 --- a/internal/database/mariadb/issue_repository.go +++ b/internal/database/mariadb/issue_repository.go @@ -46,6 +46,9 @@ func (s *SqlDatabase) getIssueRepositoryUpdateFields(issueRepository *entity.Iss if issueRepository.Url != "" { fl = append(fl, "issuerepository_url = :issuerepository_url") } + if issueRepository.BaseIssueRepository.UpdatedBy != 0 { + fl = append(fl, "issuerepository_updated_by = :issuerepository_updated_by") + } return strings.Join(fl, ", ") } @@ -218,10 +221,12 @@ func (s *SqlDatabase) CreateIssueRepository(issueRepository *entity.IssueReposit query := ` INSERT INTO IssueRepository ( issuerepository_name, - issuerepository_url + issuerepository_url, + issuerepository_created_by ) VALUES ( :issuerepository_name, - :issuerepository_url + :issuerepository_url, + :issuerepository_created_by ) ` diff --git a/internal/database/mariadb/issue_variant.go b/internal/database/mariadb/issue_variant.go index 651a28e7..1cac98b3 100644 --- a/internal/database/mariadb/issue_variant.go +++ b/internal/database/mariadb/issue_variant.go @@ -96,6 +96,9 @@ func (s *SqlDatabase) getIssueVariantUpdateFields(issueVariant *entity.IssueVari if issueVariant.IssueRepositoryId != 0 { fl = append(fl, "issuevariant_repository_id = :issuevariant_repository_id") } + if issueVariant.UpdatedBy != 0 { + fl = append(fl, "issuevariant_updated_by = :issuevariant_updated_by") + } return strings.Join(fl, ", ") } @@ -242,14 +245,16 @@ func (s *SqlDatabase) CreateIssueVariant(issueVariant *entity.IssueVariant) (*en issuevariant_vector, issuevariant_rating, issuevariant_secondary_name, - issuevariant_description + issuevariant_description, + issuevariant_created_by ) VALUES ( :issuevariant_issue_id, :issuevariant_repository_id, :issuevariant_vector, :issuevariant_rating, :issuevariant_secondary_name, - :issuevariant_description + :issuevariant_description, + :issuevariant_created_by ) ` diff --git a/internal/database/mariadb/service.go b/internal/database/mariadb/service.go index 21ff8495..9064115b 100644 --- a/internal/database/mariadb/service.go +++ b/internal/database/mariadb/service.go @@ -134,6 +134,9 @@ func (s *SqlDatabase) getServiceUpdateFields(service *entity.Service) string { if service.CCRN != "" { fl = append(fl, "service_ccrn = :service_ccrn") } + if service.BaseService.UpdatedBy != 0 { + fl = append(fl, "service_updated_by = :service_updated_by") + } return strings.Join(fl, ", ") } @@ -341,9 +344,11 @@ func (s *SqlDatabase) CreateService(service *entity.Service) (*entity.Service, e query := ` INSERT INTO Service ( - service_ccrn + service_ccrn, + service_created_by ) VALUES ( - :service_ccrn + :service_ccrn, + :service_created_by ) ` diff --git a/internal/database/mariadb/service_issue_variant_test.go b/internal/database/mariadb/service_issue_variant_test.go index e10f6d1a..403a3eed 100644 --- a/internal/database/mariadb/service_issue_variant_test.go +++ b/internal/database/mariadb/service_issue_variant_test.go @@ -206,7 +206,7 @@ var _ = Describe("ServiceIssueVariant - ", Label("database", "IssueVariant"), fu BeforeEach(func() { // Create service services = seeder.SeedServices(1) - + // Create issue issues := seeder.SeedIssues(1) issue = issues[0] @@ -228,7 +228,7 @@ var _ = Describe("ServiceIssueVariant - ", Label("database", "IssueVariant"), fu } _, err := seeder.InsertFakeComponentVersionIssue(cvi) Expect(err).To(BeNil()) - + // Create component instance componentInstances = seeder.SeedComponentInstances(1, componentVersions, services) @@ -263,13 +263,13 @@ var _ = Describe("ServiceIssueVariant - ", Label("database", "IssueVariant"), fu It("returns all variants when filtering for the issue", func() { filter := &entity.ServiceIssueVariantFilter{ ComponentInstanceId: []*int64{lo.ToPtr(componentInstances[0].Id.Int64)}, - IssueId: []*int64{lo.ToPtr(issue.Id.Int64)}, + IssueId: []*int64{lo.ToPtr(issue.Id.Int64)}, } res, err := db.GetServiceIssueVariants(filter) Expect(err).To(BeNil()) Expect(res).To(HaveLen(5)) // One variant per repository - + // All variants should be for our issue for _, variant := range res { Expect(variant.IssueId).To(Equal(issue.Id.Int64)) diff --git a/internal/database/mariadb/service_test.go b/internal/database/mariadb/service_test.go index e160fa90..4479f3a9 100644 --- a/internal/database/mariadb/service_test.go +++ b/internal/database/mariadb/service_test.go @@ -775,7 +775,9 @@ var _ = Describe("Service", Label("database", "Service"), func() { seedCollection = seeder.SeedDbWithNFakeData(10) newIssueRepositoryRow = test.NewFakeIssueRepository() newIssueRepository = newIssueRepositoryRow.AsIssueRepository() - issueRepository, _ = db.CreateIssueRepository(&newIssueRepository) + var err error + issueRepository, err = db.CreateIssueRepository(&newIssueRepository) + Expect(err).To(BeNil()) }) It("can add issue repository correctly", func() { service := seedCollection.ServiceRows[0].AsService() diff --git a/internal/database/mariadb/support_group.go b/internal/database/mariadb/support_group.go index f407af2e..024fc031 100644 --- a/internal/database/mariadb/support_group.go +++ b/internal/database/mariadb/support_group.go @@ -28,6 +28,9 @@ func (s *SqlDatabase) getSupportGroupUpdateFields(supportGroup *entity.SupportGr if supportGroup.CCRN != "" { fl = append(fl, "supportgroup_ccrn = :supportgroup_ccrn") } + if supportGroup.UpdatedBy != 0 { + fl = append(fl, "supportgroup_updated_by = :supportgroup_updated_by") + } return strings.Join(fl, ", ") } @@ -206,9 +209,11 @@ func (s *SqlDatabase) CreateSupportGroup(supportGroup *entity.SupportGroup) (*en query := ` INSERT INTO SupportGroup ( - supportgroup_ccrn + supportgroup_ccrn, + supportgroup_created_by ) VALUES ( - :supportgroup_ccrn + :supportgroup_ccrn, + :supportgroup_created_by ) ` diff --git a/internal/database/mariadb/test/database_manager.go b/internal/database/mariadb/test/database_manager.go index d1e30765..8006d2e9 100644 --- a/internal/database/mariadb/test/database_manager.go +++ b/internal/database/mariadb/test/database_manager.go @@ -149,6 +149,7 @@ func (dbm *LocalTestDataBaseManager) NewTestSchema() *mariadb.SqlDatabase { dbm.Schemas = append(dbm.Schemas, schemaName) dbm.CurrentSchema = schemaName dbm.Config.DBName = schemaName + dbm.Config.AuthType = "none" err := dbm.dbClient.SetupSchema(dbm.Config.Config) if err != nil { diff --git a/internal/database/mariadb/test/fixture.go b/internal/database/mariadb/test/fixture.go index e4e36ef3..a62921fe 100644 --- a/internal/database/mariadb/test/fixture.go +++ b/internal/database/mariadb/test/fixture.go @@ -9,6 +9,7 @@ import ( "math/rand" "strings" + "github.com/cloudoperators/heureka/internal/e2e/common" "github.com/cloudoperators/heureka/internal/entity" "github.com/goark/go-cvss/v3/metric" "github.com/onsi/ginkgo/v2/dsl/core" @@ -269,6 +270,7 @@ func GenerateRandomCVSS31Vector() string { } func (s *DatabaseSeeder) SeedDbForServer(n int) *SeedCollection { + users := s.SeedUsers(n) supportGroupsMap := s.SeedRealSupportGroups() supportGroups := lo.Values[string, mariadb.SupportGroupRow](supportGroupsMap) servicesMap := s.SeedRealServices() @@ -279,7 +281,6 @@ func (s *DatabaseSeeder) SeedDbForServer(n int) *SeedCollection { repos := s.SeedIssueRepositories() issues := s.SeedIssues(n) issueVariants := s.SeedIssueVariants(n, repos, issues) - users := s.SeedUsers(n) owners := s.SeedOwners(n, services, users) supportGroupServices := s.SeedRealSupportGroupService(servicesMap, supportGroupsMap) supportGroupUsers := s.SeedSupportGroupUsers(n, users, supportGroups) @@ -319,6 +320,7 @@ func (s *DatabaseSeeder) SeedDbForServer(n int) *SeedCollection { } func (s *DatabaseSeeder) SeedDbWithNFakeData(n int) *SeedCollection { + users := s.SeedUsers(n) supportGroups := s.SeedSupportGroups(n) services := s.SeedServices(n) components := s.SeedComponents(n) @@ -327,7 +329,6 @@ func (s *DatabaseSeeder) SeedDbWithNFakeData(n int) *SeedCollection { repos := s.SeedIssueRepositories() issues := s.SeedIssues(n) issueVariants := s.SeedIssueVariants(n, repos, issues) - users := s.SeedUsers(n) owners := s.SeedOwners(n, services, users) supportGroupServices := s.SeedSupportGroupServices(n/2, services, supportGroups) supportGroupUsers := s.SeedSupportGroupUsers(n/2, users, supportGroups) @@ -371,6 +372,7 @@ func (s *DatabaseSeeder) SeedDbWithFakeData() { } func (s *DatabaseSeeder) SeedDbForNestedIssueVariantTest() *SeedCollection { + users := s.SeedUsers(1) services := s.SeedServices(1) components := s.SeedComponents(1) componentVersions := s.SeedComponentVersions(1, components) @@ -378,7 +380,6 @@ func (s *DatabaseSeeder) SeedDbForNestedIssueVariantTest() *SeedCollection { repos := s.SeedIssueRepositories() issues := s.SeedIssues(1) issueVariants := s.SeedIssueVariants(100, repos, issues) - users := s.SeedUsers(1) issueMatches := s.SeedIssueMatches(1, issues, componentInstances, users) issueRepositoryServices := s.SeedIssueRepositoryServices(len(repos), services, repos) return &SeedCollection{ @@ -417,8 +418,10 @@ func (s *DatabaseSeeder) SeedIssueRepositories() []mariadb.BaseIssueRepositoryRo i := 0 for _, name := range variants { row := mariadb.BaseIssueRepositoryRow{ - Name: sql.NullString{String: fmt.Sprintf("%s-%s", name, gofakeit.UUID()), Valid: true}, - Url: sql.NullString{String: gofakeit.URL(), Valid: true}, + Name: sql.NullString{String: fmt.Sprintf("%s-%s", name, gofakeit.UUID()), Valid: true}, + Url: sql.NullString{String: gofakeit.URL(), Valid: true}, + CreatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, + UpdatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, } id, err := s.InsertFakeBaseIssueRepository(row) if err != nil { @@ -1123,6 +1126,8 @@ func NewFakeIssueMatch() mariadb.IssueMatchRow { Rating: sql.NullString{String: rating, Valid: true}, RemediationDate: sql.NullTime{Time: gofakeit.Date(), Valid: true}, TargetRemediationDate: sql.NullTime{Time: gofakeit.Date(), Valid: true}, + CreatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, + UpdatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, } } @@ -1131,6 +1136,8 @@ func NewFakeIssue() mariadb.IssueRow { PrimaryName: sql.NullString{String: fmt.Sprintf("CVE-%d-%d", gofakeit.Year(), gofakeit.Number(100, 9999999)), Valid: true}, Description: sql.NullString{String: gofakeit.HackerPhrase(), Valid: true}, Type: sql.NullString{String: gofakeit.RandomString(entity.AllIssueTypes), Valid: true}, + CreatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, + UpdatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, } } @@ -1152,21 +1159,27 @@ func NewFakeIssueVariant(repos []mariadb.BaseIssueRepositoryRow, disc []mariadb. Int64: disc[rand.Intn(len(disc))].Id.Int64, Valid: true, }, + CreatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, + UpdatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, } } func NewFakeIssueRepository() mariadb.IssueRepositoryRow { return mariadb.IssueRepositoryRow{ BaseIssueRepositoryRow: mariadb.BaseIssueRepositoryRow{ - Name: sql.NullString{String: fmt.Sprintf("%s-%s", gofakeit.AppName(), gofakeit.UUID()), Valid: true}, - Url: sql.NullString{String: gofakeit.URL(), Valid: true}, + Name: sql.NullString{String: fmt.Sprintf("%s-%s", gofakeit.AppName(), gofakeit.UUID()), Valid: true}, + Url: sql.NullString{String: gofakeit.URL(), Valid: true}, + CreatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, + UpdatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, }, } } func NewFakeBaseService() mariadb.BaseServiceRow { return mariadb.BaseServiceRow{ - CCRN: sql.NullString{String: fmt.Sprintf("%s-%s", gofakeit.AppName(), gofakeit.UUID()), Valid: true}, + CCRN: sql.NullString{String: fmt.Sprintf("%s-%s", gofakeit.AppName(), gofakeit.UUID()), Valid: true}, + CreatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, + UpdatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, } } @@ -1181,7 +1194,9 @@ func NewFakeService() mariadb.ServiceRow { func NewFakeSupportGroup() mariadb.SupportGroupRow { return mariadb.SupportGroupRow{ - CCRN: sql.NullString{String: fmt.Sprintf("%s-%s", gofakeit.AppName(), gofakeit.UUID()), Valid: true}, + CCRN: sql.NullString{String: fmt.Sprintf("%s-%s", gofakeit.AppName(), gofakeit.UUID()), Valid: true}, + CreatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, + UpdatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, } } @@ -1189,14 +1204,18 @@ func NewFakeComponent() mariadb.ComponentRow { types := []string{"containerImage", "virtualMachineImage", "repository"} ccrn := fmt.Sprintf("%s-%d", gofakeit.AppName(), gofakeit.UUID()) return mariadb.ComponentRow{ - CCRN: sql.NullString{String: ccrn, Valid: true}, - Type: sql.NullString{String: gofakeit.RandomString(types), Valid: true}, + CCRN: sql.NullString{String: ccrn, Valid: true}, + Type: sql.NullString{String: gofakeit.RandomString(types), Valid: true}, + CreatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, + UpdatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, } } func NewFakeComponentVersion() mariadb.ComponentVersionRow { return mariadb.ComponentVersionRow{ - Version: sql.NullString{String: gofakeit.AppVersion(), Valid: true}, + Version: sql.NullString{String: gofakeit.AppVersion(), Valid: true}, + CreatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, + UpdatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, } } @@ -1206,8 +1225,10 @@ func NewFakeComponentInstance() mariadb.ComponentInstanceRow { n = n * -1 } return mariadb.ComponentInstanceRow{ - CCRN: sql.NullString{String: gofakeit.UUID(), Valid: true}, - Count: sql.NullInt16{Int16: n, Valid: true}, + CCRN: sql.NullString{String: gofakeit.UUID(), Valid: true}, + Count: sql.NullInt16{Int16: n, Valid: true}, + CreatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, + UpdatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, } } @@ -1229,6 +1250,8 @@ func NewFakeUser() mariadb.UserRow { Name: sql.NullString{String: gofakeit.Name(), Valid: true}, UniqueUserID: sql.NullString{String: uniqueUserId, Valid: true}, Type: sql.NullInt64{Int64: getNextUserType(), Valid: true}, + CreatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, + UpdatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, } } @@ -1247,7 +1270,9 @@ func NewFakeSupportGroupUser() mariadb.SupportGroupUserRow { func NewFakeActivity() mariadb.ActivityRow { status := []string{"open", "closed", "in_progress"} return mariadb.ActivityRow{ - Status: sql.NullString{String: gofakeit.RandomString(status), Valid: true}, + Status: sql.NullString{String: gofakeit.RandomString(status), Valid: true}, + CreatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, + UpdatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, } } @@ -1274,9 +1299,11 @@ func NewFakeEvidence() mariadb.EvidenceRow { String: gofakeit.RandomString(types), Valid: true, }, - Vector: sql.NullString{String: v, Valid: true}, - Rating: sql.NullString{String: rating, Valid: true}, - RAAEnd: sql.NullTime{Time: gofakeit.Date(), Valid: true}, + Vector: sql.NullString{String: v, Valid: true}, + Rating: sql.NullString{String: rating, Valid: true}, + RAAEnd: sql.NullTime{Time: gofakeit.Date(), Valid: true}, + CreatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, + UpdatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, } } @@ -1294,6 +1321,8 @@ func NewFakeIssueMatchChange() mariadb.IssueMatchChangeRow { String: gofakeit.RandomString(entity.AllIssueMatchChangeActions), Valid: true, }, + CreatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, + UpdatedBy: sql.NullInt64{Int64: e2e_common.SystemUserId, Valid: true}, } } diff --git a/internal/database/mariadb/user.go b/internal/database/mariadb/user.go index dea44f59..59078262 100644 --- a/internal/database/mariadb/user.go +++ b/internal/database/mariadb/user.go @@ -62,6 +62,9 @@ func (s *SqlDatabase) getUserUpdateFields(user *entity.User) string { if user.Type != entity.InvalidUserType { fl = append(fl, "user_type = :user_type") } + if user.UpdatedBy != 0 { + fl = append(fl, "user_updated_by = :user_updated_by") + } return strings.Join(fl, ", ") } @@ -178,7 +181,6 @@ func (s *SqlDatabase) GetUsers(filter *entity.UserFilter) ([]entity.User, error) } defer stmt.Close() - return performListScan( stmt, filterParameters, @@ -220,11 +222,13 @@ func (s *SqlDatabase) CreateUser(user *entity.User) (*entity.User, error) { INSERT INTO User ( user_name, user_unique_user_id, - user_type + user_type, + user_created_by ) VALUES ( :user_name, :user_unique_user_id, - :user_type + :user_type, + :user_created_by ) ` diff --git a/internal/database/mariadb/user_test.go b/internal/database/mariadb/user_test.go index 75a86d6f..9e80c14f 100644 --- a/internal/database/mariadb/user_test.go +++ b/internal/database/mariadb/user_test.go @@ -8,6 +8,7 @@ import ( "github.com/cloudoperators/heureka/internal/database/mariadb" "github.com/cloudoperators/heureka/internal/database/mariadb/test" + "github.com/cloudoperators/heureka/internal/e2e/common" "github.com/cloudoperators/heureka/internal/entity" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -28,11 +29,12 @@ var _ = Describe("User", Label("database", "User"), func() { Context("and the database is empty", func() { It("can perform the query", func() { res, err := db.GetAllUserIds(nil) + res = e2e_common.SubtractSystemUserId(res) By("throwing no error", func() { Expect(err).To(BeNil()) }) - By("returning an empty list", func() { + By("returning an empty list of non-system users", func() { Expect(res).To(BeEmpty()) }) }) @@ -50,6 +52,7 @@ var _ = Describe("User", Label("database", "User"), func() { Context("and using no filter", func() { It("can fetch the items correctly", func() { res, err := db.GetAllUserIds(nil) + res = e2e_common.SubtractSystemUserId(res) By("throwing no error", func() { Expect(err).Should(BeNil()) @@ -105,6 +108,7 @@ var _ = Describe("User", Label("database", "User"), func() { Context("and the database is empty", func() { It("can perform the query", func() { res, err := db.GetUsers(nil) + res = e2e_common.SubtractSystemUsersEntity(res) By("throwing no error", func() { Expect(err).To(BeNil()) @@ -123,7 +127,7 @@ var _ = Describe("User", Label("database", "User"), func() { It("can fetch the items correctly", func() { res, err := db.GetUsers(nil) - + res = e2e_common.SubtractSystemUsersEntity(res) By("throwing no error", func() { Expect(err).Should(BeNil()) }) @@ -304,7 +308,7 @@ var _ = Describe("User", Label("database", "User"), func() { }) By("number of human and technical user types should match number of all users", func() { - Expect(len(humanUserEntries) + len(technicalUserEntries)).To(BeEquivalentTo(len(seedCollection.UserRows))) + Expect(e2e_common.SubtractSystemUsers(len(humanUserEntries) + len(technicalUserEntries))).To(BeEquivalentTo(len(seedCollection.UserRows))) }) }) }) @@ -314,6 +318,7 @@ var _ = Describe("User", Label("database", "User"), func() { Context("and the database is empty", func() { It("can count correctly", func() { c, err := db.CountUsers(nil) + c = e2e_common.SubtractSystemUsers(c) By("throwing no error", func() { Expect(err).To(BeNil()) @@ -336,6 +341,7 @@ var _ = Describe("User", Label("database", "User"), func() { Context("and using no filter", func() { It("can count", func() { c, err := db.CountUsers(nil) + c = e2e_common.SubtractSystemUsers(c) By("throwing no error", func() { Expect(err).To(BeNil()) @@ -355,6 +361,7 @@ var _ = Describe("User", Label("database", "User"), func() { }, } c, err := db.CountUsers(filter) + c = e2e_common.SubtractSystemUsers(c) By("throwing no error", func() { Expect(err).To(BeNil()) @@ -545,6 +552,7 @@ var _ = Describe("User", Label("database", "User"), func() { Context("and the database is empty", func() { It("can perform the list query", func() { res, err := db.GetUserNames(nil) + res = e2e_common.SubtractSystemUserNameVL(res) By("throwing no error", func() { Expect(err).To(BeNil()) }) @@ -562,6 +570,7 @@ var _ = Describe("User", Label("database", "User"), func() { Context("and using no filter", func() { It("can fetch the items correctly", func() { res, err := db.GetUserNames(nil) + res = e2e_common.SubtractSystemUserNameVL(res) By("throwing no error", func() { Expect(err).Should(BeNil()) @@ -649,6 +658,7 @@ var _ = Describe("User", Label("database", "User"), func() { Context("and the database is empty", func() { It("can perform the list query", func() { res, err := db.GetUniqueUserIDs(nil) + res = e2e_common.SubtractSystemUserUniqueUserIdVL(res) By("throwing no error", func() { Expect(err).To(BeNil()) }) @@ -666,6 +676,7 @@ var _ = Describe("User", Label("database", "User"), func() { Context("and using no filter", func() { It("can fetch the items correctly", func() { res, err := db.GetUniqueUserIDs(nil) + res = e2e_common.SubtractSystemUserUniqueUserIdVL(res) By("throwing no error", func() { Expect(err).Should(BeNil()) diff --git a/internal/e2e/common/issue.go b/internal/e2e/common/issue.go new file mode 100644 index 00000000..8fc26276 --- /dev/null +++ b/internal/e2e/common/issue.go @@ -0,0 +1,104 @@ +// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors +// SPDX-License-Identifier: Apache-2.0 + +package e2e_common + +import ( + "context" + "fmt" + "os" + + "github.com/cloudoperators/heureka/internal/api/graphql/graph/model" + util2 "github.com/cloudoperators/heureka/pkg/util" + + "github.com/machinebox/graphql" + . "github.com/onsi/gomega" + "github.com/sirupsen/logrus" +) + +type Issue struct { + PrimaryName string + Description string + Type string +} + +func QueryCreateIssue(port string, issue Issue) *model.Issue { + client := graphql.NewClient(fmt.Sprintf("http://localhost:%s/query", port)) + + //@todo may need to make this more fault proof?! What if the test is executed from the root dir? does it still work? + b, err := os.ReadFile("../api/graphql/graph/queryCollection/issue/create.graphql") + Expect(err).To(BeNil()) + str := string(b) + req := graphql.NewRequest(str) + + req.Var("input", map[string]string{ + "primaryName": issue.PrimaryName, + "description": issue.Description, + "type": issue.Type, + }) + + req.Header.Set("Cache-Control", "no-cache") + ctx := context.Background() + + var respData struct { + Issue model.Issue `json:"createIssue"` + } + if err := util2.RequestWithBackoff(func() error { return client.Run(ctx, req, &respData) }); err != nil { + logrus.WithError(err).WithField("request", req).Fatalln("Error while unmarshaling") + } + return &respData.Issue +} + +func QueryUpdateIssue(port string, issue Issue, iid string) *model.Issue { + // create a queryCollection (safe to share across requests) + client := graphql.NewClient(fmt.Sprintf("http://localhost:%s/query", port)) + + //@todo may need to make this more fault proof?! What if the test is executed from the root dir? does it still work? + b, err := os.ReadFile("../api/graphql/graph/queryCollection/issue/update.graphql") + Expect(err).To(BeNil()) + str := string(b) + req := graphql.NewRequest(str) + + req.Var("id", iid) + req.Var("input", map[string]string{ + "description": issue.Description, + "type": issue.Type, + }) + + req.Header.Set("Cache-Control", "no-cache") + ctx := context.Background() + + var respData struct { + Issue model.Issue `json:"updateIssue"` + } + if err := util2.RequestWithBackoff(func() error { return client.Run(ctx, req, &respData) }); err != nil { + logrus.WithError(err).WithField("request", req).Fatalln("Error while unmarshaling") + } + return &respData.Issue +} + +func QueryGetIssue(port string, issuePrimaryName string) *model.IssueConnection { + // create a queryCollection (safe to share across requests) + client := graphql.NewClient(fmt.Sprintf("http://localhost:%s/query", port)) + + //@todo may need to make this more fault proof?! What if the test is executed from the root dir? does it still work? + b, err := os.ReadFile("../api/graphql/graph/queryCollection/issue/listIssues.graphql") + Expect(err).To(BeNil()) + str := string(b) + req := graphql.NewRequest(str) + + req.Var("filter", map[string]string{"primaryName": issuePrimaryName}) + req.Var("first", 1) + req.Var("after", "0") + + req.Header.Set("Cache-Control", "no-cache") + ctx := context.Background() + + var respData struct { + Issues model.IssueConnection `json:"Issues"` + } + if err := util2.RequestWithBackoff(func() error { return client.Run(ctx, req, &respData) }); err != nil { + logrus.WithError(err).WithField("request", req).Fatalln("Error while unmarshaling") + } + return &respData.Issues +} diff --git a/internal/e2e/common/user.go b/internal/e2e/common/user.go new file mode 100644 index 00000000..9c697476 --- /dev/null +++ b/internal/e2e/common/user.go @@ -0,0 +1,169 @@ +// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors +// SPDX-License-Identifier: Apache-2.0 + +package e2e_common + +import ( + "context" + "fmt" + "os" + + "github.com/cloudoperators/heureka/internal/api/graphql/graph/model" + "github.com/cloudoperators/heureka/internal/entity" + util2 "github.com/cloudoperators/heureka/pkg/util" + + "github.com/machinebox/graphql" + . "github.com/onsi/gomega" + "github.com/samber/lo" + "github.com/sirupsen/logrus" +) + +const NumberOfSystemUsers = 1 +const SystemUserId = 1 +const EmptyUserId = -1 + +var SystemUserName = "systemuser" +var SystemUserUniqueUserId = "S0000000" + +type Number interface { + int | int64 +} + +func SubtractSystemUsers[T Number](n T) T { + return n - NumberOfSystemUsers +} + +func SubtractSystemUserName(v []*string) []*string { + return lo.Filter(v, func(val *string, _ int) bool { + return val == nil || *val != SystemUserName + }) +} + +func SubtractSystemUserUniqueUserId(v []*string) []*string { + return lo.Filter(v, func(val *string, _ int) bool { + return val == nil || *val != SystemUserUniqueUserId + }) +} + +func SubtractSystemUserUniqueUserIdVL(v []string) []string { + return lo.Filter(v, func(val string, _ int) bool { + return val != SystemUserUniqueUserId + }) +} + +func SubtractSystemUserNameVL(v []string) []string { + return lo.Filter(v, func(val string, _ int) bool { + return val != SystemUserName + }) +} + +func SubtractSystemUsersEntity(v []entity.User) []entity.User { + return lo.Filter(v, func(val entity.User, _ int) bool { + return val.UniqueUserID != SystemUserUniqueUserId + }) +} + +func SubtractSystemUserId(v []int64) []int64 { + return lo.Filter(v, func(val int64, _ int) bool { + return val != SystemUserId + }) +} + +func ExpectNonSystemUserCount(n, expectedN int) { + Expect(SubtractSystemUsers(n)).To(Equal(expectedN)) +} + +func ExpectNonSystemUserNames(v, expectedV []*string) { + Expect(SubtractSystemUserName(v)).To(Equal(expectedV)) +} + +func ExpectNonSystemUserUniqueUserIds(v, expectedV []*string) { + Expect(SubtractSystemUserUniqueUserId(v)).To(Equal(expectedV)) +} + +type User struct { + UniqueUserID string + Type entity.UserType + Name string +} + +func QueryCreateUser(port string, user User) *model.User { + client := graphql.NewClient(fmt.Sprintf("http://localhost:%s/query", port)) + + //@todo may need to make this more fault proof?! What if the test is executed from the root dir? does it still work? + b, err := os.ReadFile("../api/graphql/graph/queryCollection/user/create.graphql") + Expect(err).To(BeNil()) + str := string(b) + req := graphql.NewRequest(str) + + req.Var("input", map[string]string{ + "uniqueUserId": user.UniqueUserID, + "type": entity.GetUserTypeString(user.Type), + "name": user.Name, + }) + + req.Header.Set("Cache-Control", "no-cache") + ctx := context.Background() + + var respData struct { + User model.User `json:"createUser"` + } + if err := util2.RequestWithBackoff(func() error { return client.Run(ctx, req, &respData) }); err != nil { + logrus.WithError(err).WithField("request", req).Fatalln("Error while unmarshaling") + } + return &respData.User +} + +func QueryUpdateUser(port string, user User, uid string) *model.User { + // create a queryCollection (safe to share across requests) + client := graphql.NewClient(fmt.Sprintf("http://localhost:%s/query", port)) + + //@todo may need to make this more fault proof?! What if the test is executed from the root dir? does it still work? + b, err := os.ReadFile("../api/graphql/graph/queryCollection/user/update.graphql") + Expect(err).To(BeNil()) + str := string(b) + req := graphql.NewRequest(str) + + req.Var("id", uid) + req.Var("input", map[string]string{ + "name": user.Name, + "type": entity.GetUserTypeString(user.Type), + }) + + req.Header.Set("Cache-Control", "no-cache") + ctx := context.Background() + + var respData struct { + User model.User `json:"updateUser"` + } + if err := util2.RequestWithBackoff(func() error { return client.Run(ctx, req, &respData) }); err != nil { + logrus.WithError(err).WithField("request", req).Fatalln("Error while unmarshaling") + } + return &respData.User +} + +func QueryGetUser(port string, uniqueUserId string) *model.UserConnection { + // create a queryCollection (safe to share across requests) + client := graphql.NewClient(fmt.Sprintf("http://localhost:%s/query", port)) + + //@todo may need to make this more fault proof?! What if the test is executed from the root dir? does it still work? + b, err := os.ReadFile("../api/graphql/graph/queryCollection/user/listUsers.graphql") + Expect(err).To(BeNil()) + str := string(b) + req := graphql.NewRequest(str) + + req.Var("filter", map[string]string{"uniqueUserId": uniqueUserId}) + req.Var("first", 1) + req.Var("after", "0") + + req.Header.Set("Cache-Control", "no-cache") + ctx := context.Background() + + var respData struct { + Users model.UserConnection `json:"Users"` + } + if err := util2.RequestWithBackoff(func() error { return client.Run(ctx, req, &respData) }); err != nil { + logrus.WithError(err).WithField("request", req).Fatalln("Error while unmarshaling") + } + return &respData.Users +} diff --git a/internal/e2e/issue_query_test.go b/internal/e2e/issue_query_test.go index f4846d7b..e4bacbec 100644 --- a/internal/e2e/issue_query_test.go +++ b/internal/e2e/issue_query_test.go @@ -199,13 +199,13 @@ var _ = Describe("Getting Issues via API", Label("e2e", "Issues"), func() { Expect(*respData.Issues.PageInfo.PageNumber).To(Equal(1), "Correct page number") }) }) - Context("and we request metadata", Label("withMetadata.graphql"), func() { + Context("and we request metadata", Label("withObjectMetadata.graphql"), func() { It("returns correct metadata counts", func() { // create a queryCollection (safe to share across requests) client := graphql.NewClient(fmt.Sprintf("http://localhost:%s/query", cfg.Port)) //@todo may need to make this more fault proof?! What if the test is executed from the root dir? does it still work? - b, err := os.ReadFile("../api/graphql/graph/queryCollection/issue/withMetadata.graphql") + b, err := os.ReadFile("../api/graphql/graph/queryCollection/issue/withObjectMetadata.graphql") Expect(err).To(BeNil()) str := string(b) @@ -232,10 +232,10 @@ var _ = Describe("Getting Issues via API", Label("e2e", "Issues"), func() { ciCount += *imEdge.Node.ComponentInstance.Count serviceIdSet[imEdge.Node.ComponentInstance.Service.ID] = true } - Expect(issueEdge.Node.Metadata.IssueMatchCount).To(Equal(issueEdge.Node.IssueMatches.TotalCount), "IssueMatchCount is correct") - Expect(issueEdge.Node.Metadata.ComponentInstanceCount).To(Equal(ciCount), "ComponentInstanceCount is correct") - Expect(issueEdge.Node.Metadata.ActivityCount).To(Equal(issueEdge.Node.Activities.TotalCount), "ActivityCount is correct") - Expect(issueEdge.Node.Metadata.ServiceCount).To(Equal(len(serviceIdSet)), "ServiceCount is correct") + Expect(issueEdge.Node.ObjectMetadata.IssueMatchCount).To(Equal(issueEdge.Node.IssueMatches.TotalCount), "IssueMatchCount is correct") + Expect(issueEdge.Node.ObjectMetadata.ComponentInstanceCount).To(Equal(ciCount), "ComponentInstanceCount is correct") + Expect(issueEdge.Node.ObjectMetadata.ActivityCount).To(Equal(issueEdge.Node.Activities.TotalCount), "ActivityCount is correct") + Expect(issueEdge.Node.ObjectMetadata.ServiceCount).To(Equal(len(serviceIdSet)), "ServiceCount is correct") } }) }) @@ -286,7 +286,7 @@ var _ = Describe("Creating Issue via API", Label("e2e", "Issues"), func() { str := string(b) req := graphql.NewRequest(str) - req.Var("input", map[string]string{ + req.Var("input", map[string]interface{}{ "primaryName": issue.PrimaryName, "description": issue.Description, "type": issue.Type.String(), diff --git a/internal/e2e/metadata_test.go b/internal/e2e/metadata_test.go new file mode 100644 index 00000000..bb0d82a9 --- /dev/null +++ b/internal/e2e/metadata_test.go @@ -0,0 +1,123 @@ +// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors +// SPDX-License-Identifier: Apache-2.0 + +package e2e_test + +import ( + "fmt" + "time" + + "github.com/cloudoperators/heureka/internal/api/graphql/graph/model" + "github.com/cloudoperators/heureka/internal/e2e/common" + "github.com/cloudoperators/heureka/internal/entity" + "github.com/cloudoperators/heureka/internal/server" + "github.com/cloudoperators/heureka/internal/util" + util2 "github.com/cloudoperators/heureka/pkg/util" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +const ( + testIssuePrimaryName = "PN-001" + testCreatedIssueDescription = "Created Issue" + testUpdatedIssueDescription = "Updated Issue" + dbDateLayout = "2006-01-02 15:04:05 -0700 MST" +) + +var ( + testCreatedIssueType = entity.IssueTypeVulnerability.String() + testUpdatedIssueType = entity.IssueTypePolicyViolation.String() +) + +func createTestIssue(port string) string { + issue := e2e_common.QueryCreateIssue(port, e2e_common.Issue{PrimaryName: testIssuePrimaryName, Description: testCreatedIssueDescription, Type: testCreatedIssueType}) + Expect(*issue.PrimaryName).To(Equal(testIssuePrimaryName)) + Expect(*issue.Description).To(Equal(testCreatedIssueDescription)) + Expect(issue.Type.String()).To(Equal(testCreatedIssueType)) + return issue.ID +} +func updateTestIssue(port string, iid string) { + issue := e2e_common.QueryUpdateIssue(port, e2e_common.Issue{PrimaryName: testIssuePrimaryName, Description: testUpdatedIssueDescription, Type: testUpdatedIssueType}, iid) + Expect(*issue.PrimaryName).To(Equal(testIssuePrimaryName)) + Expect(*issue.Description).To(Equal(testUpdatedIssueDescription)) + Expect(issue.Type.String()).To(Equal(testUpdatedIssueType)) +} + +func getTestIssue(port string) model.Issue { + issues := e2e_common.QueryGetIssue(port, testIssuePrimaryName) + Expect(issues.TotalCount).To(Equal(1)) + return *issues.Edges[0].Node +} + +var _ = Describe("Creating and updating entity via API", Label("e2e", "Entities"), func() { + var s *server.Server + var cfg util.Config + + BeforeEach(func() { + _ = dbm.NewTestSchema() + + cfg = dbm.DbConfig() + cfg.Port = util2.GetRandomFreePort() + s = server.NewServer(cfg) + + s.NonBlockingStart() + }) + + AfterEach(func() { + s.BlockingStop() + }) + + When("New issue is created via API", func() { + var issue model.Issue + BeforeEach(func() { + createTestIssue(cfg.Port) + issue = getTestIssue(cfg.Port) + }) + It("shall assign CreatedBy and CreatedAt metadata fields and shall keep nil in UpdatedBy, UpdatedAt and DeltedAt metadata fields", func() { + Expect(*issue.Description).To(Equal(testCreatedIssueDescription)) + Expect(issue.Type.String()).To(Equal(testCreatedIssueType)) + + Expect(issue.Metadata).To(Not(BeNil())) + Expect(*issue.Metadata.CreatedBy).To(Equal(fmt.Sprintf("%d", e2e_common.SystemUserId))) + + createdAt, err := time.Parse(dbDateLayout, *issue.Metadata.CreatedAt) + Expect(err).Should(BeNil()) + Expect(createdAt).Should(BeTemporally("~", time.Now().UTC(), 3*time.Second)) + + Expect(*issue.Metadata.UpdatedBy).To(Equal(fmt.Sprintf("%d", e2e_common.EmptyUserId))) + + updatedAt, err := time.Parse(dbDateLayout, *issue.Metadata.UpdatedAt) + Expect(err).Should(BeNil()) + Expect(updatedAt).To(Equal(createdAt)) + }) + }) + When("Issue is updated via API", func() { + var issue model.Issue + BeforeEach(func() { + iid := createTestIssue(cfg.Port) + time.Sleep(1100 * time.Millisecond) + updateTestIssue(cfg.Port, iid) + issue = getTestIssue(cfg.Port) + }) + It("shall assign UpdatedBy and UpdatedAt metadata fields and shall keep nil in DeletedAt metadata field", func() { + Expect(*issue.Description).To(Equal(testUpdatedIssueDescription)) + Expect(issue.Type.String()).To(Equal(testUpdatedIssueType)) + + Expect(issue.Metadata).To(Not(BeNil())) + Expect(*issue.Metadata.CreatedBy).To(Equal(fmt.Sprintf("%d", e2e_common.SystemUserId))) + + createdAt, err := time.Parse(dbDateLayout, *issue.Metadata.CreatedAt) + Expect(err).Should(BeNil()) + Expect(createdAt).Should(BeTemporally("~", time.Now().UTC(), 3*time.Second)) + + Expect(*issue.Metadata.UpdatedBy).To(Equal(fmt.Sprintf("%d", e2e_common.SystemUserId))) + + updatedAt, err := time.Parse(dbDateLayout, *issue.Metadata.UpdatedAt) + Expect(err).Should(BeNil()) + Expect(updatedAt).Should(BeTemporally("~", time.Now().UTC(), 2*time.Second)) + Expect(updatedAt).Should(BeTemporally(">", createdAt)) + }) + }) + +}) diff --git a/internal/e2e/service_filter_query_test.go b/internal/e2e/service_filter_query_test.go index 73ca78a9..3f758965 100644 --- a/internal/e2e/service_filter_query_test.go +++ b/internal/e2e/service_filter_query_test.go @@ -16,6 +16,7 @@ import ( "github.com/cloudoperators/heureka/internal/api/graphql/graph/model" "github.com/cloudoperators/heureka/internal/database/mariadb" "github.com/cloudoperators/heureka/internal/database/mariadb/test" + "github.com/cloudoperators/heureka/internal/e2e/common" "github.com/machinebox/graphql" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -109,7 +110,7 @@ var _ = Describe("Getting ServiceFilterValues via API", Label("e2e", "ServiceFil logrus.WithError(err).WithField("request", req).Fatalln("Error while unmarshaling") } - Expect(respData.ServiceFilterValues.UserName.Values).To(BeEmpty()) + e2e_common.ExpectNonSystemUserNames(respData.ServiceFilterValues.UserName.Values, []*string{}) }) It("returns empty for uniqueUserID", func() { client := graphql.NewClient(fmt.Sprintf("http://localhost:%s/query", cfg.Port)) @@ -130,7 +131,7 @@ var _ = Describe("Getting ServiceFilterValues via API", Label("e2e", "ServiceFil logrus.WithError(err).WithField("request", req).Fatalln("Error while unmarshaling") } - Expect(respData.ServiceFilterValues.UniqueUserID.Values).To(BeEmpty()) + e2e_common.ExpectNonSystemUserUniqueUserIds(respData.ServiceFilterValues.UniqueUserID.Values, []*string{}) }) }) @@ -218,13 +219,13 @@ var _ = Describe("Getting ServiceFilterValues via API", Label("e2e", "ServiceFil logrus.WithError(err).WithField("request", req).Fatalln("Error while unmarshaling") } - Expect(len(respData.ServiceFilterValues.UserName.Values)).To(Equal(len(seedCollection.UserRows))) + e2e_common.ExpectNonSystemUserCount(len(respData.ServiceFilterValues.UserName.Values), len(seedCollection.UserRows)) existingUserNames := lo.Map(seedCollection.UserRows, func(s mariadb.UserRow, index int) string { return s.Name.String }) - for _, name := range respData.ServiceFilterValues.UserName.Values { + for _, name := range e2e_common.SubtractSystemUserName(respData.ServiceFilterValues.UserName.Values) { Expect(lo.Contains(existingUserNames, *name)).To(BeTrue()) } }) @@ -247,13 +248,13 @@ var _ = Describe("Getting ServiceFilterValues via API", Label("e2e", "ServiceFil logrus.WithError(err).WithField("request", req).Fatalln("Error while unmarshaling") } - Expect(len(respData.ServiceFilterValues.UniqueUserID.Values)).To(Equal(len(seedCollection.UserRows))) + e2e_common.ExpectNonSystemUserCount(len(respData.ServiceFilterValues.UniqueUserID.Values), len(seedCollection.UserRows)) existingUniqueUserIds := lo.Map(seedCollection.UserRows, func(s mariadb.UserRow, index int) string { return s.UniqueUserID.String }) - for _, name := range respData.ServiceFilterValues.UniqueUserID.Values { + for _, name := range e2e_common.SubtractSystemUserUniqueUserId(respData.ServiceFilterValues.UniqueUserID.Values) { Expect(lo.Contains(existingUniqueUserIds, *name)).To(BeTrue()) } }) diff --git a/internal/e2e/service_query_test.go b/internal/e2e/service_query_test.go index b7b46656..1742c868 100644 --- a/internal/e2e/service_query_test.go +++ b/internal/e2e/service_query_test.go @@ -119,7 +119,7 @@ var _ = Describe("Getting Services via API", Label("e2e", "Services"), func() { client := graphql.NewClient(fmt.Sprintf("http://localhost:%s/query", cfg.Port)) //@todo may need to make this more fault proof?! What if the test is executed from the root dir? does it still work? - b, err := os.ReadFile("../api/graphql/graph/queryCollection/service/withMetadata.graphql") + b, err := os.ReadFile("../api/graphql/graph/queryCollection/service/withObjectMetadata.graphql") Expect(err).To(BeNil()) str := string(b) @@ -146,8 +146,8 @@ var _ = Describe("Getting Services via API", Label("e2e", "Services"), func() { imCount += ciEdge.Node.IssueMatches.TotalCount ciCount += *ciEdge.Node.Count } - Expect(serviceEdge.Node.Metadata.IssueMatchCount).To(Equal(imCount)) - Expect(serviceEdge.Node.Metadata.ComponentInstanceCount).To(Equal(ciCount)) + Expect(serviceEdge.Node.ObjectMetadata.IssueMatchCount).To(Equal(imCount)) + Expect(serviceEdge.Node.ObjectMetadata.ComponentInstanceCount).To(Equal(ciCount)) } }) diff --git a/internal/e2e/user_query_test.go b/internal/e2e/user_query_test.go index f32fe6c5..7ca75dd7 100644 --- a/internal/e2e/user_query_test.go +++ b/internal/e2e/user_query_test.go @@ -21,6 +21,7 @@ import ( "github.com/sirupsen/logrus" "github.com/cloudoperators/heureka/internal/database/mariadb/test" + "github.com/cloudoperators/heureka/internal/e2e/common" testentity "github.com/cloudoperators/heureka/internal/entity/test" "github.com/cloudoperators/heureka/internal/server" ) @@ -73,8 +74,7 @@ var _ = Describe("Getting Users via API", Label("e2e", "Users"), func() { if err := util2.RequestWithBackoff(func() error { return client.Run(ctx, req, &respData) }); err != nil { logrus.WithError(err).WithField("request", req).Fatalln("Error while unmarshaling") } - - Expect(respData.Users.TotalCount).To(Equal(0)) + e2e_common.ExpectNonSystemUserCount(respData.Users.TotalCount, 0) }) }) @@ -112,7 +112,7 @@ var _ = Describe("Getting Users via API", Label("e2e", "Users"), func() { logrus.WithError(err).WithField("request", req).Fatalln("Error while unmarshaling") } - Expect(respData.Users.TotalCount).To(Equal(len(seedCollection.UserRows))) + e2e_common.ExpectNonSystemUserCount(respData.Users.TotalCount, len(seedCollection.UserRows)) Expect(len(respData.Users.Edges)).To(Equal(5)) }) }) @@ -145,7 +145,7 @@ var _ = Describe("Getting Users via API", Label("e2e", "Users"), func() { }) It("- returns the correct result count", func() { - Expect(respData.Users.TotalCount).To(Equal(len(seedCollection.UserRows))) + e2e_common.ExpectNonSystemUserCount(respData.Users.TotalCount, len(seedCollection.UserRows)) Expect(len(respData.Users.Edges)).To(Equal(5)) }) @@ -188,7 +188,7 @@ var _ = Describe("Getting Users via API", Label("e2e", "Users"), func() { Expect(*respData.Users.PageInfo.HasNextPage).To(BeTrue(), "hasNextPage is set") Expect(*respData.Users.PageInfo.HasPreviousPage).To(BeFalse(), "hasPreviousPage is set") Expect(respData.Users.PageInfo.NextPageAfter).ToNot(BeNil(), "nextPageAfter is set") - Expect(len(respData.Users.PageInfo.Pages)).To(Equal(2), "Correct amount of pages") + Expect(len(respData.Users.PageInfo.Pages)).To(Equal(3), "Correct amount of pages") Expect(*respData.Users.PageInfo.PageNumber).To(Equal(1), "Correct page number") }) }) @@ -229,35 +229,10 @@ var _ = Describe("Creating User via API", Label("e2e", "Users"), func() { Context("and a mutation query is performed", Label("create.graphql"), func() { It("creates new user", func() { - // create a queryCollection (safe to share across requests) - client := graphql.NewClient(fmt.Sprintf("http://localhost:%s/query", cfg.Port)) - - //@todo may need to make this more fault proof?! What if the test is executed from the root dir? does it still work? - b, err := os.ReadFile("../api/graphql/graph/queryCollection/user/create.graphql") - - Expect(err).To(BeNil()) - str := string(b) - req := graphql.NewRequest(str) - - req.Var("input", map[string]string{ - "uniqueUserId": user.UniqueUserID, - "type": entity.GetUserTypeString(user.Type), - "name": user.Name, - }) - - req.Header.Set("Cache-Control", "no-cache") - ctx := context.Background() - - var respData struct { - User model.User `json:"createUser"` - } - if err := util2.RequestWithBackoff(func() error { return client.Run(ctx, req, &respData) }); err != nil { - logrus.WithError(err).WithField("request", req).Fatalln("Error while unmarshaling") - } - - Expect(*respData.User.Name).To(Equal(user.Name)) - Expect(*respData.User.UniqueUserID).To(Equal(user.UniqueUserID)) - Expect(entity.UserType(respData.User.Type)).To(Equal(user.Type)) + respUser := e2e_common.QueryCreateUser(cfg.Port, e2e_common.User{UniqueUserID: user.UniqueUserID, Type: user.Type, Name: user.Name}) + Expect(*respUser.Name).To(Equal(user.Name)) + Expect(*respUser.UniqueUserID).To(Equal(user.UniqueUserID)) + Expect(entity.UserType(respUser.Type)).To(Equal(user.Type)) }) }) }) @@ -295,37 +270,12 @@ var _ = Describe("Updating User via API", Label("e2e", "Users"), func() { Context("and a mutation query is performed", Label("update.graphql"), func() { It("updates user", func() { - // create a queryCollection (safe to share across requests) - client := graphql.NewClient(fmt.Sprintf("http://localhost:%s/query", cfg.Port)) - - //@todo may need to make this more fault proof?! What if the test is executed from the root dir? does it still work? - b, err := os.ReadFile("../api/graphql/graph/queryCollection/user/update.graphql") - - Expect(err).To(BeNil()) - str := string(b) - req := graphql.NewRequest(str) - user := seedCollection.UserRows[0].AsUser() user.Name = "Sauron" - - req.Var("id", fmt.Sprintf("%d", user.Id)) - req.Var("input", map[string]string{ - "name": user.Name, - }) - - req.Header.Set("Cache-Control", "no-cache") - ctx := context.Background() - - var respData struct { - User model.User `json:"updateUser"` - } - if err := util2.RequestWithBackoff(func() error { return client.Run(ctx, req, &respData) }); err != nil { - logrus.WithError(err).WithField("request", req).Fatalln("Error while unmarshaling") - } - - Expect(*respData.User.Name).To(Equal(user.Name)) - Expect(*respData.User.UniqueUserID).To(Equal(user.UniqueUserID)) - Expect(entity.UserType(respData.User.Type)).To(Equal(user.Type)) + respUser := e2e_common.QueryUpdateUser(cfg.Port, e2e_common.User{UniqueUserID: user.UniqueUserID, Name: user.Name, Type: user.Type}, fmt.Sprintf("%d", user.Id)) + Expect(*respUser.Name).To(Equal(user.Name)) + Expect(*respUser.UniqueUserID).To(Equal(user.UniqueUserID)) + Expect(entity.UserType(respUser.Type)).To(Equal(user.Type)) }) }) }) diff --git a/internal/entity/activity.go b/internal/entity/activity.go index 4769e363..2bb0ffa5 100644 --- a/internal/entity/activity.go +++ b/internal/entity/activity.go @@ -3,8 +3,6 @@ package entity -import "time" - type ActivityStatusValue string const ( @@ -36,14 +34,12 @@ var AllActivityStatusValues = []string{ } type Activity struct { + Metadata Id int64 `json:"id"` Status ActivityStatusValue `json:"status"` Service *Service `json:"service,omitempty"` Issues []Issue `json:"issues,omitempty"` Evidences []Evidence `json:"evidences,omitempty"` - CreatedAt time.Time `json:"created_at"` - DeletedAt time.Time `json:"deleted_at,omitempty"` - UpdatedAt time.Time `json:"updated_at"` } func (a *Activity) GetId() int64 { @@ -51,11 +47,9 @@ func (a *Activity) GetId() int64 { } type ActivityHasIssue struct { - ActivityId int64 `json:"activity_id"` - IssueId int64 `json:"issue_id"` - CreatedAt time.Time `json:"created_at"` - DeletedAt time.Time `json:"deleted_at,omitempty"` - UpdatedAt time.Time `json:"updated_at"` + Metadata + ActivityId int64 `json:"activity_id"` + IssueId int64 `json:"issue_id"` } type ActivityAggregations struct { diff --git a/internal/entity/common.go b/internal/entity/common.go index 1a11dac2..f0d26d0f 100644 --- a/internal/entity/common.go +++ b/internal/entity/common.go @@ -17,10 +17,13 @@ import ( type HeurekaEntity interface { Activity | + ActivityAggregations | ActivityHasIssue | IssueVariant | + IssueVariantAggregations | BaseIssueRepository | IssueRepository | + IssueRepositoryAggregations | ResultList | ListOptions | PageInfo | @@ -28,18 +31,23 @@ type HeurekaEntity interface { Severity | Cvss | Component | - ComponentInstanceAggregations | + ComponentAggregations | ComponentInstance | + ComponentInstanceAggregations | ComponentVersion | + ComponentVersionAggregations | Evidence | + EvidenceAggregations | BaseService | Service | ServiceAggregations | ServiceWithAggregations | SupportGroup | + SupportGroupAggregations | SupportGroupService | SupportGroupUser | User | + UserAggregations | IssueWithAggregations | IssueAggregations | Issue | @@ -47,6 +55,7 @@ type HeurekaEntity interface { IssueMatchChange | HeurekaFilter | IssueCount | + IssueTypeCounts | ServiceIssueVariant } @@ -64,7 +73,8 @@ type HeurekaFilter interface { EvidenceFilter | ComponentFilter | ComponentVersionFilter | - IssueRepositoryFilter + IssueRepositoryFilter | + SeverityFilter } type HasCursor interface { @@ -185,3 +195,11 @@ type Cvss struct { Temporal *metric.Temporal Environmental *metric.Environmental } + +type Metadata struct { + CreatedAt time.Time `json:"created_at"` + CreatedBy int64 `json:"created_by"` + UpdatedAt time.Time `json:"updated_at"` + UpdatedBy int64 `json:"updated_by"` + DeletedAt time.Time `json:"deleted_at,omitempty"` +} diff --git a/internal/entity/component.go b/internal/entity/component.go index 45eff250..82d5d959 100644 --- a/internal/entity/component.go +++ b/internal/entity/component.go @@ -3,15 +3,11 @@ package entity -import "time" - type Component struct { - Id int64 `json:"id"` - CCRN string `json:"ccrn"` - Type string `json:"type"` - CreatedAt time.Time `json:"created_at"` - DeletedAt time.Time `json:"deleted_at,omitempty"` - UpdatedAt time.Time `json:"updated_at"` + Metadata + Id int64 `json:"id"` + CCRN string `json:"ccrn"` + Type string `json:"type"` } type ComponentResult struct { diff --git a/internal/entity/component_instance.go b/internal/entity/component_instance.go index d20ad7de..a9249a47 100644 --- a/internal/entity/component_instance.go +++ b/internal/entity/component_instance.go @@ -3,8 +3,6 @@ package entity -import "time" - type ComponentInstanceFilter struct { Paginated IssueMatchId []*int64 `json:"issue_match_id"` @@ -16,7 +14,8 @@ type ComponentInstanceFilter struct { Search []*string `json:"search"` } -type ComponentInstanceAggregations struct{} +type ComponentInstanceAggregations struct { +} type ComponentInstanceResult struct { WithCursor @@ -25,6 +24,7 @@ type ComponentInstanceResult struct { } type ComponentInstance struct { + Metadata Id int64 `json:"id"` CCRN string `json:"ccrn"` Count int16 `json:"count"` @@ -32,7 +32,4 @@ type ComponentInstance struct { ComponentVersionId int64 `db:"componentinstance_component_version_id"` Service *Service `json:"service,omitempty"` ServiceId int64 `db:"componentinstance_service_id"` - CreatedAt time.Time `json:"created_at"` - DeletedAt time.Time `json:"deleted_at,omitempty"` - UpdatedAt time.Time `json:"updated_at"` } diff --git a/internal/entity/component_version.go b/internal/entity/component_version.go index 6ea5d88b..1d76d1f4 100644 --- a/internal/entity/component_version.go +++ b/internal/entity/component_version.go @@ -3,8 +3,6 @@ package entity -import "time" - type ComponentVersionFilter struct { Paginated Id []*int64 `json:"id"` @@ -14,7 +12,8 @@ type ComponentVersionFilter struct { Version []*string `json:"version"` } -type ComponentVersionAggregations struct{} +type ComponentVersionAggregations struct { +} type ComponentVersionResult struct { WithCursor @@ -23,13 +22,11 @@ type ComponentVersionResult struct { } type ComponentVersion struct { + Metadata Id int64 `json:"id"` Version string `json:"version"` Component *Component `json:"component,omitempty"` ComponentId int64 `db:"componentversion_component_id"` ComponentInstances []ComponentInstance `json:"component_instances,omitempty"` Issues []Issue `json:"issues,omitempty"` - CreatedAt time.Time `json:"created_at"` - DeletedAt time.Time `json:"deleted_at,omitempty"` - UpdatedAt time.Time `json:"updated_at"` } diff --git a/internal/entity/evidence.go b/internal/entity/evidence.go index a4e0a0e0..ae6becf5 100644 --- a/internal/entity/evidence.go +++ b/internal/entity/evidence.go @@ -42,6 +42,7 @@ var AllEvidenceTypeValues = []string{ } type Evidence struct { + Metadata Id int64 `json:"id"` Description string `json:"description"` Type EvidenceType `json:"type"` @@ -51,9 +52,6 @@ type Evidence struct { UserId int64 `db:"evidence_author_id"` Activity *Activity `json:"activity,omitempty"` ActivityId int64 `db:"evidence_activity_id"` - CreatedAt time.Time `json:"created_at"` - DeletedAt time.Time `json:"deleted_at,omitempty"` - UpdatedAt time.Time `json:"updated_at"` } type EvidenceFilter struct { @@ -63,7 +61,8 @@ type EvidenceFilter struct { IssueMatchId []*int64 `json:"issue_match_id"` UserId []*int64 `json:"user_id"` } -type EvidenceAggregations struct{} +type EvidenceAggregations struct { +} type EvidenceResult struct { WithCursor diff --git a/internal/entity/issue.go b/internal/entity/issue.go index 95ecb1ef..44e52129 100644 --- a/internal/entity/issue.go +++ b/internal/entity/issue.go @@ -76,6 +76,7 @@ type IssueAggregations struct { } type Issue struct { + Metadata Id int64 `json:"id"` Type IssueType `json:"type"` PrimaryName string `json:"primary_name"` @@ -84,9 +85,6 @@ type Issue struct { IssueMatches []IssueMatch `json:"issue_matches,omitempty"` ComponentVersions []ComponentVersion `json:"component_versions,omitempty"` Activity []Activity `json:"activity,omitempty"` - CreatedAt time.Time `json:"created_at"` - DeletedAt time.Time `json:"deleted_at,omitempty"` - UpdatedAt time.Time `json:"updated_lsat"` } type IssueCount struct { diff --git a/internal/entity/issue_match.go b/internal/entity/issue_match.go index fbd0ea7e..8e020893 100644 --- a/internal/entity/issue_match.go +++ b/internal/entity/issue_match.go @@ -39,6 +39,7 @@ var AllIssueMatchStatusValues = []string{ } type IssueMatch struct { + Metadata Id int64 `json:"id"` Status IssueMatchStatusValue `json:"status"` User *User `json:"user,omitempty"` @@ -51,9 +52,6 @@ type IssueMatch struct { IssueId int64 `json:"issue_id"` RemediationDate time.Time `json:"remediation_date"` TargetRemediationDate time.Time `json:"target_remediation_date"` - CreatedAt time.Time `json:"created_at"` - DeletedAt time.Time `json:"deleted_at,omitempty"` - UpdatedAt time.Time `json:"updated_at"` } type IssueMatchFilter struct { diff --git a/internal/entity/issue_match_change.go b/internal/entity/issue_match_change.go index 416b029a..bbcd54a5 100644 --- a/internal/entity/issue_match_change.go +++ b/internal/entity/issue_match_change.go @@ -3,8 +3,6 @@ package entity -import "time" - type IssueMatchChangeAction string const ( @@ -32,15 +30,13 @@ var AllIssueMatchChangeActions = []string{ } type IssueMatchChange struct { + Metadata Id int64 `json:"id"` ActivityId int64 `json:"activity_id"` Activity *Activity IssueMatchId int64 `json:"issue_match_id"` IssueMatch *IssueMatch - Action string `json:"action"` - CreatedAt time.Time `json:"created_at"` - DeletedAt time.Time `json:"deleted_at"` - UpdatedAt time.Time `json:"updated_at"` + Action string `json:"action"` } type IssueMatchChangeFilter struct { diff --git a/internal/entity/issue_repository.go b/internal/entity/issue_repository.go index 75013371..4456a549 100644 --- a/internal/entity/issue_repository.go +++ b/internal/entity/issue_repository.go @@ -3,17 +3,13 @@ package entity -import "time" - type BaseIssueRepository struct { + Metadata Id int64 `json:"id"` Name string `json:"name"` Url string `json:"url"` IssueVariants []IssueVariant `json:"issue_variants,omitempty"` Services []Service `json:"services,omitempty"` - CreatedAt time.Time `json:"created_at"` - DeletedAt time.Time `json:"deleted_at,omitempty"` - UpdatedAt time.Time `json:"updated_at"` } type IssueRepositoryFilter struct { diff --git a/internal/entity/issue_repository_service.go b/internal/entity/issue_repository_service.go index fddbc449..5005b841 100644 --- a/internal/entity/issue_repository_service.go +++ b/internal/entity/issue_repository_service.go @@ -3,13 +3,9 @@ package entity -import "time" - type IssueRepositoryService struct { - ServiceId int64 `json:"service_id"` - IssueRepositoryId int64 `json:"issue_repository_id"` - Priority int64 `json:"priority"` - CreatedAt time.Time `json:"created_at"` - DeletedAt time.Time `json:"deleted_at,omitempty"` - UpdatedAt time.Time `json:"updated_at"` + Metadata + ServiceId int64 `json:"service_id"` + IssueRepositoryId int64 `json:"issue_repository_id"` + Priority int64 `json:"priority"` } diff --git a/internal/entity/issue_variant.go b/internal/entity/issue_variant.go index 2c4f5b25..3b891740 100644 --- a/internal/entity/issue_variant.go +++ b/internal/entity/issue_variant.go @@ -3,9 +3,8 @@ package entity -import "time" - type IssueVariant struct { + Metadata Id int64 `json:"id"` IssueRepositoryId int64 `json:"issue_repository_id"` IssueRepository *IssueRepository `json:"issue_repository"` @@ -14,9 +13,6 @@ type IssueVariant struct { Issue *Issue `json:"issue"` Severity Severity `json:"severity"` Description string `json:"description"` - CreatedAt time.Time `json:"created_at"` - DeletedAt time.Time `json:"deleted_at,omitempty"` - UpdatedAt time.Time `json:"updated_at"` } type IssueVariantFilter struct { diff --git a/internal/entity/service.go b/internal/entity/service.go index bd034086..2c96629e 100644 --- a/internal/entity/service.go +++ b/internal/entity/service.go @@ -3,9 +3,8 @@ package entity -import "time" - type BaseService struct { + Metadata Id int64 `json:"id"` CCRN string `json:"ccrn"` SupportGroup *SupportGroup `json:"support_group,omitempty"` @@ -13,9 +12,6 @@ type BaseService struct { Owners []User `json:"owners,omitempty"` Activities []Activity `json:"activities,omitempty"` Priority int64 `json:"priority"` - CreatedAt time.Time `json:"created_at"` - DeletedAt time.Time `json:"deleted_at,omitempty"` - UpdatedAt time.Time `json:"updated_at"` } type ServiceAggregations struct { diff --git a/internal/entity/support_group.go b/internal/entity/support_group.go index 75259174..f9d48b6b 100644 --- a/internal/entity/support_group.go +++ b/internal/entity/support_group.go @@ -3,14 +3,10 @@ package entity -import "time" - type SupportGroup struct { - Id int64 `json:"id"` - CCRN string `json:"ccrn"` - CreatedAt time.Time `json:"created_at"` - DeletedAt time.Time `json:"deleted_at,omitempty"` - UpdatedAt time.Time `json:"updated_at"` + Metadata + Id int64 `json:"id"` + CCRN string `json:"ccrn"` } type SupportGroupFilter struct { diff --git a/internal/entity/support_group_service.go b/internal/entity/support_group_service.go index 1e0e42c4..b098a564 100644 --- a/internal/entity/support_group_service.go +++ b/internal/entity/support_group_service.go @@ -3,12 +3,8 @@ package entity -import "time" - type SupportGroupService struct { - SupportGroupId int64 `json:"support_group_id"` - ServiceId int64 `json:"service_id"` - CreatedAt time.Time `json:"created_at"` - DeletedAt time.Time `json:"deleted_at,omitempty"` - UpdatedAt time.Time `json:"updated_at"` + Metadata + SupportGroupId int64 `json:"support_group_id"` + ServiceId int64 `json:"service_id"` } diff --git a/internal/entity/support_group_user.go b/internal/entity/support_group_user.go index e35ad945..d811acff 100644 --- a/internal/entity/support_group_user.go +++ b/internal/entity/support_group_user.go @@ -3,12 +3,8 @@ package entity -import "time" - type SupportGroupUser struct { - SupportGroupId int64 `json:"support_group_id"` - UserId int64 `json:"user_id"` - CreatedAt time.Time `json:"created_at"` - DeletedAt time.Time `json:"deleted_at,omitempty"` - UpdatedAt time.Time `json:"updated_at"` + Metadata + SupportGroupId int64 `json:"support_group_id"` + UserId int64 `json:"user_id"` } diff --git a/internal/entity/test/activity.go b/internal/entity/test/activity.go index a182335b..da70be19 100644 --- a/internal/entity/test/activity.go +++ b/internal/entity/test/activity.go @@ -15,9 +15,11 @@ func NewFakeActivityEntity() entity.Activity { Issues: nil, Evidences: nil, Service: nil, - CreatedAt: gofakeit.Date(), - DeletedAt: gofakeit.Date(), - UpdatedAt: gofakeit.Date(), + Metadata: entity.Metadata{ + CreatedAt: gofakeit.Date(), + DeletedAt: gofakeit.Date(), + UpdatedAt: gofakeit.Date(), + }, } } diff --git a/internal/entity/test/component.go b/internal/entity/test/component.go index 867fae84..425c2d3a 100644 --- a/internal/entity/test/component.go +++ b/internal/entity/test/component.go @@ -10,12 +10,14 @@ import ( func NewFakeComponentEntity() entity.Component { return entity.Component{ - Id: int64(gofakeit.Number(1, 10000000)), - CCRN: gofakeit.Name(), - Type: gofakeit.Word(), - CreatedAt: gofakeit.Date(), - DeletedAt: gofakeit.Date(), - UpdatedAt: gofakeit.Date(), + Id: int64(gofakeit.Number(1, 10000000)), + CCRN: gofakeit.Name(), + Type: gofakeit.Word(), + Metadata: entity.Metadata{ + CreatedAt: gofakeit.Date(), + DeletedAt: gofakeit.Date(), + UpdatedAt: gofakeit.Date(), + }, } } diff --git a/internal/entity/test/component_instance.go b/internal/entity/test/component_instance.go index 217f25cc..d34fc3c4 100644 --- a/internal/entity/test/component_instance.go +++ b/internal/entity/test/component_instance.go @@ -17,9 +17,11 @@ func NewFakeComponentInstanceEntity() entity.ComponentInstance { ComponentVersionId: int64(gofakeit.Number(1, 10000000)), Service: nil, ServiceId: int64(gofakeit.Number(1, 10000000)), - CreatedAt: gofakeit.Date(), - DeletedAt: gofakeit.Date(), - UpdatedAt: gofakeit.Date(), + Metadata: entity.Metadata{ + CreatedAt: gofakeit.Date(), + DeletedAt: gofakeit.Date(), + UpdatedAt: gofakeit.Date(), + }, } } diff --git a/internal/entity/test/component_version.go b/internal/entity/test/component_version.go index a44b32a3..07fff6d2 100644 --- a/internal/entity/test/component_version.go +++ b/internal/entity/test/component_version.go @@ -15,9 +15,11 @@ func NewFakeComponentVersionEntity() entity.ComponentVersion { ComponentId: 0, ComponentInstances: nil, Issues: nil, - CreatedAt: gofakeit.Date(), - DeletedAt: gofakeit.Date(), - UpdatedAt: gofakeit.Date(), + Metadata: entity.Metadata{ + CreatedAt: gofakeit.Date(), + DeletedAt: gofakeit.Date(), + UpdatedAt: gofakeit.Date(), + }, } } diff --git a/internal/entity/test/evidence.go b/internal/entity/test/evidence.go index d0c561b8..ea837675 100644 --- a/internal/entity/test/evidence.go +++ b/internal/entity/test/evidence.go @@ -19,9 +19,11 @@ func NewFakeEvidenceEntity() entity.Evidence { RaaEnd: gofakeit.Date(), Type: entity.NewEvidenceTypeValue(t), Severity: severity, - CreatedAt: gofakeit.Date(), - DeletedAt: gofakeit.Date(), - UpdatedAt: gofakeit.Date(), + Metadata: entity.Metadata{ + CreatedAt: gofakeit.Date(), + DeletedAt: gofakeit.Date(), + UpdatedAt: gofakeit.Date(), + }, } } diff --git a/internal/entity/test/issue.go b/internal/entity/test/issue.go index d233e39a..927f4487 100644 --- a/internal/entity/test/issue.go +++ b/internal/entity/test/issue.go @@ -22,9 +22,11 @@ func NewFakeIssueEntity() entity.Issue { IssueMatches: nil, ComponentVersions: nil, Activity: nil, - CreatedAt: gofakeit.Date(), - DeletedAt: gofakeit.Date(), - UpdatedAt: gofakeit.Date(), + Metadata: entity.Metadata{ + CreatedAt: gofakeit.Date(), + DeletedAt: gofakeit.Date(), + UpdatedAt: gofakeit.Date(), + }, } } diff --git a/internal/entity/test/issue_match.go b/internal/entity/test/issue_match.go index e0b839d0..45ecfc62 100644 --- a/internal/entity/test/issue_match.go +++ b/internal/entity/test/issue_match.go @@ -25,9 +25,11 @@ func NewFakeIssueMatch() entity.IssueMatch { Issue: nil, RemediationDate: gofakeit.Date(), TargetRemediationDate: gofakeit.Date(), - CreatedAt: gofakeit.Date(), - DeletedAt: gofakeit.Date(), - UpdatedAt: gofakeit.Date(), + Metadata: entity.Metadata{ + CreatedAt: gofakeit.Date(), + DeletedAt: gofakeit.Date(), + UpdatedAt: gofakeit.Date(), + }, } } diff --git a/internal/entity/test/issue_match_change.go b/internal/entity/test/issue_match_change.go index ea11442a..b706a086 100644 --- a/internal/entity/test/issue_match_change.go +++ b/internal/entity/test/issue_match_change.go @@ -15,9 +15,11 @@ func NewFakeIssueMatchChange() entity.IssueMatchChange { Action: gofakeit.RandomString(actions), IssueMatch: nil, Activity: nil, - CreatedAt: gofakeit.Date(), - DeletedAt: gofakeit.Date(), - UpdatedAt: gofakeit.Date(), + Metadata: entity.Metadata{ + CreatedAt: gofakeit.Date(), + DeletedAt: gofakeit.Date(), + UpdatedAt: gofakeit.Date(), + }, } } diff --git a/internal/entity/test/issue_repository.go b/internal/entity/test/issue_repository.go index f61af12b..f0c6ecf4 100644 --- a/internal/entity/test/issue_repository.go +++ b/internal/entity/test/issue_repository.go @@ -11,12 +11,14 @@ import ( func NewFakeIssueRepositoryEntity() entity.IssueRepository { return entity.IssueRepository{ BaseIssueRepository: entity.BaseIssueRepository{ - Id: int64(gofakeit.Number(1, 10000000)), - Name: gofakeit.Noun(), - Url: gofakeit.URL(), - CreatedAt: gofakeit.Date(), - DeletedAt: gofakeit.Date(), - UpdatedAt: gofakeit.Date(), + Id: int64(gofakeit.Number(1, 10000000)), + Name: gofakeit.Noun(), + Url: gofakeit.URL(), + Metadata: entity.Metadata{ + CreatedAt: gofakeit.Date(), + DeletedAt: gofakeit.Date(), + UpdatedAt: gofakeit.Date(), + }, }, IssueRepositoryService: entity.IssueRepositoryService{ Priority: int64(gofakeit.Number(1, 10)), diff --git a/internal/entity/test/issue_variant.go b/internal/entity/test/issue_variant.go index 72437b67..7724da6d 100644 --- a/internal/entity/test/issue_variant.go +++ b/internal/entity/test/issue_variant.go @@ -29,9 +29,11 @@ func NewFakeIssueVariantEntity(issue *int64) entity.IssueVariant { Issue: nil, IssueRepositoryId: 0, IssueRepository: nil, - CreatedAt: gofakeit.Date(), - DeletedAt: gofakeit.Date(), - UpdatedAt: gofakeit.Date(), + Metadata: entity.Metadata{ + CreatedAt: gofakeit.Date(), + DeletedAt: gofakeit.Date(), + UpdatedAt: gofakeit.Date(), + }, } } diff --git a/internal/entity/test/service.go b/internal/entity/test/service.go index 50cb5fae..1c8be266 100644 --- a/internal/entity/test/service.go +++ b/internal/entity/test/service.go @@ -16,9 +16,11 @@ func NewFakeServiceEntity() entity.Service { SupportGroup: nil, Activities: nil, Owners: nil, - CreatedAt: gofakeit.Date(), - DeletedAt: gofakeit.Date(), - UpdatedAt: gofakeit.Date(), + Metadata: entity.Metadata{ + CreatedAt: gofakeit.Date(), + DeletedAt: gofakeit.Date(), + UpdatedAt: gofakeit.Date(), + }, }, } } diff --git a/internal/entity/test/support_group.go b/internal/entity/test/support_group.go index 17719720..ac6bcd52 100644 --- a/internal/entity/test/support_group.go +++ b/internal/entity/test/support_group.go @@ -10,11 +10,13 @@ import ( func NewFakeSupportGroupEntity() entity.SupportGroup { return entity.SupportGroup{ - Id: int64(gofakeit.Number(1, 10000000)), - CCRN: gofakeit.AppName(), - CreatedAt: gofakeit.Date(), - DeletedAt: gofakeit.Date(), - UpdatedAt: gofakeit.Date(), + Id: int64(gofakeit.Number(1, 10000000)), + CCRN: gofakeit.AppName(), + Metadata: entity.Metadata{ + CreatedAt: gofakeit.Date(), + DeletedAt: gofakeit.Date(), + UpdatedAt: gofakeit.Date(), + }, } } diff --git a/internal/entity/test/user.go b/internal/entity/test/user.go index c06d95af..0cf39c0e 100644 --- a/internal/entity/test/user.go +++ b/internal/entity/test/user.go @@ -17,9 +17,11 @@ func NewFakeUserEntity() entity.User { Name: gofakeit.Name(), UniqueUserID: uniqueUserId, Type: entity.HumanUserType, - CreatedAt: gofakeit.Date(), - DeletedAt: gofakeit.Date(), - UpdatedAt: gofakeit.Date(), + Metadata: entity.Metadata{ + CreatedAt: gofakeit.Date(), + DeletedAt: gofakeit.Date(), + UpdatedAt: gofakeit.Date(), + }, } } diff --git a/internal/entity/user.go b/internal/entity/user.go index 324a7782..4f373bcd 100644 --- a/internal/entity/user.go +++ b/internal/entity/user.go @@ -3,8 +3,6 @@ package entity -import "time" - type UserType int const ( @@ -14,13 +12,11 @@ const ( ) type User struct { - Id int64 `json:"id"` - Name string `json:"name"` - UniqueUserID string `json:"uniqueUserId"` - Type UserType `json:"type"` - CreatedAt time.Time `json:"created_at"` - DeletedAt time.Time `json:"deleted_at,omitempty"` - UpdatedAt time.Time `json:"updated_at"` + Metadata + Id int64 `json:"id"` + Name string `json:"name"` + UniqueUserID string `json:"uniqueUserId"` + Type UserType `json:"type"` } type UserFilter struct {