From 44ecc4c728489e9cab57e670445084e8544d3856 Mon Sep 17 00:00:00 2001 From: Albin Antony Date: Thu, 2 Nov 2023 23:48:59 +0530 Subject: [PATCH] Fix #444 In privacy dashboard only the latest published version is shown --- internal/dataagreement/dataagreements.go | 57 ++++++++++++++-- .../v2/audit/audit_list_dataagreements.go | 2 +- .../config_list_dataagreements.go | 2 +- .../v2/service/service_list_dataagreements.go | 67 ++++++++----------- internal/revision/revisions.go | 12 ++++ 5 files changed, 91 insertions(+), 49 deletions(-) diff --git a/internal/dataagreement/dataagreements.go b/internal/dataagreement/dataagreements.go index 29d79f1..0bc8120 100644 --- a/internal/dataagreement/dataagreements.go +++ b/internal/dataagreement/dataagreements.go @@ -68,6 +68,11 @@ type DataAgreement struct { IsDeleted bool `json:"-"` } +type DataAgreementWithObjectData struct { + DataAgreement + ObjectData string `json:"objectData"` +} + type DataAgreementRepository struct { DefaultFilter bson.M } @@ -133,7 +138,7 @@ func (darepo *DataAgreementRepository) IsDataAgreementExist(dataAgreementID stri } // CreatePipelineForFilteringDataAgreements This pipeline is used for filtering data agreements -func CreatePipelineForFilteringDataAgreements(organisationId string) ([]primitive.M, error) { +func CreatePipelineForFilteringDataAgreements(organisationId string, removeRevisions bool) ([]primitive.M, error) { var pipeline []bson.M @@ -173,12 +178,14 @@ func CreatePipelineForFilteringDataAgreements(organisationId string) ([]primitiv }, }}}) - // Stage 4 - Remove revisions field - pipeline = append(pipeline, bson.M{ - "$project": bson.M{ - "revisions": 0, - }, - }) + if removeRevisions { + // Stage 4 - Remove revisions field + pipeline = append(pipeline, bson.M{ + "$project": bson.M{ + "revisions": 0, + }, + }) + } return pipeline, nil } @@ -283,3 +290,39 @@ func (darepo *DataAgreementRepository) GetAll() ([]DataAgreement, error) { } return results, nil } + +// GetAllDataAgreementsWithLatestRevisionsObjectData +func GetAllDataAgreementsWithLatestRevisionsObjectData(organisationId string) ([]DataAgreementWithObjectData, error) { + + var results []DataAgreementWithObjectData + + pipeline, err := CreatePipelineForFilteringDataAgreements(organisationId, false) + if err != nil { + return results, err + } + // Stage 4 - Add the object data from revisions + pipeline = append(pipeline, bson.M{"$addFields": bson.M{"objectData": bson.M{ + "$let": bson.M{ + "vars": bson.M{ + "first": bson.M{ + "$arrayElemAt": bson.A{"$revisions", 0}, + }, + }, + "in": "$$first.objectdata", + }, + }}}) + pipeline = append(pipeline, bson.M{"$sort": bson.M{"timestamp": -1}}) + + // Perform the aggregation + cursor, err := Collection().Aggregate(context.Background(), pipeline) + if err != nil { + return results, err + } + defer cursor.Close(context.Background()) + + if err := cursor.All(context.Background(), &results); err != nil { + return results, err + } + + return results, nil +} diff --git a/internal/handler/v2/audit/audit_list_dataagreements.go b/internal/handler/v2/audit/audit_list_dataagreements.go index a4fb401..1e17d75 100644 --- a/internal/handler/v2/audit/audit_list_dataagreements.go +++ b/internal/handler/v2/audit/audit_list_dataagreements.go @@ -32,7 +32,7 @@ func AuditListDataAgreements(w http.ResponseWriter, r *http.Request) { var resp listDataAgreementsResp - pipeline, err := dataagreement.CreatePipelineForFilteringDataAgreements(organisationId) + pipeline, err := dataagreement.CreatePipelineForFilteringDataAgreements(organisationId, true) if err != nil { m := "Failed to create pipeline" common.HandleErrorV2(w, http.StatusInternalServerError, m, err) diff --git a/internal/handler/v2/config/dataagreement/config_list_dataagreements.go b/internal/handler/v2/config/dataagreement/config_list_dataagreements.go index 6aa7a11..e89d594 100644 --- a/internal/handler/v2/config/dataagreement/config_list_dataagreements.go +++ b/internal/handler/v2/config/dataagreement/config_list_dataagreements.go @@ -94,7 +94,7 @@ func ConfigListDataAgreements(w http.ResponseWriter, r *http.Request) { darepo.Init(organisationId) if err != nil && errors.Is(err, LifecycleIsMissingError) { - pipeline, err := dataagreement.CreatePipelineForFilteringDataAgreements(organisationId) + pipeline, err := dataagreement.CreatePipelineForFilteringDataAgreements(organisationId, true) if err != nil { m := "Failed to create pipeline" common.HandleErrorV2(w, http.StatusInternalServerError, m, err) diff --git a/internal/handler/v2/service/service_list_dataagreements.go b/internal/handler/v2/service/service_list_dataagreements.go index 6ce1f7c..b7875ee 100644 --- a/internal/handler/v2/service/service_list_dataagreements.go +++ b/internal/handler/v2/service/service_list_dataagreements.go @@ -1,8 +1,6 @@ package service import ( - "context" - "encoding/json" "errors" "fmt" "log" @@ -13,7 +11,6 @@ import ( "github.com/bb-consent/api/internal/dataagreement" "github.com/bb-consent/api/internal/paginate" "github.com/bb-consent/api/internal/revision" - "go.mongodb.org/mongo-driver/bson" ) // ListDataAgreementsError is an error enumeration for list data agreement API. @@ -47,18 +44,30 @@ func ParseListDataAgreementsQueryParams(r *http.Request) (revisionId string, err return "", RevisionIDIsMissingError } +func activeDataAgreementsFromObjectData(organisationId string) ([]interface{}, error) { + var activeDataAgreements []interface{} + dataAgreements, err := dataagreement.GetAllDataAgreementsWithLatestRevisionsObjectData(organisationId) + if err != nil { + return activeDataAgreements, err + } + + for _, dataAgreement := range dataAgreements { + // Recreate data agreement from revision + activeDataAgreement, err := revision.RecreateDataAgreementFromObjectData(dataAgreement.ObjectData) + if err != nil { + return activeDataAgreements, err + } + activeDataAgreements = append(activeDataAgreements, activeDataAgreement) + } + + return activeDataAgreements, nil +} + type listDataAgreementsResp struct { DataAgreements interface{} `json:"dataAgreements"` Pagination paginate.Pagination `json:"pagination"` } -func returnHTTPResponse(resp interface{}, w http.ResponseWriter) { - response, _ := json.Marshal(resp) - w.Header().Set(config.ContentTypeHeader, config.ContentTypeJSON) - w.WriteHeader(http.StatusOK) - w.Write(response) -} - // ServiceListDataAgreements func ServiceListDataAgreements(w http.ResponseWriter, r *http.Request) { // Headers @@ -73,49 +82,27 @@ func ServiceListDataAgreements(w http.ResponseWriter, r *http.Request) { revisionId, err := ParseListDataAgreementsQueryParams(r) revisionId = common.Sanitize(revisionId) if err != nil && errors.Is(err, RevisionIDIsMissingError) { - lifecycle := config.Complete darepo := dataagreement.DataAgreementRepository{} darepo.Init(organisationId) - pipeline, err := dataagreement.CreatePipelineForFilteringDataAgreementsUsingLifecycle(organisationId, lifecycle) + activeDataAgreements, err := activeDataAgreementsFromObjectData(organisationId) if err != nil { - m := "Failed to create pipeline" - common.HandleErrorV2(w, http.StatusInternalServerError, m, err) + common.HandleErrorV2(w, http.StatusInternalServerError, "Failed to fetch active data agreements", err) return } - // Return liecycle filtered data agreements - var dataAgreements []dataagreement.DataAgreement - pipeline = append(pipeline, bson.M{"$sort": bson.M{"timestamp": -1}}) - query := paginate.PaginateDBObjectsQueryUsingPipeline{ - Pipeline: pipeline, - Collection: dataagreement.Collection(), - Context: context.Background(), - Limit: limit, - Offset: offset, + query := paginate.PaginateObjectsQuery{ + Limit: limit, + Offset: offset, } - result, err := paginate.PaginateDBObjectsUsingPipeline(query, &dataAgreements) - if err != nil { - if errors.Is(err, paginate.EmptyDBError) { - emptyDataAgreements := make([]interface{}, 0) - resp = listDataAgreementsResp{ - DataAgreements: emptyDataAgreements, - Pagination: result.Pagination, - } - returnHTTPResponse(resp, w) - return - } - m := "Failed to paginate data agreement" - common.HandleErrorV2(w, http.StatusInternalServerError, m, err) - return + result := paginate.PaginateObjects(query, activeDataAgreements) - } resp = listDataAgreementsResp{ DataAgreements: result.Items, Pagination: result.Pagination, } - returnHTTPResponse(resp, w) + common.ReturnHTTPResponse(resp, w) return } else { @@ -153,5 +140,5 @@ func ServiceListDataAgreements(w http.ResponseWriter, r *http.Request) { } - returnHTTPResponse(resp, w) + common.ReturnHTTPResponse(resp, w) } diff --git a/internal/revision/revisions.go b/internal/revision/revisions.go index 8f027dd..d8c1d79 100644 --- a/internal/revision/revisions.go +++ b/internal/revision/revisions.go @@ -384,6 +384,18 @@ func CreateRevisionForDraftDataAgreement(newDataAgreement dataagreement.DataAgre return revision, err } +func RecreateDataAgreementFromObjectData(objectData string) (interface{}, error) { + + // Deserialise data agreement + var da interface{} + err := json.Unmarshal([]byte(objectData), &da) + if err != nil { + return nil, err + } + + return da, nil +} + type dataAgreementRecordForObjectData struct { Id primitive.ObjectID `json:"id" bson:"_id,omitempty"` DataAgreementId string `json:"dataAgreementId"`