Skip to content

Commit bcc4259

Browse files
Merge branch 'develop' into feat/4885/add-related-content-at-edition-level
2 parents 3c2034e + 34ff90d commit bcc4259

29 files changed

Lines changed: 741 additions & 68 deletions

api/api.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,23 @@ func (api DatasetAPI) getPermissionAttributesFromRequest(req *http.Request) (map
509509
}, nil
510510
}
511511

512+
versions, _, err := api.dataStore.Backend.GetVersionsStaticByEditionNoLimit(req.Context(), datasetID, edition, "")
513+
logData := log.Data{"dataset_id": datasetID, "edition": edition}
514+
if err != nil {
515+
log.Error(req.Context(), "failed to get versions for dataset edition", err, logData)
516+
}
517+
518+
for i := range versions {
519+
for _, prevEdition := range versions[i].PreviousEditionId {
520+
previousAttributes := map[string]string{
521+
"dataset_edition": datasetID + "/" + prevEdition,
522+
}
523+
if api.checkUserPermission(req, logData, datasetEditionVersionReadPermission, previousAttributes) {
524+
return previousAttributes, nil
525+
}
526+
}
527+
}
528+
512529
return map[string]string{
513530
"dataset_edition": datasetID + "/" + edition,
514531
}, nil

api/auth_test.go

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,18 @@ import (
77
"errors"
88
"io"
99
"net/http"
10+
"net/http/httptest"
1011
"testing"
1112

1213
healthcheck "github.com/ONSdigital/dp-api-clients-go/v2/health"
1314
authMock "github.com/ONSdigital/dp-authorisation/v2/authorisation/mock"
15+
"github.com/ONSdigital/dp-dataset-api/models"
16+
"github.com/ONSdigital/dp-dataset-api/store"
17+
storetest "github.com/ONSdigital/dp-dataset-api/store/datastoretest"
1418
dphttp "github.com/ONSdigital/dp-net/v3/http"
1519
dprequest "github.com/ONSdigital/dp-net/v3/request"
1620
permissionsAPISDK "github.com/ONSdigital/dp-permissions-api/sdk"
21+
"github.com/gorilla/mux"
1722
. "github.com/smartystreets/goconvey/convey"
1823

1924
clientsidentity "github.com/ONSdigital/dp-api-clients-go/v2/identity"
@@ -188,3 +193,87 @@ func TestGetAccessTokenFromRequest(t *testing.T) {
188193
})
189194
}
190195
}
196+
197+
func TestGetPermissionAttributesFromRequest(t *testing.T) {
198+
Convey("Given a request for permission attributes", t, func() {
199+
Convey("When only a dataset id is provided", func() {
200+
datasetID := "test-dataset"
201+
mockedDataStore := &storetest.StorerMock{}
202+
api := DatasetAPI{dataStore: store.DataStore{Backend: mockedDataStore}}
203+
204+
req := httptest.NewRequest(http.MethodGet, "/datasets/"+datasetID, http.NoBody)
205+
req = mux.SetURLVars(req, map[string]string{"dataset_id": datasetID})
206+
207+
attributes, err := api.getPermissionAttributesFromRequest(req)
208+
209+
Convey("Then it should return the dataset id without checking versions", func() {
210+
So(err, ShouldBeNil)
211+
So(attributes, ShouldResemble, map[string]string{"dataset_edition": datasetID})
212+
So(len(mockedDataStore.GetVersionsStaticNoLimitCalls()), ShouldEqual, 0)
213+
})
214+
})
215+
216+
Convey("When a dataset id and edition are provided", func() {
217+
datasetID := "test-dataset"
218+
edition := "2024"
219+
mockedDataStore := &storetest.StorerMock{
220+
GetVersionsStaticByEditionNoLimitFunc: func(ctx context.Context, datasetID string, edition string, state string) ([]*models.Version, int, error) {
221+
return []*models.Version{}, 0, nil
222+
},
223+
}
224+
api := DatasetAPI{dataStore: store.DataStore{Backend: mockedDataStore}}
225+
226+
req := httptest.NewRequest(http.MethodGet, "/datasets/"+datasetID+"/editions/"+edition, http.NoBody)
227+
req = mux.SetURLVars(req, map[string]string{"dataset_id": datasetID, "edition": edition})
228+
229+
attributes, err := api.getPermissionAttributesFromRequest(req)
230+
231+
Convey("Then it should return the dataset edition from the request", func() {
232+
So(err, ShouldBeNil)
233+
So(attributes, ShouldResemble, map[string]string{"dataset_edition": datasetID + "/" + edition})
234+
So(len(mockedDataStore.GetVersionsStaticByEditionNoLimitCalls()), ShouldEqual, 1)
235+
})
236+
})
237+
238+
Convey("When a dataset id and edition are provided and the user has access to a previous edition", func() {
239+
datasetID := "test-dataset"
240+
edition := "2024"
241+
previousEdition := "2023"
242+
mockedDataStore := &storetest.StorerMock{
243+
GetVersionsStaticByEditionNoLimitFunc: func(ctx context.Context, datasetID string, edition string, state string) ([]*models.Version, int, error) {
244+
return []*models.Version{{PreviousEditionId: []string{previousEdition}}}, 0, nil
245+
},
246+
}
247+
permissionsChecker := &authMock.PermissionsCheckerMock{
248+
HasPermissionFunc: func(ctx context.Context, entityData permissionsAPISDK.EntityData, permission string, attributes map[string]string) (bool, error) {
249+
return attributes["dataset_edition"] == datasetID+"/"+previousEdition, nil
250+
},
251+
}
252+
api := DatasetAPI{
253+
dataStore: store.DataStore{Backend: mockedDataStore},
254+
EnablePrePublishView: true,
255+
authMiddleware: &authMock.MiddlewareMock{
256+
ParseFunc: func(token string) (*permissionsAPISDK.EntityData, error) {
257+
So(token, ShouldEqual, "valid-token")
258+
return testEntityData, nil
259+
},
260+
},
261+
permissionsChecker: permissionsChecker,
262+
}
263+
264+
req := httptest.NewRequest(http.MethodGet, "/datasets/"+datasetID+"/editions/"+edition, http.NoBody)
265+
req.Header.Set(dprequest.AuthHeaderKey, dprequest.BearerPrefix+"valid-token")
266+
req = mux.SetURLVars(req, map[string]string{"dataset_id": datasetID, "edition": edition})
267+
268+
attributes, err := api.getPermissionAttributesFromRequest(req)
269+
270+
Convey("Then it should return the permitted previous edition", func() {
271+
So(err, ShouldBeNil)
272+
So(attributes, ShouldResemble, map[string]string{"dataset_edition": datasetID + "/" + previousEdition})
273+
So(len(mockedDataStore.GetVersionsStaticByEditionNoLimitCalls()), ShouldEqual, 1)
274+
So(len(permissionsChecker.HasPermissionCalls()), ShouldEqual, 1)
275+
So(permissionsChecker.HasPermissionCalls()[0].Attributes, ShouldResemble, map[string]string{"dataset_edition": datasetID + "/" + previousEdition})
276+
})
277+
})
278+
})
279+
}

