diff --git a/dataset/client.go b/dataset/client.go index 3c84a93..c1cf7cc 100644 --- a/dataset/client.go +++ b/dataset/client.go @@ -18,10 +18,12 @@ type DatasetClient interface { GetEdition(ctx context.Context, userAuthToken, serviceAuthToken, collectionID, datasetID, edition string) (m datasetclient.Edition, err error) GetEditions(ctx context.Context, userAuthToken, serviceAuthToken, collectionID, datasetID string) (m []datasetclient.Edition, err error) GetVersion(ctx context.Context, userAuthToken, serviceAuthToken, downloadServiceAuthToken, collectionID, datasetID, edition, version string) (m datasetclient.Version, err error) + GetVersionWithHeaders(ctx context.Context, userAuthToken, serviceAuthToken, downloadServiceAuthToken, collectionID, datasetID, edition, version string) (datasetclient.Version, datasetclient.ResponseHeaders, error) GetInstance(ctx context.Context, userAuthToken, serviceAuthToken, collectionID, instanceID, ifMatch string) (i datasetclient.Instance, eTag string, err error) PutDataset(ctx context.Context, userAuthToken, serviceAuthToken, collectionID, datasetID string, d datasetclient.DatasetDetails) error PutVersion(ctx context.Context, userAuthToken, serviceAuthToken, collectionID, datasetID, edition, version string, v datasetclient.Version) error PutInstance(ctx context.Context, userAuthToken, serviceAuthToken, collectionID, instanceID string, i datasetclient.UpdateInstance, ifMatch string) (eTag string, err error) + PutMetadata(ctx context.Context, userAuthToken, serviceAuthToken, collectionID, datasetID, edition, version string, metadata datasetclient.EditableMetadata, versionEtag string) error } type ZebedeeClient interface { diff --git a/dataset/get-metadata.go b/dataset/get-metadata.go index 1c81946..597cf87 100644 --- a/dataset/get-metadata.go +++ b/dataset/get-metadata.go @@ -53,7 +53,7 @@ func getEditMetadataHandler(w http.ResponseWriter, req *http.Request, dc Dataset "version": version, } - v, err := dc.GetVersion(ctx, userAccessToken, "", "", collectionID, datasetID, edition, version) + v, headers, err := dc.GetVersionWithHeaders(ctx, userAccessToken, "", "", collectionID, datasetID, edition, version) if err != nil { log.Error(ctx, "failed Get version details", err, log.Data(logInfo)) setErrorStatusCode(req, w, err, datasetID) @@ -85,9 +85,10 @@ func getEditMetadataHandler(w http.ResponseWriter, req *http.Request, dc Dataset return } - p := mapper.EditMetadata(d.Next, v, dims, c) + editMetadata := mapper.EditMetadata(d.Next, v, dims, c) + editMetadata.VersionEtag = headers.ETag - b, err := json.Marshal(p) + b, err := json.Marshal(editMetadata) if err != nil { log.Error(ctx, "failed marshalling page into bytes", err) setErrorStatusCode(req, w, err, datasetID) diff --git a/dataset/get-metadata_test.go b/dataset/get-metadata_test.go index e0f4d00..d1495cf 100644 --- a/dataset/get-metadata_test.go +++ b/dataset/get-metadata_test.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "errors" - "io/ioutil" "net/http" "net/http/httptest" "testing" @@ -37,13 +36,11 @@ func doTestRequest(target string, req *http.Request, handlerFunc http.HandlerFun func TestUnitHandlers(t *testing.T) { t.Parallel() - const mockUserAuthToken = "" - const mockServiceAuthToken = "" - const mockDownloadToken = "" - const mockCollectionID = "" + const mockUserAuthToken = "testuser" const mockDatasetID = "bar" const mockEdition = "baz" const mockVersionNum = "1" + const mockCollectionId = "test-collection" mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() @@ -61,8 +58,9 @@ func TestUnitHandlers(t *testing.T) { Convey("test getEditMetadataHandler", t, func() { mockDatasetDetails := dataset.DatasetDetails{ - ID: "test-dataset", - Links: dataset.Links{LatestVersion: dataset.Link{URL: "/v1/datasets/test/editions/test/version/1"}}, + ID: "test-dataset", + CollectionID: mockCollectionId, + Links: dataset.Links{LatestVersion: dataset.Link{URL: "/v1/datasets/test/editions/test/version/1"}}, } mockDataset := dataset.Dataset{ @@ -75,78 +73,96 @@ func TestUnitHandlers(t *testing.T) { Version: 1, } + datasetCollectionItem := zebedee.CollectionItem{ + ID: mockDatasetDetails.ID, + State: "inProgress", + LastEditedBy: "an-user", + } + mockCollection := zebedee.Collection{ - ID: "test-collection", + ID: mockCollectionId, Datasets: []zebedee.CollectionItem{ + { - ID: "foo", - State: "inProgress", + ID: "foo", + State: "reviewed", + LastEditedBy: "other-user", }, + datasetCollectionItem, }, } + responseHeaders := dataset.ResponseHeaders{ETag: "version-etag"} + mockZebedeeClient := &ZebedeeClientMock{ GetCollectionFunc: func(ctx context.Context, userAccessToken, collectionID string) (c zebedeeclient.Collection, err error) { - return mockCollection, nil + if collectionID == mockCollectionId { + return mockCollection, nil + } else { + return c, errors.New("collection not found") + } }, } - Convey("when Version.State is NOT edition-confirmed returns correctly with empty dimensions struct", func() { + mockDatasetClient := &DatasetClientMock{ + GetDatasetCurrentAndNextFunc: func(ctx context.Context, userAuthToken, serviceAuthToken, collectionID, datasetID string) (m datasetclient.Dataset, err error) { + return mockDataset, nil + }, + GetVersionFunc: func(ctx context.Context, userAuthToken, serviceAuthToken, downloadServiceAuthToken, collectionID, datasetID, edition, version string) (datasetclient.Version, error) { + return mockVersionDetails, nil + }, + GetVersionWithHeadersFunc: func(ctx context.Context, userAuthToken, serviceAuthToken, downloadServiceAuthToken, collectionID, datasetID, edition, version string) (datasetclient.Version, datasetclient.ResponseHeaders, error) { + return mockVersionDetails, responseHeaders, nil + }, + } - mockDatasetClient := &DatasetClientMock{ - GetDatasetCurrentAndNextFunc: func(ctx context.Context, userAuthToken, serviceAuthToken, collectionID, datasetID string) (m datasetclient.Dataset, err error) { - return mockDataset, nil - }, - GetVersionFunc: func(ctx context.Context, userAuthToken, serviceAuthToken, downloadServiceAuthToken, collectionID, datasetID, edition, version string) (m datasetclient.Version, err error) { - return mockVersionDetails, nil - }, - } + Convey("when Version.State is NOT edition-confirmed returns correctly with empty dimensions struct", func() { + mockVersionDetails.State = "associated" req := httptest.NewRequest("GET", "/datasets/bar/editions/baz/versions/1", nil) - req.Header.Set("Collection-Id", "testcollection") - req.Header.Set("X-Florence-Token", "testuser") + req.Header.Set("Collection-Id", mockCollectionId) + req.Header.Set("X-Florence-Token", mockUserAuthToken) w := doTestRequest("/datasets/{datasetID}/editions/{editionID}/versions/{versionID}", req, GetMetadataHandler(mockDatasetClient, mockZebedeeClient), nil) So(w.Code, ShouldEqual, http.StatusOK) So(w.Body.String(), ShouldNotBeNil) + + var body model.EditMetadata + err := json.Unmarshal(w.Body.Bytes(), &body) + So(err, ShouldBeNil) + So(body.Version, ShouldResemble, mockVersionDetails) + So(body.Dataset, ShouldResemble, *mockDataset.Next) + So(body.Dimensions, ShouldBeEmpty) + So(body.VersionEtag, ShouldEqual, responseHeaders.ETag) + So(body.CollectionID, ShouldEqual, mockCollectionId) + So(body.CollectionState, ShouldEqual, datasetCollectionItem.State) + So(body.CollectionLastEditedBy, ShouldEqual, datasetCollectionItem.LastEditedBy) }) Convey("when Version.State is edition-confirmed returns correctly with populated dimensions struct", func() { + mockVersionDetails.State = "edition-confirmed" + mockVersionDetails.Version = 2 - mockVersion := mockVersionDetails - mockVersion.State = "edition-confirmed" - mockVersion.Version = 2 - - var count int - mockDatasetClient := &DatasetClientMock{ - GetDatasetCurrentAndNextFunc: func(ctx context.Context, userAuthToken, serviceAuthToken, collectionID, datasetID string) (m datasetclient.Dataset, err error) { - return mockDataset, nil - }, - GetVersionFunc: func(ctx context.Context, userAuthToken, serviceAuthToken, downloadServiceAuthToken, collectionID, datasetID, edition, version string) (m datasetclient.Version, err error) { - var data datasetclient.Version - if count == 0 { - data = mockVersion - } - if count == 1 { - data = datasetclient.Version{Dimensions: []datasetclient.VersionDimension{{ID: "dim001", Label: "Test dimension"}}} - } - count++ - return data, nil - }, - } + mockVersionDetails.Dimensions = []datasetclient.VersionDimension{{ID: "dim001", Label: "Test dimension"}} req := httptest.NewRequest("GET", "/datasets/bar/editions/baz/versions/1", nil) - req.Header.Set("Collection-Id", "testcollection") - req.Header.Set("X-Florence-Token", "testuser") + req.Header.Set("Collection-Id", mockCollectionId) + req.Header.Set("X-Florence-Token", mockUserAuthToken) w := doTestRequest("/datasets/{datasetID}/editions/{editionID}/versions/{versionID}", req, GetMetadataHandler(mockDatasetClient, mockZebedeeClient), nil) So(w.Code, ShouldEqual, http.StatusOK) + So(w.Body.String(), ShouldNotBeNil) + var body model.EditMetadata - b, _ := ioutil.ReadAll(w.Body) - _ = json.Unmarshal(b, &body) - So(body.Dataset.ID, ShouldEqual, "test-dataset") - So(body.Version.ID, ShouldEqual, "test-version") - So(len(body.Dimensions), ShouldBeGreaterThan, 0) + err := json.Unmarshal(w.Body.Bytes(), &body) + So(err, ShouldBeNil) + So(body.Version, ShouldResemble, mockVersionDetails) + So(body.Dataset, ShouldResemble, *mockDataset.Next) + So(body.Dimensions, ShouldResemble, mockVersionDetails.Dimensions) + So(body.VersionEtag, ShouldEqual, responseHeaders.ETag) + So(body.CollectionID, ShouldEqual, mockCollectionId) + So(body.CollectionState, ShouldEqual, datasetCollectionItem.State) + So(body.CollectionLastEditedBy, ShouldEqual, datasetCollectionItem.LastEditedBy) }) }) diff --git a/dataset/mocks_test.go b/dataset/mocks_test.go index c005033..0890b4b 100644 --- a/dataset/mocks_test.go +++ b/dataset/mocks_test.go @@ -17,49 +17,55 @@ var _ DatasetClient = &DatasetClientMock{} // DatasetClientMock is a mock implementation of DatasetClient. // -// func TestSomethingThatUsesDatasetClient(t *testing.T) { +// func TestSomethingThatUsesDatasetClient(t *testing.T) { // -// // make and configure a mocked DatasetClient -// mockedDatasetClient := &DatasetClientMock{ -// GetFunc: func(ctx context.Context, userAuthToken string, serviceAuthToken string, collectionID string, datasetID string) (datasetclient.DatasetDetails, error) { -// panic("mock out the Get method") -// }, -// GetDatasetCurrentAndNextFunc: func(ctx context.Context, userAuthToken string, serviceAuthToken string, collectionID string, datasetID string) (datasetclient.Dataset, error) { -// panic("mock out the GetDatasetCurrentAndNext method") -// }, -// GetDatasetsInBatchesFunc: func(ctx context.Context, userAuthToken string, serviceAuthToken string, collectionID string, batchSize int, maxWorkers int) (datasetclient.List, error) { -// panic("mock out the GetDatasetsInBatches method") -// }, -// GetEditionFunc: func(ctx context.Context, userAuthToken string, serviceAuthToken string, collectionID string, datasetID string, edition string) (datasetclient.Edition, error) { -// panic("mock out the GetEdition method") -// }, -// GetEditionsFunc: func(ctx context.Context, userAuthToken string, serviceAuthToken string, collectionID string, datasetID string) ([]datasetclient.Edition, error) { -// panic("mock out the GetEditions method") -// }, -// GetInstanceFunc: func(ctx context.Context, userAuthToken string, serviceAuthToken string, collectionID string, instanceID string, ifMatch string) (datasetclient.Instance, string, error) { -// panic("mock out the GetInstance method") -// }, -// GetVersionFunc: func(ctx context.Context, userAuthToken string, serviceAuthToken string, downloadServiceAuthToken string, collectionID string, datasetID string, edition string, version string) (datasetclient.Version, error) { -// panic("mock out the GetVersion method") -// }, -// GetVersionsInBatchesFunc: func(ctx context.Context, userAuthToken string, serviceAuthToken string, downloadServiceAuthToken string, collectionID string, datasetID string, edition string, batchSize int, maxWorkers int) (datasetclient.VersionsList, error) { -// panic("mock out the GetVersionsInBatches method") -// }, -// PutDatasetFunc: func(ctx context.Context, userAuthToken string, serviceAuthToken string, collectionID string, datasetID string, d datasetclient.DatasetDetails) error { -// panic("mock out the PutDataset method") -// }, -// PutInstanceFunc: func(ctx context.Context, userAuthToken string, serviceAuthToken string, collectionID string, instanceID string, i datasetclient.UpdateInstance, ifMatch string) (string, error) { -// panic("mock out the PutInstance method") -// }, -// PutVersionFunc: func(ctx context.Context, userAuthToken string, serviceAuthToken string, collectionID string, datasetID string, edition string, version string, v datasetclient.Version) error { -// panic("mock out the PutVersion method") -// }, -// } +// // make and configure a mocked DatasetClient +// mockedDatasetClient := &DatasetClientMock{ +// GetFunc: func(ctx context.Context, userAuthToken string, serviceAuthToken string, collectionID string, datasetID string) (datasetclient.DatasetDetails, error) { +// panic("mock out the Get method") +// }, +// GetDatasetCurrentAndNextFunc: func(ctx context.Context, userAuthToken string, serviceAuthToken string, collectionID string, datasetID string) (datasetclient.Dataset, error) { +// panic("mock out the GetDatasetCurrentAndNext method") +// }, +// GetDatasetsInBatchesFunc: func(ctx context.Context, userAuthToken string, serviceAuthToken string, collectionID string, batchSize int, maxWorkers int) (datasetclient.List, error) { +// panic("mock out the GetDatasetsInBatches method") +// }, +// GetEditionFunc: func(ctx context.Context, userAuthToken string, serviceAuthToken string, collectionID string, datasetID string, edition string) (datasetclient.Edition, error) { +// panic("mock out the GetEdition method") +// }, +// GetEditionsFunc: func(ctx context.Context, userAuthToken string, serviceAuthToken string, collectionID string, datasetID string) ([]datasetclient.Edition, error) { +// panic("mock out the GetEditions method") +// }, +// GetInstanceFunc: func(ctx context.Context, userAuthToken string, serviceAuthToken string, collectionID string, instanceID string, ifMatch string) (datasetclient.Instance, string, error) { +// panic("mock out the GetInstance method") +// }, +// GetVersionFunc: func(ctx context.Context, userAuthToken string, serviceAuthToken string, downloadServiceAuthToken string, collectionID string, datasetID string, edition string, version string) (datasetclient.Version, error) { +// panic("mock out the GetVersion method") +// }, +// GetVersionWithHeadersFunc: func(ctx context.Context, userAuthToken string, serviceAuthToken string, downloadServiceAuthToken string, collectionID string, datasetID string, edition string, version string) (datasetclient.Version, datasetclient.ResponseHeaders, error) { +// panic("mock out the GetVersionWithHeaders method") +// }, +// GetVersionsInBatchesFunc: func(ctx context.Context, userAuthToken string, serviceAuthToken string, downloadServiceAuthToken string, collectionID string, datasetID string, edition string, batchSize int, maxWorkers int) (datasetclient.VersionsList, error) { +// panic("mock out the GetVersionsInBatches method") +// }, +// PutDatasetFunc: func(ctx context.Context, userAuthToken string, serviceAuthToken string, collectionID string, datasetID string, d datasetclient.DatasetDetails) error { +// panic("mock out the PutDataset method") +// }, +// PutInstanceFunc: func(ctx context.Context, userAuthToken string, serviceAuthToken string, collectionID string, instanceID string, i datasetclient.UpdateInstance, ifMatch string) (string, error) { +// panic("mock out the PutInstance method") +// }, +// PutMetadataFunc: func(ctx context.Context, userAuthToken string, serviceAuthToken string, collectionID string, datasetID string, edition string, version string, metadata datasetclient.EditableMetadata, versionEtag string) error { +// panic("mock out the PutMetadata method") +// }, +// PutVersionFunc: func(ctx context.Context, userAuthToken string, serviceAuthToken string, collectionID string, datasetID string, edition string, version string, v datasetclient.Version) error { +// panic("mock out the PutVersion method") +// }, +// } // -// // use mockedDatasetClient in code that requires DatasetClient -// // and then make assertions. +// // use mockedDatasetClient in code that requires DatasetClient +// // and then make assertions. // -// } +// } type DatasetClientMock struct { // GetFunc mocks the Get method. GetFunc func(ctx context.Context, userAuthToken string, serviceAuthToken string, collectionID string, datasetID string) (datasetclient.DatasetDetails, error) @@ -82,6 +88,9 @@ type DatasetClientMock struct { // GetVersionFunc mocks the GetVersion method. GetVersionFunc func(ctx context.Context, userAuthToken string, serviceAuthToken string, downloadServiceAuthToken string, collectionID string, datasetID string, edition string, version string) (datasetclient.Version, error) + // GetVersionWithHeadersFunc mocks the GetVersionWithHeaders method. + GetVersionWithHeadersFunc func(ctx context.Context, userAuthToken string, serviceAuthToken string, downloadServiceAuthToken string, collectionID string, datasetID string, edition string, version string) (datasetclient.Version, datasetclient.ResponseHeaders, error) + // GetVersionsInBatchesFunc mocks the GetVersionsInBatches method. GetVersionsInBatchesFunc func(ctx context.Context, userAuthToken string, serviceAuthToken string, downloadServiceAuthToken string, collectionID string, datasetID string, edition string, batchSize int, maxWorkers int) (datasetclient.VersionsList, error) @@ -91,6 +100,9 @@ type DatasetClientMock struct { // PutInstanceFunc mocks the PutInstance method. PutInstanceFunc func(ctx context.Context, userAuthToken string, serviceAuthToken string, collectionID string, instanceID string, i datasetclient.UpdateInstance, ifMatch string) (string, error) + // PutMetadataFunc mocks the PutMetadata method. + PutMetadataFunc func(ctx context.Context, userAuthToken string, serviceAuthToken string, collectionID string, datasetID string, edition string, version string, metadata datasetclient.EditableMetadata, versionEtag string) error + // PutVersionFunc mocks the PutVersion method. PutVersionFunc func(ctx context.Context, userAuthToken string, serviceAuthToken string, collectionID string, datasetID string, edition string, version string, v datasetclient.Version) error @@ -199,6 +211,25 @@ type DatasetClientMock struct { // Version is the version argument value. Version string } + // GetVersionWithHeaders holds details about calls to the GetVersionWithHeaders method. + GetVersionWithHeaders []struct { + // Ctx is the ctx argument value. + Ctx context.Context + // UserAuthToken is the userAuthToken argument value. + UserAuthToken string + // ServiceAuthToken is the serviceAuthToken argument value. + ServiceAuthToken string + // DownloadServiceAuthToken is the downloadServiceAuthToken argument value. + DownloadServiceAuthToken string + // CollectionID is the collectionID argument value. + CollectionID string + // DatasetID is the datasetID argument value. + DatasetID string + // Edition is the edition argument value. + Edition string + // Version is the version argument value. + Version string + } // GetVersionsInBatches holds details about calls to the GetVersionsInBatches method. GetVersionsInBatches []struct { // Ctx is the ctx argument value. @@ -252,6 +283,27 @@ type DatasetClientMock struct { // IfMatch is the ifMatch argument value. IfMatch string } + // PutMetadata holds details about calls to the PutMetadata method. + PutMetadata []struct { + // Ctx is the ctx argument value. + Ctx context.Context + // UserAuthToken is the userAuthToken argument value. + UserAuthToken string + // ServiceAuthToken is the serviceAuthToken argument value. + ServiceAuthToken string + // CollectionID is the collectionID argument value. + CollectionID string + // DatasetID is the datasetID argument value. + DatasetID string + // Edition is the edition argument value. + Edition string + // Version is the version argument value. + Version string + // Metadata is the metadata argument value. + Metadata datasetclient.EditableMetadata + // VersionEtag is the versionEtag argument value. + VersionEtag string + } // PutVersion holds details about calls to the PutVersion method. PutVersion []struct { // Ctx is the ctx argument value. @@ -279,9 +331,11 @@ type DatasetClientMock struct { lockGetEditions sync.RWMutex lockGetInstance sync.RWMutex lockGetVersion sync.RWMutex + lockGetVersionWithHeaders sync.RWMutex lockGetVersionsInBatches sync.RWMutex lockPutDataset sync.RWMutex lockPutInstance sync.RWMutex + lockPutMetadata sync.RWMutex lockPutVersion sync.RWMutex } @@ -311,7 +365,8 @@ func (mock *DatasetClientMock) Get(ctx context.Context, userAuthToken string, se // GetCalls gets all the calls that were made to Get. // Check the length with: -// len(mockedDatasetClient.GetCalls()) +// +// len(mockedDatasetClient.GetCalls()) func (mock *DatasetClientMock) GetCalls() []struct { Ctx context.Context UserAuthToken string @@ -358,7 +413,8 @@ func (mock *DatasetClientMock) GetDatasetCurrentAndNext(ctx context.Context, use // GetDatasetCurrentAndNextCalls gets all the calls that were made to GetDatasetCurrentAndNext. // Check the length with: -// len(mockedDatasetClient.GetDatasetCurrentAndNextCalls()) +// +// len(mockedDatasetClient.GetDatasetCurrentAndNextCalls()) func (mock *DatasetClientMock) GetDatasetCurrentAndNextCalls() []struct { Ctx context.Context UserAuthToken string @@ -407,7 +463,8 @@ func (mock *DatasetClientMock) GetDatasetsInBatches(ctx context.Context, userAut // GetDatasetsInBatchesCalls gets all the calls that were made to GetDatasetsInBatches. // Check the length with: -// len(mockedDatasetClient.GetDatasetsInBatchesCalls()) +// +// len(mockedDatasetClient.GetDatasetsInBatchesCalls()) func (mock *DatasetClientMock) GetDatasetsInBatchesCalls() []struct { Ctx context.Context UserAuthToken string @@ -458,7 +515,8 @@ func (mock *DatasetClientMock) GetEdition(ctx context.Context, userAuthToken str // GetEditionCalls gets all the calls that were made to GetEdition. // Check the length with: -// len(mockedDatasetClient.GetEditionCalls()) +// +// len(mockedDatasetClient.GetEditionCalls()) func (mock *DatasetClientMock) GetEditionCalls() []struct { Ctx context.Context UserAuthToken string @@ -507,7 +565,8 @@ func (mock *DatasetClientMock) GetEditions(ctx context.Context, userAuthToken st // GetEditionsCalls gets all the calls that were made to GetEditions. // Check the length with: -// len(mockedDatasetClient.GetEditionsCalls()) +// +// len(mockedDatasetClient.GetEditionsCalls()) func (mock *DatasetClientMock) GetEditionsCalls() []struct { Ctx context.Context UserAuthToken string @@ -556,7 +615,8 @@ func (mock *DatasetClientMock) GetInstance(ctx context.Context, userAuthToken st // GetInstanceCalls gets all the calls that were made to GetInstance. // Check the length with: -// len(mockedDatasetClient.GetInstanceCalls()) +// +// len(mockedDatasetClient.GetInstanceCalls()) func (mock *DatasetClientMock) GetInstanceCalls() []struct { Ctx context.Context UserAuthToken string @@ -611,7 +671,8 @@ func (mock *DatasetClientMock) GetVersion(ctx context.Context, userAuthToken str // GetVersionCalls gets all the calls that were made to GetVersion. // Check the length with: -// len(mockedDatasetClient.GetVersionCalls()) +// +// len(mockedDatasetClient.GetVersionCalls()) func (mock *DatasetClientMock) GetVersionCalls() []struct { Ctx context.Context UserAuthToken string @@ -638,6 +699,66 @@ func (mock *DatasetClientMock) GetVersionCalls() []struct { return calls } +// GetVersionWithHeaders calls GetVersionWithHeadersFunc. +func (mock *DatasetClientMock) GetVersionWithHeaders(ctx context.Context, userAuthToken string, serviceAuthToken string, downloadServiceAuthToken string, collectionID string, datasetID string, edition string, version string) (datasetclient.Version, datasetclient.ResponseHeaders, error) { + if mock.GetVersionWithHeadersFunc == nil { + panic("DatasetClientMock.GetVersionWithHeadersFunc: method is nil but DatasetClient.GetVersionWithHeaders was just called") + } + callInfo := struct { + Ctx context.Context + UserAuthToken string + ServiceAuthToken string + DownloadServiceAuthToken string + CollectionID string + DatasetID string + Edition string + Version string + }{ + Ctx: ctx, + UserAuthToken: userAuthToken, + ServiceAuthToken: serviceAuthToken, + DownloadServiceAuthToken: downloadServiceAuthToken, + CollectionID: collectionID, + DatasetID: datasetID, + Edition: edition, + Version: version, + } + mock.lockGetVersionWithHeaders.Lock() + mock.calls.GetVersionWithHeaders = append(mock.calls.GetVersionWithHeaders, callInfo) + mock.lockGetVersionWithHeaders.Unlock() + return mock.GetVersionWithHeadersFunc(ctx, userAuthToken, serviceAuthToken, downloadServiceAuthToken, collectionID, datasetID, edition, version) +} + +// GetVersionWithHeadersCalls gets all the calls that were made to GetVersionWithHeaders. +// Check the length with: +// +// len(mockedDatasetClient.GetVersionWithHeadersCalls()) +func (mock *DatasetClientMock) GetVersionWithHeadersCalls() []struct { + Ctx context.Context + UserAuthToken string + ServiceAuthToken string + DownloadServiceAuthToken string + CollectionID string + DatasetID string + Edition string + Version string +} { + var calls []struct { + Ctx context.Context + UserAuthToken string + ServiceAuthToken string + DownloadServiceAuthToken string + CollectionID string + DatasetID string + Edition string + Version string + } + mock.lockGetVersionWithHeaders.RLock() + calls = mock.calls.GetVersionWithHeaders + mock.lockGetVersionWithHeaders.RUnlock() + return calls +} + // GetVersionsInBatches calls GetVersionsInBatchesFunc. func (mock *DatasetClientMock) GetVersionsInBatches(ctx context.Context, userAuthToken string, serviceAuthToken string, downloadServiceAuthToken string, collectionID string, datasetID string, edition string, batchSize int, maxWorkers int) (datasetclient.VersionsList, error) { if mock.GetVersionsInBatchesFunc == nil { @@ -672,7 +793,8 @@ func (mock *DatasetClientMock) GetVersionsInBatches(ctx context.Context, userAut // GetVersionsInBatchesCalls gets all the calls that were made to GetVersionsInBatches. // Check the length with: -// len(mockedDatasetClient.GetVersionsInBatchesCalls()) +// +// len(mockedDatasetClient.GetVersionsInBatchesCalls()) func (mock *DatasetClientMock) GetVersionsInBatchesCalls() []struct { Ctx context.Context UserAuthToken string @@ -729,7 +851,8 @@ func (mock *DatasetClientMock) PutDataset(ctx context.Context, userAuthToken str // PutDatasetCalls gets all the calls that were made to PutDataset. // Check the length with: -// len(mockedDatasetClient.PutDatasetCalls()) +// +// len(mockedDatasetClient.PutDatasetCalls()) func (mock *DatasetClientMock) PutDatasetCalls() []struct { Ctx context.Context UserAuthToken string @@ -782,7 +905,8 @@ func (mock *DatasetClientMock) PutInstance(ctx context.Context, userAuthToken st // PutInstanceCalls gets all the calls that were made to PutInstance. // Check the length with: -// len(mockedDatasetClient.PutInstanceCalls()) +// +// len(mockedDatasetClient.PutInstanceCalls()) func (mock *DatasetClientMock) PutInstanceCalls() []struct { Ctx context.Context UserAuthToken string @@ -807,6 +931,70 @@ func (mock *DatasetClientMock) PutInstanceCalls() []struct { return calls } +// PutMetadata calls PutMetadataFunc. +func (mock *DatasetClientMock) PutMetadata(ctx context.Context, userAuthToken string, serviceAuthToken string, collectionID string, datasetID string, edition string, version string, metadata datasetclient.EditableMetadata, versionEtag string) error { + if mock.PutMetadataFunc == nil { + panic("DatasetClientMock.PutMetadataFunc: method is nil but DatasetClient.PutMetadata was just called") + } + callInfo := struct { + Ctx context.Context + UserAuthToken string + ServiceAuthToken string + CollectionID string + DatasetID string + Edition string + Version string + Metadata datasetclient.EditableMetadata + VersionEtag string + }{ + Ctx: ctx, + UserAuthToken: userAuthToken, + ServiceAuthToken: serviceAuthToken, + CollectionID: collectionID, + DatasetID: datasetID, + Edition: edition, + Version: version, + Metadata: metadata, + VersionEtag: versionEtag, + } + mock.lockPutMetadata.Lock() + mock.calls.PutMetadata = append(mock.calls.PutMetadata, callInfo) + mock.lockPutMetadata.Unlock() + return mock.PutMetadataFunc(ctx, userAuthToken, serviceAuthToken, collectionID, datasetID, edition, version, metadata, versionEtag) +} + +// PutMetadataCalls gets all the calls that were made to PutMetadata. +// Check the length with: +// +// len(mockedDatasetClient.PutMetadataCalls()) +func (mock *DatasetClientMock) PutMetadataCalls() []struct { + Ctx context.Context + UserAuthToken string + ServiceAuthToken string + CollectionID string + DatasetID string + Edition string + Version string + Metadata datasetclient.EditableMetadata + VersionEtag string +} { + var calls []struct { + Ctx context.Context + UserAuthToken string + ServiceAuthToken string + CollectionID string + DatasetID string + Edition string + Version string + Metadata datasetclient.EditableMetadata + VersionEtag string + } + mock.lockPutMetadata.RLock() + calls = mock.calls.PutMetadata + mock.lockPutMetadata.RUnlock() + return calls +} + // PutVersion calls PutVersionFunc. func (mock *DatasetClientMock) PutVersion(ctx context.Context, userAuthToken string, serviceAuthToken string, collectionID string, datasetID string, edition string, version string, v datasetclient.Version) error { if mock.PutVersionFunc == nil { @@ -839,7 +1027,8 @@ func (mock *DatasetClientMock) PutVersion(ctx context.Context, userAuthToken str // PutVersionCalls gets all the calls that were made to PutVersion. // Check the length with: -// len(mockedDatasetClient.PutVersionCalls()) +// +// len(mockedDatasetClient.PutVersionCalls()) func (mock *DatasetClientMock) PutVersionCalls() []struct { Ctx context.Context UserAuthToken string @@ -872,25 +1061,25 @@ var _ ZebedeeClient = &ZebedeeClientMock{} // ZebedeeClientMock is a mock implementation of ZebedeeClient. // -// func TestSomethingThatUsesZebedeeClient(t *testing.T) { +// func TestSomethingThatUsesZebedeeClient(t *testing.T) { // -// // make and configure a mocked ZebedeeClient -// mockedZebedeeClient := &ZebedeeClientMock{ -// GetCollectionFunc: func(ctx context.Context, userAccessToken string, collectionID string) (zebedeeclient.Collection, error) { -// panic("mock out the GetCollection method") -// }, -// PutDatasetInCollectionFunc: func(ctx context.Context, userAccessToken string, collectionID string, lang string, datasetID string, state string) error { -// panic("mock out the PutDatasetInCollection method") -// }, -// PutDatasetVersionInCollectionFunc: func(ctx context.Context, userAccessToken string, collectionID string, lang string, datasetID string, edition string, version string, state string) error { -// panic("mock out the PutDatasetVersionInCollection method") -// }, -// } +// // make and configure a mocked ZebedeeClient +// mockedZebedeeClient := &ZebedeeClientMock{ +// GetCollectionFunc: func(ctx context.Context, userAccessToken string, collectionID string) (zebedeeclient.Collection, error) { +// panic("mock out the GetCollection method") +// }, +// PutDatasetInCollectionFunc: func(ctx context.Context, userAccessToken string, collectionID string, lang string, datasetID string, state string) error { +// panic("mock out the PutDatasetInCollection method") +// }, +// PutDatasetVersionInCollectionFunc: func(ctx context.Context, userAccessToken string, collectionID string, lang string, datasetID string, edition string, version string, state string) error { +// panic("mock out the PutDatasetVersionInCollection method") +// }, +// } // -// // use mockedZebedeeClient in code that requires ZebedeeClient -// // and then make assertions. +// // use mockedZebedeeClient in code that requires ZebedeeClient +// // and then make assertions. // -// } +// } type ZebedeeClientMock struct { // GetCollectionFunc mocks the GetCollection method. GetCollectionFunc func(ctx context.Context, userAccessToken string, collectionID string) (zebedeeclient.Collection, error) @@ -974,7 +1163,8 @@ func (mock *ZebedeeClientMock) GetCollection(ctx context.Context, userAccessToke // GetCollectionCalls gets all the calls that were made to GetCollection. // Check the length with: -// len(mockedZebedeeClient.GetCollectionCalls()) +// +// len(mockedZebedeeClient.GetCollectionCalls()) func (mock *ZebedeeClientMock) GetCollectionCalls() []struct { Ctx context.Context UserAccessToken string @@ -1019,7 +1209,8 @@ func (mock *ZebedeeClientMock) PutDatasetInCollection(ctx context.Context, userA // PutDatasetInCollectionCalls gets all the calls that were made to PutDatasetInCollection. // Check the length with: -// len(mockedZebedeeClient.PutDatasetInCollectionCalls()) +// +// len(mockedZebedeeClient.PutDatasetInCollectionCalls()) func (mock *ZebedeeClientMock) PutDatasetInCollectionCalls() []struct { Ctx context.Context UserAccessToken string @@ -1074,7 +1265,8 @@ func (mock *ZebedeeClientMock) PutDatasetVersionInCollection(ctx context.Context // PutDatasetVersionInCollectionCalls gets all the calls that were made to PutDatasetVersionInCollection. // Check the length with: -// len(mockedZebedeeClient.PutDatasetVersionInCollectionCalls()) +// +// len(mockedZebedeeClient.PutDatasetVersionInCollectionCalls()) func (mock *ZebedeeClientMock) PutDatasetVersionInCollectionCalls() []struct { Ctx context.Context UserAccessToken string @@ -1107,19 +1299,19 @@ var _ BabbageClient = &BabbageClientMock{} // BabbageClientMock is a mock implementation of BabbageClient. // -// func TestSomethingThatUsesBabbageClient(t *testing.T) { +// func TestSomethingThatUsesBabbageClient(t *testing.T) { // -// // make and configure a mocked BabbageClient -// mockedBabbageClient := &BabbageClientMock{ -// GetTopicsFunc: func(ctx context.Context, userAccessToken string) (babbageclient.TopicsResult, error) { -// panic("mock out the GetTopics method") -// }, -// } +// // make and configure a mocked BabbageClient +// mockedBabbageClient := &BabbageClientMock{ +// GetTopicsFunc: func(ctx context.Context, userAccessToken string) (babbageclient.TopicsResult, error) { +// panic("mock out the GetTopics method") +// }, +// } // -// // use mockedBabbageClient in code that requires BabbageClient -// // and then make assertions. +// // use mockedBabbageClient in code that requires BabbageClient +// // and then make assertions. // -// } +// } type BabbageClientMock struct { // GetTopicsFunc mocks the GetTopics method. GetTopicsFunc func(ctx context.Context, userAccessToken string) (babbageclient.TopicsResult, error) @@ -1157,7 +1349,8 @@ func (mock *BabbageClientMock) GetTopics(ctx context.Context, userAccessToken st // GetTopicsCalls gets all the calls that were made to GetTopics. // Check the length with: -// len(mockedBabbageClient.GetTopicsCalls()) +// +// len(mockedBabbageClient.GetTopicsCalls()) func (mock *BabbageClientMock) GetTopicsCalls() []struct { Ctx context.Context UserAccessToken string diff --git a/dataset/put-metadata.go b/dataset/put-metadata.go index 0d78a24..8404a8b 100644 --- a/dataset/put-metadata.go +++ b/dataset/put-metadata.go @@ -2,17 +2,19 @@ package dataset import ( "encoding/json" + "io" "io/ioutil" "net/http" datasetclient "github.com/ONSdigital/dp-api-clients-go/v2/dataset" dphandlers "github.com/ONSdigital/dp-net/handlers" + "github.com/ONSdigital/dp-publishing-dataset-controller/mapper" "github.com/ONSdigital/dp-publishing-dataset-controller/model" "github.com/ONSdigital/log.go/v2/log" "github.com/gorilla/mux" ) -// PutMetadata updates dataset, version and dimension data +// PutMetadata updates all the dataset, version and dimension object fields func PutMetadata(dc DatasetClient, zc ZebedeeClient) http.HandlerFunc { return dphandlers.ControllerHandler(func(w http.ResponseWriter, r *http.Request, lang, collectionID, accessToken string) { putMetadata(w, r, dc, zc, accessToken, collectionID, lang) @@ -97,3 +99,82 @@ func putMetadata(w http.ResponseWriter, req *http.Request, dc DatasetClient, zc log.Info(ctx, "put metadata: request successful", log.Data(logInfo)) } + +// PutEditableMetadata updates a given list of metadata fields, agreed as being editable for both a dataset and a version object +// This new endpoint makes a unique call to the dataset api updating only the relevant metadata fields in a transactional way +// It also calls zebedee to update the collection +func PutEditableMetadata(dc DatasetClient, zc ZebedeeClient) http.HandlerFunc { + return dphandlers.ControllerHandler(func(w http.ResponseWriter, r *http.Request, lang, collectionID, accessToken string) { + putEditableMetadata(w, r, dc, zc, accessToken, collectionID) + }) +} + +func putEditableMetadata(w http.ResponseWriter, req *http.Request, dc DatasetClient, zc ZebedeeClient, userAccessToken, collectionID string) { + ctx := req.Context() + + err := checkAccessTokenAndCollectionHeaders(userAccessToken, collectionID) + if err != nil { + log.Error(ctx, err.Error(), err) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + vars := mux.Vars(req) + datasetID := vars["datasetID"] + edition := vars["editionID"] + version := vars["versionID"] + + logInfo := map[string]interface{}{ + "datasetID": datasetID, + "edition": edition, + "version": version, + } + + b, err := io.ReadAll(req.Body) + if err != nil { + log.Error(ctx, "putMetadata endpoint: error reading body", err, log.Data(logInfo)) + http.Error(w, "error reading body", http.StatusBadRequest) + return + } + + var body model.EditMetadata + if err = json.Unmarshal(b, &body); err != nil { + log.Error(ctx, "putMetadata endpoint: error unmarshalling body", err, log.Data(logInfo)) + http.Error(w, "error unmarshalling body", http.StatusBadRequest) + return + } + + versionEtag := body.VersionEtag + + editableMetadata := mapper.PutMetadata(body) + + err = dc.PutMetadata(ctx, userAccessToken, "", collectionID, datasetID, edition, version, editableMetadata, versionEtag) + if err != nil { + log.Error(ctx, "error updating metadata", err, log.Data(logInfo)) + http.Error(w, "error updating metadata", http.StatusInternalServerError) + return + } + + err = zc.PutDatasetInCollection(ctx, userAccessToken, collectionID, "", datasetID, body.CollectionState) + if err != nil { + log.Error(ctx, "error adding dataset to collection", err, log.Data(logInfo)) + http.Error(w, "error adding dataset to collection", http.StatusInternalServerError) + return + } + + err = zc.PutDatasetVersionInCollection(ctx, userAccessToken, collectionID, "", datasetID, edition, version, body.CollectionState) + if err != nil { + log.Error(ctx, "error adding version to collection", err, log.Data(logInfo)) + http.Error(w, "error adding version to collection", http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusOK) + if _, err = w.Write(b); err != nil { + log.Error(ctx, "failed to write response body", err, log.Data(logInfo)) + http.Error(w, "failed to write response body", http.StatusInternalServerError) + return + } + + log.Info(ctx, "put metadata: request successful", log.Data(logInfo)) +} diff --git a/dataset/put-metadata_test.go b/dataset/put-metadata_test.go index beb223a..a0c1bf7 100644 --- a/dataset/put-metadata_test.go +++ b/dataset/put-metadata_test.go @@ -3,7 +3,9 @@ package dataset import ( "bytes" "context" + "encoding/json" "errors" + "fmt" "net/http" "net/http/httptest" "testing" @@ -11,6 +13,7 @@ import ( "github.com/gorilla/mux" datasetclient "github.com/ONSdigital/dp-api-clients-go/v2/dataset" + "github.com/ONSdigital/dp-publishing-dataset-controller/model" . "github.com/smartystreets/goconvey/convey" ) @@ -162,3 +165,168 @@ func TestUnitPutMetadata(t *testing.T) { }) }) } + +func TestUnitPutEditableMetadata(t *testing.T) { + Convey("Given a metadata object", t, func() { + mockDatasetId := "test-dataset" + mockEdition := "test-edition" + mockVersionNumber := "1" + mockCollectionId := "testcollection" + etag := "versionEtag" + + metadata := model.EditMetadata{ + Dataset: datasetclient.DatasetDetails{ + ID: mockDatasetId, + CollectionID: mockCollectionId, + Contacts: &[]datasetclient.Contact{{ + Name: "contact", + Email: "contact@ons.gov.uk", + Telephone: "029", + }}, + Description: "dataset description", + Keywords: &[]string{"one", "two"}, + License: "license", + Methodologies: &[]datasetclient.Methodology{ + { + Title: "methodology", + Description: "methodology description", + URL: "methodology url", + }, + }, + NationalStatistic: true, + NextRelease: "tomorrow", + Publications: &[]datasetclient.Publication{}, + QMI: datasetclient.Publication{}, + RelatedDatasets: &[]datasetclient.RelatedDataset{}, + ReleaseFrequency: "daily", + Title: "dataset title", + UnitOfMeasure: "unit", + UsageNotes: &[]datasetclient.UsageNote{}, + CanonicalTopic: "topic", + Subtopics: []string{"three"}, + Survey: "census", + RelatedContent: &[]datasetclient.GeneralDetails{}, + }, + Version: datasetclient.Version{ + Alerts: &[]datasetclient.Alert{}, + CollectionID: mockCollectionId, + Dimensions: []datasetclient.VersionDimension{}, + ID: "version-id", + LatestChanges: []datasetclient.Change{}, + Version: 1, + UsageNotes: &[]datasetclient.UsageNote{}, + }, + CollectionState: "in-progress", + VersionEtag: etag, + } + + Convey("And a router using the PutEditableMetadata handler", func() { + + florenceToken := "testuser" + + datasetClient := &DatasetClientMock{ + PutMetadataFunc: func(ctx context.Context, userAuthToken, serviceAuthToken, collectionID, datasetID, edition, version string, editableMetadata datasetclient.EditableMetadata, versionEtag string) error { + if userAuthToken != florenceToken || serviceAuthToken != "" { + return errors.New("Function called with unexpected tokens") + } + if collectionID != mockCollectionId || datasetID != mockDatasetId || edition != mockEdition || version != mockVersionNumber { + return errors.New("Function called with unexpected parameters") + } + if versionEtag != etag { + return errors.New("Function called with invalid version etag") + } + return nil + }, + } + + zebedeeClient := &ZebedeeClientMock{ + PutDatasetInCollectionFunc: func(ctx context.Context, userAccessToken, collectionID, lang, datasetID, state string) error { + if userAccessToken != florenceToken || collectionID != mockCollectionId || lang != "" || datasetID != mockDatasetId || state != metadata.CollectionState { + return errors.New("Function called with unexpected parameters") + } + return nil + }, + PutDatasetVersionInCollectionFunc: func(ctx context.Context, userAccessToken, collectionID, lang, datasetID, edition, version, state string) error { + if userAccessToken != florenceToken || collectionID != mockCollectionId || lang != "" || datasetID != mockDatasetId || edition != mockEdition || version != mockVersionNumber || state != metadata.CollectionState { + return errors.New("Function called with unexpected parameters") + } + return nil + }, + } + + router := mux.NewRouter() + router.Path("/datasets/{datasetID}/editions/{editionID}/versions/{versionID}/metadata").HandlerFunc(PutEditableMetadata(datasetClient, zebedeeClient)) + + rec := httptest.NewRecorder() + + body, _ := json.Marshal(metadata) + url := fmt.Sprintf("/datasets/%s/editions/%s/versions/%s/metadata", mockDatasetId, mockEdition, mockVersionNumber) + + req := httptest.NewRequest("PUT", url, bytes.NewBuffer(body)) + + Convey("When a request without a florence token header is made", func() { + req.Header.Set("Collection-Id", mockCollectionId) + + router.ServeHTTP(rec, req) + + Convey("Then we receive a 400 response", func() { + So(rec.Code, ShouldEqual, http.StatusBadRequest) + So(rec.Body.String(), ShouldEqual, "no user access token header set\n") + + So(len(datasetClient.PutMetadataCalls()), ShouldEqual, 0) + So(len(zebedeeClient.PutDatasetInCollectionCalls()), ShouldEqual, 0) + So(len(zebedeeClient.PutDatasetVersionInCollectionCalls()), ShouldEqual, 0) + }) + }) + + Convey("When a request without a collection id header is made", func() { + req.Header.Set("X-Florence-Token", florenceToken) + + router.ServeHTTP(rec, req) + + Convey("Then we receive a 400 response", func() { + So(rec.Code, ShouldEqual, http.StatusBadRequest) + So(rec.Body.String(), ShouldEqual, "no collection ID header set\n") + + So(len(datasetClient.PutMetadataCalls()), ShouldEqual, 0) + So(len(zebedeeClient.PutDatasetInCollectionCalls()), ShouldEqual, 0) + So(len(zebedeeClient.PutDatasetVersionInCollectionCalls()), ShouldEqual, 0) + }) + }) + + Convey("And all headers are set", func() { + req.Header.Set("Collection-Id", mockCollectionId) + req.Header.Set("X-Florence-Token", florenceToken) + + Convey("And the version etag is wrong", func() { + etag = "wrong" + + Convey("When a PUT metadata request is made", func() { + router.ServeHTTP(rec, req) + + Convey("Then we receive a 500 response", func() { + So(rec.Code, ShouldEqual, http.StatusInternalServerError) + So(rec.Body.String(), ShouldEqual, "error updating metadata\n") + + So(len(datasetClient.PutMetadataCalls()), ShouldEqual, 1) + So(len(zebedeeClient.PutDatasetInCollectionCalls()), ShouldEqual, 0) + So(len(zebedeeClient.PutDatasetVersionInCollectionCalls()), ShouldEqual, 0) + }) + }) + }) + + Convey("When a PUT metadata request is made", func() { + router.ServeHTTP(rec, req) + + Convey("Then we receive a 200 response", func() { + So(rec.Code, ShouldEqual, http.StatusOK) + + So(len(datasetClient.PutMetadataCalls()), ShouldEqual, 1) + So(len(zebedeeClient.PutDatasetInCollectionCalls()), ShouldEqual, 1) + So(len(zebedeeClient.PutDatasetVersionInCollectionCalls()), ShouldEqual, 1) + }) + }) + }) + }) + }) +} diff --git a/go.mod b/go.mod index 9f08fe6..82ed2a9 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ replace github.com/spf13/cobra => github.com/spf13/cobra v1.4.0 replace golang.org/x/text => golang.org/x/text v0.3.8 require ( - github.com/ONSdigital/dp-api-clients-go/v2 v2.192.0 + github.com/ONSdigital/dp-api-clients-go/v2 v2.250.0 github.com/ONSdigital/dp-healthcheck v1.5.0 github.com/ONSdigital/dp-net v1.5.0 github.com/ONSdigital/log.go/v2 v2.3.0 @@ -22,17 +22,17 @@ require ( require ( github.com/ONSdigital/dp-api-clients-go v1.43.0 // indirect - github.com/ONSdigital/dp-net/v2 v2.6.0 // indirect - github.com/aws/aws-sdk-go v1.44.76 // indirect - github.com/fatih/color v1.13.0 // indirect + github.com/ONSdigital/dp-net/v2 v2.8.0 // indirect + github.com/aws/aws-sdk-go v1.44.204 // indirect + github.com/fatih/color v1.14.1 // indirect github.com/gopherjs/gopherjs v1.17.2 // indirect github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jtolds/gls v4.20.0+incompatible // indirect github.com/justinas/alice v1.2.0 // indirect - github.com/mattn/go-colorable v0.1.12 // indirect - github.com/mattn/go-isatty v0.0.16 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect github.com/smartystreets/assertions v1.13.0 // indirect - golang.org/x/net v0.0.0-20220812174116-3211cb980234 // indirect - golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect + golang.org/x/net v0.7.0 // indirect + golang.org/x/sys v0.5.0 // indirect ) diff --git a/go.sum b/go.sum index d3dd3dd..e5ba7fd 100644 --- a/go.sum +++ b/go.sum @@ -3,8 +3,8 @@ github.com/ONSdigital/dp-api-clients-go v1.34.3/go.mod h1:kX+YKuoLYLfkeLHMvQKRRy github.com/ONSdigital/dp-api-clients-go v1.41.1/go.mod h1:Ga1+ANjviu21NFJI9wp5NctJIdB4TJLDGbpQFl2V8Wc= github.com/ONSdigital/dp-api-clients-go v1.43.0 h1:0982P/YxnYXvba1RhEcFmwF3xywC4eXokWQ8YH3Mm24= github.com/ONSdigital/dp-api-clients-go v1.43.0/go.mod h1:V5MfINik+o3OAF985UXUoMjXIfrZe3JKYa5AhZn5jts= -github.com/ONSdigital/dp-api-clients-go/v2 v2.192.0 h1:ITODCAw0lY6I+615xn2Sncychi/xScfpJ4rz2B0MYcM= -github.com/ONSdigital/dp-api-clients-go/v2 v2.192.0/go.mod h1:JhWrjETosIKYjbLoa3d19QJlKv7dx+/+x09qg355Rxg= +github.com/ONSdigital/dp-api-clients-go/v2 v2.250.0 h1:xvZ6RNYFvAj5aiOzg/QCXZRCKU7qBj73iYSx+Eo0RoI= +github.com/ONSdigital/dp-api-clients-go/v2 v2.250.0/go.mod h1:PFfLdey8l0/ufzF6/x2mn+OL+9M5/xlg4JOQpFHmCbk= github.com/ONSdigital/dp-healthcheck v1.0.5/go.mod h1:2wbVAUHMl9+4tWhUlxYUuA1dnf2+NrwzC+So5f5BMLk= github.com/ONSdigital/dp-healthcheck v1.1.0/go.mod h1:vZwyjMJiCHjp/sJ2R1ZEqzZT0rJ0+uHVGwxqdP4J5vg= github.com/ONSdigital/dp-healthcheck v1.5.0 h1:w3iMuq+CIr8lyu8xPgXPlU3MQGXWlm4eiQgsQHyqRWc= @@ -19,8 +19,8 @@ github.com/ONSdigital/dp-net v1.0.12/go.mod h1:2lvIKOlD4T3BjWQwjHhBUO2UNWDk82u/+ github.com/ONSdigital/dp-net v1.2.0/go.mod h1:NinlaqcsPbIR+X7j5PXCl3UI5G2zCL041SDF6WIiiO4= github.com/ONSdigital/dp-net v1.5.0 h1:H47O5N+eXyXCYqPoQGWwuK12uLds3pCgzxpYwepg+bQ= github.com/ONSdigital/dp-net v1.5.0/go.mod h1:d/S4n6FJlQwmVIa2rnVt1HnAUgM8XsG0QEJBQp48uGg= -github.com/ONSdigital/dp-net/v2 v2.6.0 h1:orxdb0SVDrJgz/zma0QXgQCAGJdLDhp6g2XqH6VFUZw= -github.com/ONSdigital/dp-net/v2 v2.6.0/go.mod h1:4/2ZyId//hFa7AtbbRNQctY729C1Vbw4UEdOliRvpZI= +github.com/ONSdigital/dp-net/v2 v2.8.0 h1:jCh+YN/KgQyrSQem48ShMKFi2eqF75LLI675qa8kRFA= +github.com/ONSdigital/dp-net/v2 v2.8.0/go.mod h1:QKmA2VgtVo9f7SpG9vq+VaZ9YUhQg+DpqcZkYTYi8WM= github.com/ONSdigital/go-ns v0.0.0-20191104121206-f144c4ec2e58/go.mod h1:iWos35il+NjbvDEqwtB736pyHru0MPFE/LqcwkV1wDc= github.com/ONSdigital/log.go v1.0.0/go.mod h1:UnGu9Q14gNC+kz0DOkdnLYGoqugCvnokHBRBxFRpVoQ= github.com/ONSdigital/log.go v1.0.1-0.20200805084515-ee61165ea36a/go.mod h1:dDnQATFXCBOknvj6ZQuKfmDhbOWf3e8mtV+dPEfWJqs= @@ -33,16 +33,16 @@ github.com/ONSdigital/log.go/v2 v2.0.5/go.mod h1:PR7vXrv9dZKUc7SI/0toxBbStk84snm github.com/ONSdigital/log.go/v2 v2.0.9/go.mod h1:VyTDkL82FtiAkaNFaT+bURBhLbP7NsIx4rkVbdpiuEg= github.com/ONSdigital/log.go/v2 v2.3.0 h1:go+KkUR36/CClez+UCCwVIVqFie1w3PYgvAyoclKVYM= github.com/ONSdigital/log.go/v2 v2.3.0/go.mod h1:s5iqJuW0jDE8V7VQJqLHT73nn/H8u1c+A2Nqw2QPEeo= -github.com/aws/aws-sdk-go v1.44.76 h1:5e8yGO/XeNYKckOjpBKUd5wStf0So3CrQIiOMCVLpOI= -github.com/aws/aws-sdk-go v1.44.76/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/aws/aws-sdk-go v1.44.204 h1:7/tPUXfNOHB390A63t6fJIwmlwVQAkAwcbzKsU2/6OQ= +github.com/aws/aws-sdk-go v1.44.204/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/facebookgo/freeport v0.0.0-20150612182905-d4adf43b75b9/go.mod h1:uPmAp6Sws4L7+Q/OokbWDAK1ibXYhB3PXFP1kol5hPg= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= +github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= @@ -70,16 +70,15 @@ github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dv github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -113,10 +112,10 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E= -golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -134,16 +133,16 @@ golang.org/x/sys v0.0.0-20210414055047-fe65e336abe0/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= diff --git a/mapper/mapper.go b/mapper/mapper.go index fc0fdb1..5645daf 100644 --- a/mapper/mapper.go +++ b/mapper/mapper.go @@ -98,11 +98,59 @@ func EditMetadata(d *dataset.DatasetDetails, v dataset.Version, dim []dataset.Ve } +// PutMetadata transform an EditMetadata object to the EditableMetadata as expected by dataset api +func PutMetadata(m model.EditMetadata) dataset.EditableMetadata { + metadata := dataset.EditableMetadata{ + CanonicalTopic: m.Dataset.CanonicalTopic, + Description: m.Dataset.Description, + Dimensions: m.Version.Dimensions, + LatestChanges: &m.Version.LatestChanges, + License: m.Dataset.License, + NationalStatistic: &m.Dataset.NationalStatistic, + NextRelease: m.Dataset.NextRelease, + QMI: &m.Dataset.QMI, + ReleaseDate: m.Version.ReleaseDate, + ReleaseFrequency: m.Dataset.ReleaseFrequency, + Subtopics: m.Dataset.Subtopics, + Survey: m.Dataset.Survey, + Title: m.Dataset.Title, + UnitOfMeasure: m.Dataset.UnitOfMeasure, + } + + if m.Dataset.Contacts != nil { + metadata.Contacts = *m.Dataset.Contacts + } + if m.Dataset.Keywords != nil { + metadata.Keywords = *m.Dataset.Keywords + } + if m.Dataset.Methodologies != nil { + metadata.Methodologies = *m.Dataset.Methodologies + } + if m.Dataset.Publications != nil { + metadata.Publications = *m.Dataset.Publications + } + if m.Dataset.RelatedDatasets != nil { + metadata.RelatedDatasets = *m.Dataset.RelatedDatasets + } + if m.Dataset.RelatedContent != nil { + metadata.RelatedContent = *m.Dataset.RelatedContent + } + + if m.Version.Alerts != nil { + metadata.Alerts = m.Version.Alerts + } + if m.Version.UsageNotes != nil { + metadata.UsageNotes = m.Version.UsageNotes + } + + return metadata +} + func EditDatasetVersionMetaData(d dataset.DatasetDetails, v dataset.Version) (model.EditVersionMetaData, error) { keywordsString := "" if d.Keywords != nil { keywords := *d.Keywords - keywordsString = fmt.Sprintf(strings.Join(keywords, ", ")) + keywordsString = fmt.Sprint(strings.Join(keywords, ", ")) } relatedContent := mapRelatedContent(d.RelatedDatasets, d.Methodologies, d.Publications) diff --git a/mapper/mapper_test.go b/mapper/mapper_test.go index b59d7a9..7febd42 100644 --- a/mapper/mapper_test.go +++ b/mapper/mapper_test.go @@ -141,165 +141,6 @@ func TestUnitMapper(t *testing.T) { So(len(mapped), ShouldEqual, 4) }) - mockContacts := []dataset.Contact{ - { - Name: "foo", - Telephone: "Bar", - Email: "bAz", - }, - { - Name: "bad-foo", - Telephone: "bad-Bar", - Email: "bad-bAz", - }, - } - mockMethodology := []dataset.Methodology{ - { - Description: "foo", - URL: "Bar", - Title: "bAz", - }, - { - Description: "qux", - URL: "quux", - Title: "grault", - }, - } - mockPublications := []dataset.Publication{ - { - Description: "Bar", - URL: "bAz", - Title: "foo", - }, - { - Description: "quux", - URL: "grault", - Title: "qux", - }, - } - mockRelatedDataset := []dataset.RelatedDataset{ - { - URL: "foo", - Title: "Bar", - }, - { - URL: "bAz", - Title: "qux", - }, - } - mockKeywords := []string{"foo", "Bar", "bAz"} - mockUsageNotes := []dataset.UsageNote{ - { - Title: "foo", - Note: "Bar", - }, - { - Title: "bAz", - Note: "qux", - }, - } - mockDatasetDetails := &dataset.DatasetDetails{ - ID: "foo", - CollectionID: "Bar", - Contacts: &mockContacts, - Description: "bAz", - Keywords: &mockKeywords, - License: "qux", - Links: dataset.Links{}, - Methodologies: &mockMethodology, - NationalStatistic: false, - NextRelease: "quux", - Publications: &mockPublications, - Publisher: &dataset.Publisher{}, - QMI: dataset.Publication{ - Description: "foo", - URL: "Bar", - Title: "bAz", - }, - RelatedDatasets: &mockRelatedDataset, - ReleaseFrequency: "grault", - State: "garply", - Theme: "waldo", - Title: "fred", - UnitOfMeasure: "plugh", - URI: "xyzzy", - } - mockAlerts := []dataset.Alert{ - { - Date: "2020-02-04T11:05:06.000Z", - Description: "Bar", - Type: "bAz", - }, - { - Date: "2001-04-02T23:04:02.000Z", - Description: "quux", - Type: "grault", - }, - } - mockDimensions := []dataset.VersionDimension{ - { - Links: dataset.Links{}, - Label: "bAz", - }, - { - Links: dataset.Links{}, - Label: "plaugh", - }, - } - - mockLatestChanges := []dataset.Change{ - { - Description: "foo", - Name: "Bar", - Type: "bAz", - }, - { - Description: "qux", - Name: "quux", - Type: "grault", - }, - } - mockVersion := dataset.Version{ - Alerts: &mockAlerts, - CollectionID: "foo", - Downloads: nil, - Edition: "Bar", - Dimensions: mockDimensions, - ID: "bAz", - InstanceID: "qux", - LatestChanges: mockLatestChanges, - Links: dataset.Links{}, - ReleaseDate: "quux", - State: "grault", - Temporal: nil, - Version: 1, - UsageNotes: &mockUsageNotes, - } - mockDimensions = []dataset.VersionDimension{} - - mockCollection := zebedee.Collection{ - ID: "test-collection", - Datasets: []zebedee.CollectionItem{ - { - ID: "foo", - State: "inProgress", - }, - }, - } - - expectedEditMetadata := model.EditMetadata{ - Dataset: *mockDatasetDetails, - Version: mockVersion, - Dimensions: mockDimensions, - CollectionID: "test-collection", - CollectionState: "inProgress", - } - - Convey("test EditMetadata", t, func() { - outcome := EditMetadata(mockDatasetDetails, mockVersion, mockDimensions, mockCollection) - So(outcome, ShouldResemble, expectedEditMetadata) - }) - mockTopics := babbage.TopicsResult{ Topics: babbage.Topic{ Results: []babbage.Result{{ @@ -379,3 +220,256 @@ func TestUnitMapper(t *testing.T) { }) }) } + +func TestMetadata(t *testing.T) { + Convey("Given a dataset and version objects", t, func() { + mockDatasetDetails := &dataset.DatasetDetails{ + ID: "foo", + CollectionID: "Bar", + Contacts: &[]dataset.Contact{ + { + Name: "foo", + Telephone: "Bar", + Email: "bAz", + }, + { + Name: "bad-foo", + Telephone: "bad-Bar", + Email: "bad-bAz", + }, + }, + Description: "bAz", + Keywords: &[]string{"foo", "Bar", "bAz"}, + License: "qux", + Links: dataset.Links{}, + Methodologies: &[]dataset.Methodology{ + { + Description: "foo", + URL: "Bar", + Title: "bAz", + }, + { + Description: "qux", + URL: "quux", + Title: "grault", + }, + }, + NationalStatistic: false, + NextRelease: "quux", + Publications: &[]dataset.Publication{ + { + Description: "Bar", + URL: "bAz", + Title: "foo", + }, + { + Description: "quux", + URL: "grault", + Title: "qux", + }, + }, + Publisher: &dataset.Publisher{}, + QMI: dataset.Publication{ + Description: "foo", + URL: "Bar", + Title: "bAz", + }, + RelatedDatasets: &[]dataset.RelatedDataset{ + { + URL: "foo", + Title: "Bar", + }, + { + URL: "bAz", + Title: "qux", + }, + }, + ReleaseFrequency: "grault", + State: "garply", + Theme: "waldo", + Title: "fred", + UnitOfMeasure: "plugh", + URI: "xyzzy", + CanonicalTopic: "1234", + Subtopics: []string{"5678", "9012"}, + RelatedContent: &[]dataset.GeneralDetails{ + { + Description: "foo", + HRef: "Bar", + Title: "baz", + }, + { + Description: "foo", + HRef: "Bar", + Title: "baz", + }, + }, + Survey: "census", + } + mockDimensions := []dataset.VersionDimension{ + { + Links: dataset.Links{}, + Label: "bAz", + }, + { + Links: dataset.Links{}, + Label: "plaugh", + }, + } + + mockVersion := dataset.Version{ + Alerts: &[]dataset.Alert{ + { + Date: "2020-02-04T11:05:06.000Z", + Description: "Bar", + Type: "bAz", + }, + { + Date: "2001-04-02T23:04:02.000Z", + Description: "quux", + Type: "grault", + }, + }, + CollectionID: "foo", + Downloads: nil, + Edition: "Bar", + Dimensions: mockDimensions, + ID: "bAz", + InstanceID: "qux", + LatestChanges: []dataset.Change{ + { + Description: "foo", + Name: "Bar", + Type: "bAz", + }, + { + Description: "qux", + Name: "quux", + Type: "grault", + }, + }, + Links: dataset.Links{}, + ReleaseDate: "grault", + State: "grault", + Temporal: nil, + Version: 1, + UsageNotes: &[]dataset.UsageNote{ + { + Title: "foo", + Note: "Bar", + }, + { + Title: "bAz", + Note: "qux", + }, + }, + } + + Convey("And a zebedee collection", func() { + + datasetCollectionItem := zebedee.CollectionItem{ + ID: mockDatasetDetails.ID, + State: "inProgress", + LastEditedBy: "User", + } + mockCollection := zebedee.Collection{ + ID: "test-collection", + Datasets: []zebedee.CollectionItem{ + { + ID: "other dataset id", + State: "reviewd", + LastEditedBy: "Other user", + }, + datasetCollectionItem, + }, + } + Convey("When we call EditMetadata", func() { + outcome := EditMetadata(mockDatasetDetails, mockVersion, mockDimensions, mockCollection) + Convey("Then it returns an object with all the EditMetadata fields populated", func() { + expectedEditMetadata := model.EditMetadata{ + Dataset: *mockDatasetDetails, + Version: mockVersion, + Dimensions: mockDimensions, + CollectionID: mockCollection.ID, + CollectionState: datasetCollectionItem.State, + CollectionLastEditedBy: datasetCollectionItem.LastEditedBy, + } + So(outcome, ShouldResemble, expectedEditMetadata) + }) + }) + }) + + Convey("And an empty EditMetadata", func() { + editMetadata := model.EditMetadata{} + Convey("When we call PutMetadata", func() { + + editableMetadataObj := PutMetadata(editMetadata) + + Convey("Then it returns an object with all the editable metadata fields populated", func() { + So(editableMetadataObj.Description, ShouldBeEmpty) + So(editableMetadataObj.Keywords, ShouldBeEmpty) + So(editableMetadataObj.Title, ShouldBeEmpty) + So(editableMetadataObj.UnitOfMeasure, ShouldBeEmpty) + So(editableMetadataObj.Contacts, ShouldBeEmpty) + So(editableMetadataObj.QMI.Description, ShouldBeEmpty) + So(editableMetadataObj.QMI.Title, ShouldBeEmpty) + So(editableMetadataObj.QMI.URL, ShouldBeEmpty) + So(editableMetadataObj.RelatedContent, ShouldBeEmpty) + So(editableMetadataObj.CanonicalTopic, ShouldBeEmpty) + So(editableMetadataObj.Subtopics, ShouldBeEmpty) + So(editableMetadataObj.License, ShouldBeEmpty) + So(editableMetadataObj.Methodologies, ShouldBeEmpty) + So(*editableMetadataObj.NationalStatistic, ShouldBeFalse) + So(editableMetadataObj.NextRelease, ShouldBeEmpty) + So(editableMetadataObj.Publications, ShouldBeEmpty) + So(editableMetadataObj.RelatedDatasets, ShouldBeEmpty) + So(editableMetadataObj.ReleaseFrequency, ShouldBeEmpty) + So(editableMetadataObj.Survey, ShouldBeEmpty) + + So(editableMetadataObj.Dimensions, ShouldBeEmpty) + So(editableMetadataObj.ReleaseDate, ShouldBeEmpty) + So(editableMetadataObj.Alerts, ShouldBeNil) + So(editableMetadataObj.LatestChanges, ShouldBeEmpty) + So(editableMetadataObj.UsageNotes, ShouldBeNil) + }) + }) + }) + + Convey("And an EditMetadata object with full dataset and version", func() { + editMetadata := model.EditMetadata{ + Dataset: *mockDatasetDetails, + Version: mockVersion, + } + Convey("When we call PutMetadata", func() { + + editableMetadataObj := PutMetadata(editMetadata) + + Convey("Then it returns an object with all the editable metadata fields populated", func() { + So(editableMetadataObj.Description, ShouldEqual, editMetadata.Dataset.Description) + So(editableMetadataObj.Keywords, ShouldResemble, *editMetadata.Dataset.Keywords) + So(editableMetadataObj.Title, ShouldEqual, editMetadata.Dataset.Title) + So(editableMetadataObj.UnitOfMeasure, ShouldEqual, editMetadata.Dataset.UnitOfMeasure) + So(editableMetadataObj.Contacts, ShouldResemble, *editMetadata.Dataset.Contacts) + So(editableMetadataObj.QMI, ShouldResemble, &editMetadata.Dataset.QMI) + So(editableMetadataObj.RelatedContent, ShouldResemble, *editMetadata.Dataset.RelatedContent) + So(editableMetadataObj.CanonicalTopic, ShouldEqual, editMetadata.Dataset.CanonicalTopic) + So(editableMetadataObj.Subtopics, ShouldResemble, editMetadata.Dataset.Subtopics) + So(editableMetadataObj.License, ShouldResemble, editMetadata.Dataset.License) + So(editableMetadataObj.Methodologies, ShouldResemble, *editMetadata.Dataset.Methodologies) + So(editableMetadataObj.NationalStatistic, ShouldResemble, &editMetadata.Dataset.NationalStatistic) + So(editableMetadataObj.NextRelease, ShouldResemble, editMetadata.Dataset.NextRelease) + So(editableMetadataObj.Publications, ShouldResemble, *editMetadata.Dataset.Publications) + So(editableMetadataObj.RelatedDatasets, ShouldResemble, *editMetadata.Dataset.RelatedDatasets) + So(editableMetadataObj.ReleaseFrequency, ShouldResemble, editMetadata.Dataset.ReleaseFrequency) + So(editableMetadataObj.Survey, ShouldEqual, editMetadata.Dataset.Survey) + + So(editableMetadataObj.Dimensions, ShouldResemble, editMetadata.Version.Dimensions) + So(editableMetadataObj.ReleaseDate, ShouldEqual, editMetadata.Version.ReleaseDate) + So(editableMetadataObj.Alerts, ShouldEqual, editMetadata.Version.Alerts) + So(editableMetadataObj.LatestChanges, ShouldResemble, &editMetadata.Version.LatestChanges) + So(editableMetadataObj.UsageNotes, ShouldEqual, editMetadata.Version.UsageNotes) + }) + }) + }) + }) +} diff --git a/model/dataset.go b/model/dataset.go index 22ab7bd..ae16060 100644 --- a/model/dataset.go +++ b/model/dataset.go @@ -41,6 +41,7 @@ type EditMetadata struct { CollectionID string `json:"collection_id"` CollectionState string `json:"collection_state"` CollectionLastEditedBy string `json:"collection_last_edited_by"` + VersionEtag string `json:"version_etag"` } type EditVersionMetaData struct { diff --git a/routes/routes.go b/routes/routes.go index 5b1ca7a..0c43665 100644 --- a/routes/routes.go +++ b/routes/routes.go @@ -22,4 +22,5 @@ func Init(router *mux.Router, cfg *config.Config, hc healthcheck.HealthCheck, dc router.StrictSlash(true).Path("/datasets/{datasetID}/editions/{editionID}/versions").HandlerFunc(dataset.GetVersions(dc, cfg.DatasetsBatchSize, cfg.DatasetsBatchWorkers)).Methods(http.MethodGet) router.StrictSlash(true).Path("/datasets/{datasetID}/editions/{editionID}/versions/{versionID}").HandlerFunc(dataset.GetMetadataHandler(dc, zc)).Methods(http.MethodGet) router.StrictSlash(true).Path("/datasets/{datasetID}/editions/{editionID}/versions/{versionID}").HandlerFunc(dataset.PutMetadata(dc, zc)).Methods(http.MethodPut) + router.StrictSlash(true).Path("/datasets/{datasetID}/editions/{editionID}/versions/{versionID}/metadata").HandlerFunc(dataset.PutEditableMetadata(dc, zc)).Methods(http.MethodPut) }