api/editions_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,9 @@ func TestGetEditionReturnsOK(t *testing.T) {
658658
GetDatasetTypeFunc: func(context.Context, string, bool) (string, error) {
659659
return models.CantabularFlexibleTable.String(), nil
660660
},
661+
GetVersionsStaticByEditionNoLimitFunc: func(ctx context.Context, datasetID string, edition string, state string) ([]*models.Version, int, error) {
662+
return nil, 0, nil
663+
},
661664
}
662665

663666
authorisationMock := &authMock.MiddlewareMock{
@@ -682,6 +685,7 @@ func TestGetEditionReturnsOK(t *testing.T) {
682685
So(len(mockedDataStore.GetDatasetTypeCalls()), ShouldEqual, 1)
683686
So(len(mockedDataStore.GetEditionCalls()), ShouldEqual, 1)
684687
So(len(mockedDataStore.GetLatestVersionStaticCalls()), ShouldEqual, 0)
688+
So(len(mockedDataStore.GetVersionsStaticByEditionNoLimitCalls()), ShouldEqual, 1)
685689
})
686690

687691
Convey("A successful request to get edition when dataset is static returns 200 OK response", t, func() {
@@ -697,6 +701,9 @@ func TestGetEditionReturnsOK(t *testing.T) {
697701
GetLatestVersionStaticFunc: func(context.Context, string, string, string) (*models.Version, error) {
698702
return exampleStaticVersion, nil
699703
},
704+
GetVersionsStaticByEditionNoLimitFunc: func(ctx context.Context, datasetID string, edition string, state string) ([]*models.Version, int, error) {
705+
return nil, 0, nil
706+
},
700707
}
701708

702709
authorisationMock := &authMock.MiddlewareMock{
@@ -721,6 +728,7 @@ func TestGetEditionReturnsOK(t *testing.T) {
721728
So(len(mockedDataStore.GetDatasetTypeCalls()), ShouldEqual, 1)
722729
So(len(mockedDataStore.GetLatestVersionStaticCalls()), ShouldEqual, 2)
723730
So(len(mockedDataStore.GetEditionCalls()), ShouldEqual, 0)
731+
So(len(mockedDataStore.GetVersionsStaticByEditionNoLimitCalls()), ShouldEqual, 1)
724732
})
725733
}
726734

@@ -736,6 +744,9 @@ func TestGetEditionReturnsError(t *testing.T) {
736744
GetDatasetTypeFunc: func(context.Context, string, bool) (string, error) {
737745
return "", errs.ErrInternalServer
738746
},
747+
GetVersionsStaticByEditionNoLimitFunc: func(ctx context.Context, datasetID string, edition string, state string) ([]*models.Version, int, error) {
748+
return nil, 0, nil
749+
},
739750
}
740751

741752
authorisationMock := &authMock.MiddlewareMock{
@@ -755,6 +766,7 @@ func TestGetEditionReturnsError(t *testing.T) {
755766
So(len(mockedDataStore.GetDatasetTypeCalls()), ShouldEqual, 0)
756767
So(len(mockedDataStore.GetEditionCalls()), ShouldEqual, 0)
757768
So(len(mockedDataStore.GetLatestVersionStaticCalls()), ShouldEqual, 0)
769+
So(len(mockedDataStore.GetVersionsStaticByEditionNoLimitCalls()), ShouldEqual, 1)
758770
})
759771

760772
Convey("When the dataset does not exist return status not found", t, func() {
@@ -768,6 +780,9 @@ func TestGetEditionReturnsError(t *testing.T) {
768780
GetDatasetTypeFunc: func(context.Context, string, bool) (string, error) {
769781
return "", errs.ErrDatasetNotFound
770782
},
783+
GetVersionsStaticByEditionNoLimitFunc: func(ctx context.Context, datasetID string, edition string, state string) ([]*models.Version, int, error) {
784+
return nil, 0, nil
785+
},
771786
}
772787

773788
authorisationMock := &authMock.MiddlewareMock{
@@ -787,6 +802,7 @@ func TestGetEditionReturnsError(t *testing.T) {
787802
So(len(mockedDataStore.GetDatasetTypeCalls()), ShouldEqual, 0)
788803
So(len(mockedDataStore.GetEditionCalls()), ShouldEqual, 0)
789804
So(len(mockedDataStore.GetLatestVersionStaticCalls()), ShouldEqual, 0)
805+
So(len(mockedDataStore.GetVersionsStaticByEditionNoLimitCalls()), ShouldEqual, 1)
790806
})
791807

792808
Convey("When edition does not exist for a dataset return status not found", t, func() {
@@ -803,6 +819,9 @@ func TestGetEditionReturnsError(t *testing.T) {
803819
GetEditionFunc: func(context.Context, string, string, string) (*models.EditionUpdate, error) {
804820
return nil, errs.ErrEditionNotFound
805821
},
822+
GetVersionsStaticByEditionNoLimitFunc: func(ctx context.Context, datasetID string, edition string, state string) ([]*models.Version, int, error) {
823+
return nil, 0, nil
824+
},
806825
}
807826

808827
authorisationMock := &authMock.MiddlewareMock{
@@ -822,6 +841,7 @@ func TestGetEditionReturnsError(t *testing.T) {
822841
So(len(mockedDataStore.GetDatasetTypeCalls()), ShouldEqual, 1)
823842
So(len(mockedDataStore.GetEditionCalls()), ShouldEqual, 1)
824843
So(len(mockedDataStore.GetLatestVersionStaticCalls()), ShouldEqual, 0)
844+
So(len(mockedDataStore.GetVersionsStaticByEditionNoLimitCalls()), ShouldEqual, 1)
825845
})
826846

827847
Convey("When edition is not published for a dataset return status not found", t, func() {
@@ -837,6 +857,9 @@ func TestGetEditionReturnsError(t *testing.T) {
837857
GetEditionFunc: func(context.Context, string, string, string) (*models.EditionUpdate, error) {
838858
return nil, errs.ErrEditionNotFound
839859
},
860+
GetVersionsStaticByEditionNoLimitFunc: func(ctx context.Context, datasetID string, edition string, state string) ([]*models.Version, int, error) {
861+
return nil, 0, nil
862+
},
840863
}
841864

842865
authorisationMock := &authMock.MiddlewareMock{
@@ -856,6 +879,7 @@ func TestGetEditionReturnsError(t *testing.T) {
856879
So(len(mockedDataStore.GetDatasetTypeCalls()), ShouldEqual, 1)
857880
So(len(mockedDataStore.GetEditionCalls()), ShouldEqual, 1)
858881
So(len(mockedDataStore.GetLatestVersionStaticCalls()), ShouldEqual, 0)
882+
So(len(mockedDataStore.GetVersionsStaticByEditionNoLimitCalls()), ShouldEqual, 1)
859883
})
860884

861885
Convey("When dataset is static and version does not exist return status not found", t, func() {
@@ -871,6 +895,9 @@ func TestGetEditionReturnsError(t *testing.T) {
871895
GetLatestVersionStaticFunc: func(context.Context, string, string, string) (*models.Version, error) {
872896
return nil, errs.ErrVersionNotFound
873897
},
898+
GetVersionsStaticByEditionNoLimitFunc: func(ctx context.Context, datasetID string, edition string, state string) ([]*models.Version, int, error) {
899+
return nil, 0, nil
900+
},
874901
}
875902

876903
authorisationMock := &authMock.MiddlewareMock{
@@ -890,6 +917,7 @@ func TestGetEditionReturnsError(t *testing.T) {
890917
So(len(mockedDataStore.GetDatasetTypeCalls()), ShouldEqual, 1)
891918
So(len(mockedDataStore.GetEditionCalls()), ShouldEqual, 0)
892919
So(len(mockedDataStore.GetLatestVersionStaticCalls()), ShouldEqual, 1)
920+
So(len(mockedDataStore.GetVersionsStaticByEditionNoLimitCalls()), ShouldEqual, 1)
893921
})
894922
}
895923

@@ -965,6 +993,9 @@ func TestGetEditionRecordsAuditEvent(t *testing.T) {
965993
}
966994
return unpublishedVersion, nil
967995
},
996+
GetVersionsStaticByEditionNoLimitFunc: func(ctx context.Context, datasetID string, edition string, state string) ([]*models.Version, int, error) {
997+
return nil, 0, nil
998+
},
968999
}
9691000

9701001
auditServiceMock := &applicationMocks.AuditServiceMock{
@@ -1009,6 +1040,7 @@ func TestGetEditionRecordsAuditEvent(t *testing.T) {
10091040
So(len(mockedDataStore.IsStaticDatasetCalls()), ShouldEqual, 1)
10101041
So(len(mockedDataStore.GetDatasetTypeCalls()), ShouldEqual, 1)
10111042
So(len(mockedDataStore.GetLatestVersionStaticCalls()), ShouldEqual, 2)
1043+
So(len(mockedDataStore.GetVersionsStaticByEditionNoLimitCalls()), ShouldEqual, 1)
10121044
})
10131045
})
10141046
})
@@ -1060,6 +1092,9 @@ func TestGetEditionRecordsAuditEventWithPublishedVersionOnly(t *testing.T) {
10601092
}
10611093
return nil, errs.ErrVersionNotFound
10621094
},
1095+
GetVersionsStaticByEditionNoLimitFunc: func(ctx context.Context, datasetID string, edition string, state string) ([]*models.Version, int, error) {
1096+
return nil, 0, nil
1097+
},
10631098
}
10641099

10651100
auditServiceMock := &applicationMocks.AuditServiceMock{
@@ -1146,6 +1181,9 @@ func TestGetEditionDoesNotRecordAuditEventForUnauthorisedUser(t *testing.T) {
11461181
GetLatestVersionStaticFunc: func(ctx context.Context, datasetID, editionID, state string) (*models.Version, error) {
11471182
return publishedVersion, nil
11481183
},
1184+
GetVersionsStaticByEditionNoLimitFunc: func(ctx context.Context, datasetID string, edition string, state string) ([]*models.Version, int, error) {
1185+
return nil, 0, nil
1186+
},
11491187
}
11501188

11511189
auditServiceMock := &applicationMocks.AuditServiceMock{
@@ -1183,6 +1221,7 @@ func TestGetEditionDoesNotRecordAuditEventForUnauthorisedUser(t *testing.T) {
11831221
So(len(mockedDataStore.IsStaticDatasetCalls()), ShouldEqual, 1)
11841222
So(len(mockedDataStore.GetDatasetTypeCalls()), ShouldEqual, 1)
11851223
So(len(mockedDataStore.GetLatestVersionStaticCalls()), ShouldEqual, 1)
1224+
So(len(mockedDataStore.GetVersionsStaticByEditionNoLimitCalls()), ShouldEqual, 1)
11861225
})
11871226
})
11881227
})
@@ -1234,6 +1273,9 @@ func TestGetEditionAuditEventLogsErrorButContinues(t *testing.T) {
12341273
}
12351274
return nil, errs.ErrVersionNotFound
12361275
},
1276+
GetVersionsStaticByEditionNoLimitFunc: func(ctx context.Context, datasetID string, edition string, state string) ([]*models.Version, int, error) {
1277+
return nil, 0, nil
1278+
},
12371279
}
12381280

12391281
auditServiceMock := &applicationMocks.AuditServiceMock{
@@ -1312,6 +1354,9 @@ func TestGetEditionReturnsIsMigration(t *testing.T) {
13121354
GetLatestVersionStaticFunc: func(ctx context.Context, datasetID, editionID, state string) (*models.Version, error) {
13131355
return publishedVersion, nil
13141356
},
1357+
GetVersionsStaticByEditionNoLimitFunc: func(ctx context.Context, datasetID string, edition string, state string) ([]*models.Version, int, error) {
1358+
return nil, 0, nil
1359+
},
13151360
}
13161361

13171362
Convey("When an unauthenticated user calls the GET edition endpoint", func() {
@@ -1422,6 +1467,9 @@ func TestGetEditionReturnsIsMigration(t *testing.T) {
14221467
GetLatestVersionStaticFunc: func(ctx context.Context, datasetID, editionID, state string) (*models.Version, error) {
14231468
return publishedVersion, nil
14241469
},
1470+
GetVersionsStaticByEditionNoLimitFunc: func(ctx context.Context, datasetID string, edition string, state string) ([]*models.Version, int, error) {
1471+
return nil, 0, nil
1472+
},
14251473
}
14261474

14271475
authorisationMock := &authMock.MiddlewareMock{

0 commit comments

Comments
 (0)