@openneuro/server 4.20.5 → 4.20.6-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -6
- package/src/__mocks__/{config.js → config.ts} +5 -5
- package/src/app.ts +32 -31
- package/src/cache/item.ts +6 -7
- package/src/cache/types.ts +8 -8
- package/src/{config.js → config.ts} +6 -6
- package/src/datalad/__tests__/changelog.spec.ts +83 -0
- package/src/datalad/__tests__/dataset.spec.ts +109 -0
- package/src/datalad/__tests__/description.spec.ts +141 -0
- package/src/datalad/__tests__/files.spec.ts +77 -0
- package/src/datalad/__tests__/pagination.spec.ts +136 -0
- package/src/datalad/__tests__/{snapshots.spec.js → snapshots.spec.ts} +17 -17
- package/src/datalad/{analytics.js → analytics.ts} +4 -4
- package/src/datalad/{changelog.js → changelog.ts} +17 -14
- package/src/datalad/{dataset.js → dataset.ts} +95 -93
- package/src/datalad/{description.js → description.ts} +37 -37
- package/src/datalad/draft.ts +38 -0
- package/src/datalad/files.ts +26 -20
- package/src/datalad/{pagination.js → pagination.ts} +47 -47
- package/src/datalad/{readme.js → readme.ts} +13 -11
- package/src/datalad/{reexporter.js → reexporter.ts} +4 -4
- package/src/datalad/{snapshots.js → snapshots.ts} +56 -62
- package/src/datalad/{upload.js → upload.ts} +7 -5
- package/src/elasticsearch/elastic-client.ts +11 -0
- package/src/elasticsearch/reindex-dataset.ts +7 -7
- package/src/graphql/__tests__/__snapshots__/permissions.spec.ts.snap +5 -0
- package/src/graphql/__tests__/{comment.spec.js → comment.spec.ts} +17 -17
- package/src/graphql/__tests__/permissions.spec.ts +113 -0
- package/src/graphql/{permissions.js → permissions.ts} +14 -14
- package/src/graphql/resolvers/__tests__/brainlife.spec.ts +11 -11
- package/src/graphql/resolvers/__tests__/{dataset-search.spec.js → dataset-search.spec.ts} +25 -23
- package/src/graphql/resolvers/__tests__/dataset.spec.ts +175 -0
- package/src/graphql/resolvers/__tests__/derivatives.spec.ts +19 -19
- package/src/graphql/resolvers/__tests__/importRemoteDataset.spec.ts +20 -20
- package/src/graphql/resolvers/__tests__/permssions.spec.ts +35 -0
- package/src/graphql/resolvers/__tests__/snapshots.spec.ts +59 -0
- package/src/graphql/resolvers/__tests__/user.spec.ts +18 -0
- package/src/graphql/resolvers/brainlife.ts +4 -4
- package/src/graphql/resolvers/cache.ts +4 -4
- package/src/graphql/resolvers/{comment.js → comment.ts} +16 -16
- package/src/graphql/resolvers/{dataset-search.js → dataset-search.ts} +45 -43
- package/src/graphql/resolvers/{dataset.js → dataset.ts} +38 -52
- package/src/graphql/resolvers/datasetType.ts +3 -3
- package/src/graphql/resolvers/derivatives.ts +11 -11
- package/src/graphql/resolvers/description.ts +18 -0
- package/src/graphql/resolvers/{draft.js → draft.ts} +13 -13
- package/src/graphql/resolvers/{flaggedFiles.js → flaggedFiles.ts} +4 -4
- package/src/graphql/resolvers/{follow.js → follow.ts} +1 -1
- package/src/graphql/resolvers/git.ts +3 -3
- package/src/graphql/resolvers/history.ts +13 -0
- package/src/graphql/resolvers/importRemoteDataset.ts +12 -11
- package/src/graphql/resolvers/index.ts +25 -0
- package/src/graphql/resolvers/{issues.js → issues.ts} +9 -9
- package/src/graphql/resolvers/metadata.ts +8 -8
- package/src/graphql/resolvers/{mutation.js → mutation.ts} +26 -26
- package/src/graphql/resolvers/{newsletter.js → newsletter.ts} +2 -2
- package/src/graphql/resolvers/permissions.ts +15 -21
- package/src/graphql/resolvers/publish.ts +17 -0
- package/src/graphql/resolvers/query.ts +21 -0
- package/src/graphql/resolvers/{readme.js → readme.ts} +3 -3
- package/src/graphql/resolvers/{reexporter.js → reexporter.ts} +2 -2
- package/src/graphql/resolvers/relation.ts +5 -5
- package/src/graphql/resolvers/{reset.js → reset.ts} +2 -2
- package/src/graphql/resolvers/reviewer.ts +4 -4
- package/src/graphql/resolvers/{snapshots.js → snapshots.ts} +49 -49
- package/src/graphql/resolvers/{stars.js → stars.ts} +1 -1
- package/src/graphql/resolvers/summary.ts +3 -3
- package/src/graphql/resolvers/{upload.js → upload.ts} +5 -5
- package/src/graphql/resolvers/{user.js → user.ts} +16 -18
- package/src/graphql/resolvers/{validation.js → validation.ts} +12 -14
- package/src/graphql/{schema.js → schema.ts} +4 -6
- package/src/graphql/utils/{file.js → file.ts} +2 -2
- package/src/handlers/{comments.js → comments.ts} +11 -11
- package/src/handlers/{config.js → config.ts} +1 -1
- package/src/handlers/{datalad.js → datalad.ts} +22 -22
- package/src/handlers/{doi.js → doi.ts} +6 -6
- package/src/handlers/reviewer.ts +6 -6
- package/src/handlers/{sitemap.js → sitemap.ts} +19 -19
- package/src/handlers/stars.ts +11 -10
- package/src/handlers/{subscriptions.js → subscriptions.ts} +17 -16
- package/src/handlers/{users.js → users.ts} +3 -3
- package/src/libs/__tests__/apikey.spec.ts +25 -0
- package/src/libs/__tests__/datalad-service.spec.ts +27 -0
- package/src/libs/__tests__/{dataset.spec.js → dataset.spec.ts} +9 -9
- package/src/libs/{apikey.js → apikey.ts} +5 -5
- package/src/libs/authentication/__tests__/jwt.spec.ts +59 -0
- package/src/libs/authentication/{crypto.js → crypto.ts} +16 -16
- package/src/libs/authentication/google.ts +18 -0
- package/src/libs/authentication/jwt.ts +40 -33
- package/src/libs/authentication/{orcid.js → orcid.ts} +11 -11
- package/src/libs/authentication/{passport.js → passport.ts} +45 -30
- package/src/libs/authentication/{states.js → states.ts} +17 -20
- package/src/libs/{counter.js → counter.ts} +1 -1
- package/src/libs/{datalad-service.js → datalad-service.ts} +4 -4
- package/src/libs/dataset.ts +9 -0
- package/src/libs/doi/__tests__/__snapshots__/doi.spec.ts.snap +17 -0
- package/src/libs/doi/__tests__/doi.spec.ts +25 -0
- package/src/libs/doi/__tests__/normalize.spec.ts +19 -19
- package/src/libs/doi/{index.js → index.ts} +27 -21
- package/src/libs/doi/normalize.ts +2 -2
- package/src/libs/email/__tests__/index.spec.ts +14 -14
- package/src/libs/email/index.ts +4 -4
- package/src/libs/email/templates/__tests__/comment-created.spec.ts +12 -12
- package/src/libs/email/templates/__tests__/dataset-deleted.spec.ts +6 -6
- package/src/libs/email/templates/__tests__/owner-unsubscribed.spec.ts +6 -6
- package/src/libs/email/templates/__tests__/snapshot-created.spec.ts +9 -9
- package/src/libs/email/templates/__tests__/snapshot-reminder.spec.ts +7 -7
- package/src/libs/email/templates/comment-created.ts +2 -1
- package/src/libs/email/templates/dataset-deleted.ts +2 -1
- package/src/libs/email/templates/dataset-import-failed.ts +2 -1
- package/src/libs/email/templates/dataset-imported.ts +2 -1
- package/src/libs/email/templates/owner-unsubscribed.ts +2 -1
- package/src/libs/email/templates/snapshot-created.ts +2 -1
- package/src/libs/email/templates/snapshot-reminder.ts +2 -1
- package/src/libs/{notifications.js → notifications.ts} +100 -113
- package/src/libs/{orcid.js → orcid.ts} +20 -20
- package/src/libs/{redis.js → redis.ts} +6 -6
- package/src/models/__tests__/ingestDataset.spec.ts +15 -15
- package/src/models/analytics.ts +2 -2
- package/src/models/badAnnexObject.ts +6 -6
- package/src/models/comment.ts +10 -10
- package/src/models/counter.ts +2 -2
- package/src/models/dataset.ts +16 -16
- package/src/models/deletion.ts +3 -3
- package/src/models/deprecatedSnapshot.ts +2 -2
- package/src/models/doi.ts +2 -2
- package/src/models/file.ts +2 -2
- package/src/models/ingestDataset.ts +4 -4
- package/src/models/issue.ts +2 -2
- package/src/models/key.ts +2 -2
- package/src/models/mailgunIdentifier.ts +2 -2
- package/src/models/metadata.ts +3 -3
- package/src/models/newsletter.ts +3 -3
- package/src/models/notification.ts +2 -2
- package/src/models/permission.ts +4 -4
- package/src/models/reviewer.ts +7 -7
- package/src/models/snapshot.ts +2 -2
- package/src/models/stars.ts +6 -6
- package/src/models/subscription.ts +2 -2
- package/src/models/summary.ts +2 -2
- package/src/models/upload.ts +3 -3
- package/src/models/user.ts +4 -4
- package/src/{routes.js → routes.ts} +62 -62
- package/src/server.ts +9 -9
- package/src/utils/__tests__/datasetOrSnapshot.spec.ts +25 -25
- package/src/utils/__tests__/validateUrl.spec.ts +10 -10
- package/src/utils/datasetOrSnapshot.ts +2 -2
- package/src/utils/validateUrl.ts +1 -1
- package/src/datalad/__tests__/changelog.spec.js +0 -82
- package/src/datalad/__tests__/dataset.spec.js +0 -109
- package/src/datalad/__tests__/description.spec.js +0 -137
- package/src/datalad/__tests__/files.spec.js +0 -75
- package/src/datalad/__tests__/pagination.spec.js +0 -136
- package/src/datalad/draft.js +0 -37
- package/src/elasticsearch/elastic-client.js +0 -11
- package/src/graphql/__tests__/permissions.spec.js +0 -107
- package/src/graphql/pubsub.js +0 -5
- package/src/graphql/resolvers/__tests__/dataset.spec.js +0 -175
- package/src/graphql/resolvers/__tests__/permssions.spec.js +0 -34
- package/src/graphql/resolvers/__tests__/snapshots.spec.js +0 -58
- package/src/graphql/resolvers/__tests__/user.spec.js +0 -17
- package/src/graphql/resolvers/description.js +0 -29
- package/src/graphql/resolvers/history.js +0 -11
- package/src/graphql/resolvers/index.js +0 -25
- package/src/graphql/resolvers/publish.js +0 -17
- package/src/graphql/resolvers/query.js +0 -21
- package/src/graphql/resolvers/subscriptions.js +0 -81
- package/src/graphql/utils/publish-draft-update.js +0 -13
- package/src/libs/__tests__/apikey.spec.js +0 -24
- package/src/libs/__tests__/datalad-service.spec.js +0 -26
- package/src/libs/authentication/__tests__/jwt.spec.js +0 -23
- package/src/libs/authentication/globus.js +0 -11
- package/src/libs/authentication/google.js +0 -19
- package/src/libs/bidsId.js +0 -68
- package/src/libs/dataset.js +0 -9
- package/src/libs/doi/__tests__/doi.spec.js +0 -24
- package/src/libs/redis-pubsub.js +0 -5
- package/src/libs/request.js +0 -155
- package/src/libs/scitran.js +0 -25
- package/src/libs/subscription-server.js +0 -20
- package/src/libs/testing-utils.js +0 -17
- package/src/persistent/datasets/.gitignore +0 -3
- package/src/persistent/temp/.gitignore +0 -3
- /package/src/libs/__mocks__/{notifications.js → notifications.ts} +0 -0
- /package/src/libs/authentication/{verifyUser.js → verifyUser.ts} +0 -0
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getDescriptionObject,
|
|
3
|
-
repairDescriptionTypes,
|
|
4
|
-
appendSeniorAuthor,
|
|
5
|
-
} from '../description.js'
|
|
6
|
-
|
|
7
|
-
// Mock requests to Datalad service
|
|
8
|
-
vi.mock('ioredis')
|
|
9
|
-
vi.mock('../../config.js')
|
|
10
|
-
|
|
11
|
-
describe('datalad dataset descriptions', () => {
|
|
12
|
-
describe('appendSeniorAuthor', () => {
|
|
13
|
-
it('returns author out of several', () => {
|
|
14
|
-
expect(
|
|
15
|
-
appendSeniorAuthor({
|
|
16
|
-
Authors: ['A. Bee', 'C. Dee', 'E. Eff'],
|
|
17
|
-
Name: 'test dataset',
|
|
18
|
-
}),
|
|
19
|
-
).toHaveProperty('SeniorAuthor', 'E. Eff')
|
|
20
|
-
})
|
|
21
|
-
it('returns a description when no Authors array is provided', () => {
|
|
22
|
-
expect(
|
|
23
|
-
appendSeniorAuthor({ Authors: null, Name: 'test dataset' }),
|
|
24
|
-
).toHaveProperty('Name', 'test dataset')
|
|
25
|
-
})
|
|
26
|
-
it('returns a description when no Authors array is empty', () => {
|
|
27
|
-
expect(
|
|
28
|
-
appendSeniorAuthor({ Authors: [], Name: 'test dataset' }),
|
|
29
|
-
).toHaveProperty('Name', 'test dataset')
|
|
30
|
-
})
|
|
31
|
-
})
|
|
32
|
-
describe('repairDescriptionTypes', () => {
|
|
33
|
-
it('converts strings to one element arrays for array fields', () => {
|
|
34
|
-
const description = {
|
|
35
|
-
Authors: 'Not, An Array',
|
|
36
|
-
BIDSVersion: '1.2.0',
|
|
37
|
-
ReferencesAndLinks: 'https://openneuro.org',
|
|
38
|
-
Funding: ['This one', 'is correct'],
|
|
39
|
-
EthicsApprovals: 'Also, Not, Array',
|
|
40
|
-
}
|
|
41
|
-
const repaired = repairDescriptionTypes(description)
|
|
42
|
-
// Check for discarded fields
|
|
43
|
-
expect(repaired.BIDSVersion).toBe(description.BIDSVersion)
|
|
44
|
-
// Check for extra fields
|
|
45
|
-
expect(repaired.DatasetDOI).toBe(undefined)
|
|
46
|
-
// Test each repaired field for type correct value
|
|
47
|
-
expect(Array.isArray(repaired.Authors)).toBe(true)
|
|
48
|
-
expect(Array.isArray(repaired.ReferencesAndLinks)).toBe(true)
|
|
49
|
-
expect(Array.isArray(repaired.Funding)).toBe(true)
|
|
50
|
-
expect(Array.isArray(repaired.EthicsApprovals)).toBe(true)
|
|
51
|
-
})
|
|
52
|
-
it('converts any invalid value to string values for string fields', () => {
|
|
53
|
-
const description = {
|
|
54
|
-
BIDSVersion: '1.2.0',
|
|
55
|
-
Name: 1.5,
|
|
56
|
-
DatasetDOI: ['Should', 'not', 'be', 'an', 'array'],
|
|
57
|
-
Acknowledgements: ['Should not be an array'],
|
|
58
|
-
HowToAcknowledge: Symbol(), // This can't serialize but just in case
|
|
59
|
-
}
|
|
60
|
-
const repaired = repairDescriptionTypes(description)
|
|
61
|
-
// Check for discarded fields
|
|
62
|
-
expect(repaired.BIDSVersion).toBe(description.BIDSVersion)
|
|
63
|
-
// Check for extra fields
|
|
64
|
-
expect(repaired.Authors).toBe(undefined)
|
|
65
|
-
// Check converted types
|
|
66
|
-
expect(typeof repaired.Name).toBe('string')
|
|
67
|
-
expect(typeof repaired.DatasetDOI).toBe('string')
|
|
68
|
-
expect(typeof repaired.Acknowledgements).toBe('string')
|
|
69
|
-
expect(typeof repaired.HowToAcknowledge).toBe('string')
|
|
70
|
-
})
|
|
71
|
-
it('returns correct types for empty strings', () => {
|
|
72
|
-
const description = {
|
|
73
|
-
Name: 'Classification learning',
|
|
74
|
-
License:
|
|
75
|
-
'This dataset is made available under the Public Domain Dedication and License \nv1.0, whose full text can be found at \nhttp://www.opendatacommons.org/licenses/pddl/1.0/. \nWe hope that all users will follow the ODC Attribution/Share-Alike \nCommunity Norms (http://www.opendatacommons.org/norms/odc-by-sa/); \nin particular, while not legally required, we hope that all users \nof the data will acknowledge the OpenfMRI project and NSF Grant \nOCI-1131441 (R. Poldrack, PI) in any publications.',
|
|
76
|
-
Authors: '',
|
|
77
|
-
Acknowledgements: '',
|
|
78
|
-
HowToAcknowledge: '',
|
|
79
|
-
Funding: '',
|
|
80
|
-
ReferencesAndLinks: '',
|
|
81
|
-
DatasetDOI: '',
|
|
82
|
-
BIDSVersion: '1.0.0',
|
|
83
|
-
}
|
|
84
|
-
const repaired = repairDescriptionTypes(description)
|
|
85
|
-
expect(Array.isArray(repaired.Authors)).toBe(true)
|
|
86
|
-
expect(Array.isArray(repaired.ReferencesAndLinks)).toBe(true)
|
|
87
|
-
expect(Array.isArray(repaired.Funding)).toBe(true)
|
|
88
|
-
})
|
|
89
|
-
})
|
|
90
|
-
describe('getDescriptionObject()', () => {
|
|
91
|
-
beforeAll(() => {
|
|
92
|
-
global.fetch = vi.fn()
|
|
93
|
-
})
|
|
94
|
-
it('returns the parsed dataset_description.json object', async () => {
|
|
95
|
-
fetch.mockResolvedValue({
|
|
96
|
-
json: () =>
|
|
97
|
-
Promise.resolve({ Name: 'Balloon Analog Risk-taking Task' }),
|
|
98
|
-
headers: {
|
|
99
|
-
get: () => 'application/json',
|
|
100
|
-
},
|
|
101
|
-
status: 200,
|
|
102
|
-
})
|
|
103
|
-
const description = await getDescriptionObject('ds000001', '1.0.0')
|
|
104
|
-
expect(description).toEqual({ Name: 'Balloon Analog Risk-taking Task' })
|
|
105
|
-
})
|
|
106
|
-
it('handles a corrupted response', async () => {
|
|
107
|
-
global.fetch = vi.fn()
|
|
108
|
-
fetch.mockResolvedValue({
|
|
109
|
-
json: () => Promise.reject('JSON could not be parsed'),
|
|
110
|
-
headers: {
|
|
111
|
-
get: () => 'application/json',
|
|
112
|
-
},
|
|
113
|
-
status: 400,
|
|
114
|
-
})
|
|
115
|
-
await expect(getDescriptionObject('ds000001', '1.0.0')).rejects.toEqual(
|
|
116
|
-
Error(
|
|
117
|
-
'Backend request failed, dataset_description.json may not exist or may be non-JSON (type: application/json, status: 400)',
|
|
118
|
-
),
|
|
119
|
-
)
|
|
120
|
-
})
|
|
121
|
-
it('throws an error when nothing is returned', async () => {
|
|
122
|
-
global.fetch = vi.fn()
|
|
123
|
-
fetch.mockResolvedValue({
|
|
124
|
-
json: () => Promise.reject('JSON could not be parsed'),
|
|
125
|
-
headers: {
|
|
126
|
-
get: () => 'application/json',
|
|
127
|
-
},
|
|
128
|
-
status: 404,
|
|
129
|
-
})
|
|
130
|
-
await expect(getDescriptionObject('ds000001', '1.0.0')).rejects.toEqual(
|
|
131
|
-
Error(
|
|
132
|
-
'Backend request failed, dataset_description.json may not exist or may be non-JSON (type: application/json, status: 404)',
|
|
133
|
-
),
|
|
134
|
-
)
|
|
135
|
-
})
|
|
136
|
-
})
|
|
137
|
-
})
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
encodeFilePath,
|
|
3
|
-
decodeFilePath,
|
|
4
|
-
fileUrl,
|
|
5
|
-
computeTotalSize,
|
|
6
|
-
} from '../files'
|
|
7
|
-
|
|
8
|
-
vi.mock('ioredis')
|
|
9
|
-
vi.mock('../../config.js')
|
|
10
|
-
|
|
11
|
-
const filename = 'sub-01/anat/sub-01_T1w.nii.gz'
|
|
12
|
-
|
|
13
|
-
const mockRootFiles = [
|
|
14
|
-
{ filename: 'README' },
|
|
15
|
-
{ filename: 'dataset_description.json' },
|
|
16
|
-
]
|
|
17
|
-
const mockSub01 = [
|
|
18
|
-
{ filename: 'sub-01/anat/sub-01_T1w.nii.gz' },
|
|
19
|
-
{ filename: 'sub-01/func/sub-01_task-onebacktask_run-01_bold.nii.gz' },
|
|
20
|
-
]
|
|
21
|
-
const mockSub02 = [
|
|
22
|
-
{ filename: 'sub-02/anat/sub-02_T1w.nii.gz' },
|
|
23
|
-
{ filename: 'sub-02/func/sub-02_task-onebacktask_run-01_bold.nii.gz' },
|
|
24
|
-
]
|
|
25
|
-
const mockSub03 = [
|
|
26
|
-
{ filename: 'sub-03/anat/sub-03_T1w.nii.gz' },
|
|
27
|
-
{ filename: 'sub-03/func/sub-03_task-onebacktask_run-01_bold.nii.gz' },
|
|
28
|
-
]
|
|
29
|
-
const mockDerivatives = [{ filename: 'derivatives/groundbreaking_output.html' }]
|
|
30
|
-
const mockFiles = [
|
|
31
|
-
...mockRootFiles,
|
|
32
|
-
...mockSub01,
|
|
33
|
-
...mockSub02,
|
|
34
|
-
...mockSub03,
|
|
35
|
-
...mockDerivatives,
|
|
36
|
-
]
|
|
37
|
-
|
|
38
|
-
describe('datalad files', () => {
|
|
39
|
-
describe('encodeFilePath()', () => {
|
|
40
|
-
it('should encode a nested path', () => {
|
|
41
|
-
expect(encodeFilePath(filename)).toBe('sub-01:anat:sub-01_T1w.nii.gz')
|
|
42
|
-
})
|
|
43
|
-
})
|
|
44
|
-
describe('decodeFilePath()', () => {
|
|
45
|
-
it('decodes a file path', () => {
|
|
46
|
-
expect(decodeFilePath('sub-01:anat:sub-01_T1w.nii.gz')).toBe(filename)
|
|
47
|
-
})
|
|
48
|
-
})
|
|
49
|
-
describe('fileUrl()', () => {
|
|
50
|
-
it('returns a working URL', () => {
|
|
51
|
-
expect(fileUrl('ds000001', '', filename)).toBe(
|
|
52
|
-
'http://datalad-0/datasets/ds000001/files/sub-01:anat:sub-01_T1w.nii.gz',
|
|
53
|
-
)
|
|
54
|
-
})
|
|
55
|
-
it('handles path nesting', () => {
|
|
56
|
-
expect(fileUrl('ds000001', 'sub-01/anat', 'sub-01_T1w.nii.gz')).toBe(
|
|
57
|
-
'http://datalad-0/datasets/ds000001/files/sub-01:anat:sub-01_T1w.nii.gz',
|
|
58
|
-
)
|
|
59
|
-
})
|
|
60
|
-
})
|
|
61
|
-
describe('computeTotalSize()', () => {
|
|
62
|
-
it('computes the size correctly', () => {
|
|
63
|
-
const mockFileSizes = [
|
|
64
|
-
{ filename: 'README', size: 234 },
|
|
65
|
-
{ filename: 'dataset_description.json', size: 432 },
|
|
66
|
-
{ filename: 'sub-01/anat/sub-01_T1w.nii.gz', size: 10858 },
|
|
67
|
-
{
|
|
68
|
-
filename: 'sub-01/func/sub-01_task-onebacktask_run-01_bold.nii.gz',
|
|
69
|
-
size: 1945682,
|
|
70
|
-
},
|
|
71
|
-
]
|
|
72
|
-
expect(computeTotalSize(mockFileSizes)).toBe(1957206)
|
|
73
|
-
})
|
|
74
|
-
})
|
|
75
|
-
})
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import { vi } from 'vitest'
|
|
2
|
-
vi.mock('ioredis')
|
|
3
|
-
import * as pagination from '../pagination.js'
|
|
4
|
-
import { connect, Types } from 'mongoose'
|
|
5
|
-
import Dataset from '../../models/dataset'
|
|
6
|
-
const ObjectID = Types.ObjectId
|
|
7
|
-
|
|
8
|
-
const base64 = /^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$/
|
|
9
|
-
|
|
10
|
-
describe('pagination model operations', () => {
|
|
11
|
-
describe('enumToMongoSort()', () => {
|
|
12
|
-
it('should convert enum strings to -1 or 1 values', () => {
|
|
13
|
-
expect(
|
|
14
|
-
pagination.enumToMongoSort({
|
|
15
|
-
created: 'descending',
|
|
16
|
-
name: 'ascending',
|
|
17
|
-
}),
|
|
18
|
-
).toEqual({ created: -1, name: 1 })
|
|
19
|
-
})
|
|
20
|
-
})
|
|
21
|
-
describe('apiCursor()', () => {
|
|
22
|
-
it('returns base64 string', () => {
|
|
23
|
-
expect(pagination.apiCursor(new ObjectID(5))).toMatch(base64)
|
|
24
|
-
})
|
|
25
|
-
})
|
|
26
|
-
describe('applyCursorToEdges()', () => {
|
|
27
|
-
it('returns the correct shape matching Relay connections', () => {
|
|
28
|
-
const res = pagination.applyCursorToEdges(
|
|
29
|
-
[{ _id: '123' }, { _id: '234' }, { _id: '345' }],
|
|
30
|
-
0,
|
|
31
|
-
)
|
|
32
|
-
expect(res).toEqual([
|
|
33
|
-
{ cursor: 'eyJvZmZzZXQiOjB9', node: { _id: '123' } },
|
|
34
|
-
{ cursor: 'eyJvZmZzZXQiOjF9', node: { _id: '234' } },
|
|
35
|
-
{ cursor: 'eyJvZmZzZXQiOjJ9', node: { _id: '345' } },
|
|
36
|
-
])
|
|
37
|
-
})
|
|
38
|
-
})
|
|
39
|
-
describe('datasetsConnection()', () => {
|
|
40
|
-
beforeAll(async () => {
|
|
41
|
-
await connect(globalThis.__MONGO_URI__)
|
|
42
|
-
const ds = new Dataset({
|
|
43
|
-
_id: new ObjectID('5bef51a1ed211400c08e5524'),
|
|
44
|
-
id: 'ds001001',
|
|
45
|
-
created: new Date('2018-11-16T23:24:17.203Z'),
|
|
46
|
-
modified: new Date('2018-11-16T23:24:25.050Z'),
|
|
47
|
-
uploader: 'f8d5a57c-879a-40e6-b151-e34c4a28ff70',
|
|
48
|
-
revision: '262a8e610e32b5766cbf669acc71911c1ece7126',
|
|
49
|
-
})
|
|
50
|
-
await ds.save()
|
|
51
|
-
})
|
|
52
|
-
it('returns a connection shaped result', async () => {
|
|
53
|
-
const res = await pagination.datasetsConnection({
|
|
54
|
-
orderBy: { created: 'ascending' },
|
|
55
|
-
limit: 5,
|
|
56
|
-
first: 10,
|
|
57
|
-
})([])
|
|
58
|
-
expect(res).toHaveProperty('pageInfo')
|
|
59
|
-
expect(res).toHaveProperty('edges')
|
|
60
|
-
})
|
|
61
|
-
})
|
|
62
|
-
describe('maxLimit()', () => {
|
|
63
|
-
it('should be within range 1-100', () => {
|
|
64
|
-
expect(pagination.maxLimit(0)).toBe(1)
|
|
65
|
-
expect(pagination.maxLimit(101)).toBe(100)
|
|
66
|
-
})
|
|
67
|
-
it('does not error with negative values', () => {
|
|
68
|
-
expect(pagination.maxLimit(-10)).toBe(1)
|
|
69
|
-
})
|
|
70
|
-
})
|
|
71
|
-
describe('sortAggregate()', () => {
|
|
72
|
-
it('should return natural sort for orderBy: created', () => {
|
|
73
|
-
expect(
|
|
74
|
-
pagination.sortAggregate({ orderBy: { created: 'ascending' } }),
|
|
75
|
-
).toEqual([{ $sort: { _id: 1 } }])
|
|
76
|
-
})
|
|
77
|
-
it('does not throw an error with no orderBy', () => {
|
|
78
|
-
expect(pagination.sortAggregate({})).toEqual([])
|
|
79
|
-
})
|
|
80
|
-
it('should return -1 for descending sorts', () => {
|
|
81
|
-
expect(
|
|
82
|
-
pagination.sortAggregate({ orderBy: { created: 'descending' } }),
|
|
83
|
-
).toEqual([{ $sort: { _id: -1 } }])
|
|
84
|
-
})
|
|
85
|
-
it('includes "name" for name sorts', () => {
|
|
86
|
-
expect(
|
|
87
|
-
pagination.sortAggregate({ orderBy: { name: 'descending' } }),
|
|
88
|
-
).toEqual([{ $sort: { name: -1 } }])
|
|
89
|
-
})
|
|
90
|
-
it('returns a lookup and count stage for stars', () => {
|
|
91
|
-
const agg = pagination.sortAggregate({ orderBy: { stars: 'ascending' } })
|
|
92
|
-
expect(agg[0]).toHaveProperty('$lookup')
|
|
93
|
-
expect(agg[1]).toHaveProperty('$addFields')
|
|
94
|
-
// Ends with count sort
|
|
95
|
-
expect(agg.slice(-1)).toEqual([{ $sort: { starsCount: 1 } }])
|
|
96
|
-
})
|
|
97
|
-
it('returns a lookup and count stage for subscriptions', () => {
|
|
98
|
-
const agg = pagination.sortAggregate({
|
|
99
|
-
orderBy: { subscriptions: 'descending' },
|
|
100
|
-
})
|
|
101
|
-
expect(agg[0]).toHaveProperty('$lookup')
|
|
102
|
-
expect(agg[1]).toHaveProperty('$addFields')
|
|
103
|
-
// Ends with count sort
|
|
104
|
-
expect(agg.slice(-1)).toEqual([{ $sort: { subscriptionsCount: -1 } }])
|
|
105
|
-
})
|
|
106
|
-
it('returns a lookup and no count stage for downloads', () => {
|
|
107
|
-
const agg = pagination.sortAggregate({
|
|
108
|
-
orderBy: { downloads: 'ascending' },
|
|
109
|
-
})
|
|
110
|
-
// Ends with count sort
|
|
111
|
-
expect(agg.slice(-1)).toEqual([{ $sort: { downloads: 1 } }])
|
|
112
|
-
})
|
|
113
|
-
it('returns a lookup and no count stage for views', () => {
|
|
114
|
-
const agg = pagination.sortAggregate({
|
|
115
|
-
orderBy: { views: 'ascending' },
|
|
116
|
-
})
|
|
117
|
-
// Ends with count sort
|
|
118
|
-
expect(agg.slice(-1)).toEqual([{ $sort: { views: 1 } }])
|
|
119
|
-
})
|
|
120
|
-
it('does not explode with all sorts', () => {
|
|
121
|
-
const agg = pagination.sortAggregate({
|
|
122
|
-
orderBy: {
|
|
123
|
-
created: 'ascending',
|
|
124
|
-
name: 'ascending',
|
|
125
|
-
uploader: 'ascending',
|
|
126
|
-
stars: 'ascending',
|
|
127
|
-
downloads: 'ascending',
|
|
128
|
-
subscriptions: 'ascending',
|
|
129
|
-
},
|
|
130
|
-
})
|
|
131
|
-
expect(agg).toHaveLength(6)
|
|
132
|
-
// Final stage should always be a sort
|
|
133
|
-
expect(agg.slice(-1)[0]).toHaveProperty('$sort')
|
|
134
|
-
})
|
|
135
|
-
})
|
|
136
|
-
})
|
package/src/datalad/draft.js
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Manage serving a Draft object based on DataLad working trees
|
|
3
|
-
*/
|
|
4
|
-
import request from 'superagent'
|
|
5
|
-
import Dataset from '../models/dataset'
|
|
6
|
-
import publishDraftUpdate from '../graphql/utils/publish-draft-update.js'
|
|
7
|
-
import { getDatasetWorker } from '../libs/datalad-service'
|
|
8
|
-
|
|
9
|
-
export const getDraftRevision = async datasetId => {
|
|
10
|
-
const draftUrl = `http://${getDatasetWorker(
|
|
11
|
-
datasetId,
|
|
12
|
-
)}/datasets/${datasetId}/draft`
|
|
13
|
-
const response = await fetch(draftUrl)
|
|
14
|
-
const { hexsha } = await response.json()
|
|
15
|
-
return hexsha
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export const updateDatasetRevision = (datasetId, gitRef) => {
|
|
19
|
-
/**
|
|
20
|
-
* Update the revision modified time in a draft on changes
|
|
21
|
-
*/
|
|
22
|
-
return Dataset.updateOne({ id: datasetId }, { modified: new Date() })
|
|
23
|
-
.exec()
|
|
24
|
-
.then(() => publishDraftUpdate(datasetId, gitRef))
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Run a git reset on the draft
|
|
29
|
-
* @param {string} datasetId Accession number
|
|
30
|
-
* @param {string} ref Git hexsha
|
|
31
|
-
*/
|
|
32
|
-
export const resetDraft = (datasetId, ref) => {
|
|
33
|
-
const resetUrl = `${getDatasetWorker(
|
|
34
|
-
datasetId,
|
|
35
|
-
)}/datasets/${datasetId}/reset/${ref}`
|
|
36
|
-
return request.post(resetUrl).set('Accept', 'application/json')
|
|
37
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import config from '../config.js'
|
|
2
|
-
import { Client } from '@elastic/elasticsearch'
|
|
3
|
-
|
|
4
|
-
const elasticConfig = {
|
|
5
|
-
node: config.elasticsearch.connection || 'http://mock-client',
|
|
6
|
-
maxRetries: 3,
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export const elasticClient = new Client(elasticConfig)
|
|
10
|
-
|
|
11
|
-
export default elasticClient
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
datasetReadQuery,
|
|
3
|
-
checkPermissionLevel,
|
|
4
|
-
states,
|
|
5
|
-
checkDatasetWrite,
|
|
6
|
-
checkDatasetAdmin,
|
|
7
|
-
} from '../permissions'
|
|
8
|
-
|
|
9
|
-
vi.mock('ioredis')
|
|
10
|
-
|
|
11
|
-
describe('resolver permissions helpers', () => {
|
|
12
|
-
describe('datasetReadQuery()', () => {
|
|
13
|
-
it('returns public for anonymous users', () => {
|
|
14
|
-
expect(datasetReadQuery('ds000001', null, null)).toHaveProperty(
|
|
15
|
-
'public',
|
|
16
|
-
true,
|
|
17
|
-
)
|
|
18
|
-
})
|
|
19
|
-
it('returns non-public for admins', () => {
|
|
20
|
-
expect(
|
|
21
|
-
datasetReadQuery('ds000001', '1234', { admin: true }),
|
|
22
|
-
).not.toHaveProperty('public', true)
|
|
23
|
-
})
|
|
24
|
-
it('returns public for logged in users', () => {
|
|
25
|
-
expect(
|
|
26
|
-
datasetReadQuery('ds000001', '1234', { admin: false }),
|
|
27
|
-
).toHaveProperty('public', true)
|
|
28
|
-
})
|
|
29
|
-
})
|
|
30
|
-
describe('checkPermissionLevel(..., READ)', () => {
|
|
31
|
-
it('returns false if no permission passed in', () => {
|
|
32
|
-
expect(checkPermissionLevel(null, states.READ)).toBe(false)
|
|
33
|
-
})
|
|
34
|
-
it('returns true for valid read access level', () => {
|
|
35
|
-
expect(checkPermissionLevel({ level: 'admin' }, states.READ)).toBe(true)
|
|
36
|
-
expect(checkPermissionLevel({ level: 'ro' }, states.READ)).toBe(true)
|
|
37
|
-
})
|
|
38
|
-
it('returns false if an unexpected level is present', () => {
|
|
39
|
-
expect(checkPermissionLevel({ level: 'not-real' }, states.READ)).toBe(
|
|
40
|
-
false,
|
|
41
|
-
)
|
|
42
|
-
})
|
|
43
|
-
})
|
|
44
|
-
describe('checkPermissionLevel(..., WRITE)', () => {
|
|
45
|
-
it('returns false if no permission passed in', () => {
|
|
46
|
-
expect(checkPermissionLevel(null, states.WRITE)).toBe(false)
|
|
47
|
-
})
|
|
48
|
-
it('returns true for admin', () => {
|
|
49
|
-
expect(checkPermissionLevel({ level: 'admin' }, states.WRITE)).toBe(true)
|
|
50
|
-
})
|
|
51
|
-
it('returns false for read only access', () => {
|
|
52
|
-
expect(checkPermissionLevel({ level: 'ro' }, states.WRITE)).toBe(false)
|
|
53
|
-
})
|
|
54
|
-
it('returns false if an unexpected level is present', () => {
|
|
55
|
-
expect(checkPermissionLevel({ level: 'not-real' }, states.WRITE)).toBe(
|
|
56
|
-
false,
|
|
57
|
-
)
|
|
58
|
-
})
|
|
59
|
-
})
|
|
60
|
-
describe('checkDatasetWrite()', () => {
|
|
61
|
-
it('resolves to false for anonymous users', () => {
|
|
62
|
-
return expect(
|
|
63
|
-
checkDatasetWrite('ds000001', null, null, undefined, {
|
|
64
|
-
checkExists: false,
|
|
65
|
-
}),
|
|
66
|
-
).rejects.toThrowErrorMatchingSnapshot()
|
|
67
|
-
})
|
|
68
|
-
it('resolves to true for admins', () => {
|
|
69
|
-
return expect(
|
|
70
|
-
checkDatasetWrite('ds000001', '1234', { admin: true }, undefined, {
|
|
71
|
-
checkExists: false,
|
|
72
|
-
}),
|
|
73
|
-
).resolves.toBe(true)
|
|
74
|
-
})
|
|
75
|
-
})
|
|
76
|
-
describe('checkPermissionLevel(..., ADMIN)', () => {
|
|
77
|
-
it('returns false if no permission passed in', () => {
|
|
78
|
-
expect(checkPermissionLevel(null, states.ADMIN)).toBe(false)
|
|
79
|
-
})
|
|
80
|
-
it('returns true for admin', () => {
|
|
81
|
-
expect(checkPermissionLevel({ level: 'admin' }, states.ADMIN)).toBe(true)
|
|
82
|
-
})
|
|
83
|
-
it('returns false for read write access', () => {
|
|
84
|
-
expect(checkPermissionLevel({ level: 'rw' }, states.ADMIN)).toBe(false)
|
|
85
|
-
})
|
|
86
|
-
it('returns false for read only access', () => {
|
|
87
|
-
expect(checkPermissionLevel({ level: 'ro' }, states.ADMIN)).toBe(false)
|
|
88
|
-
})
|
|
89
|
-
it('returns false if an unexpected level is present', () => {
|
|
90
|
-
expect(checkPermissionLevel({ level: 'not-real' }, states.ADMIN)).toBe(
|
|
91
|
-
false,
|
|
92
|
-
)
|
|
93
|
-
})
|
|
94
|
-
})
|
|
95
|
-
describe('checkDatasetAdmin()', () => {
|
|
96
|
-
it('resolves to false for anonymous users', () => {
|
|
97
|
-
return expect(
|
|
98
|
-
checkDatasetAdmin('ds000001', null, null, false),
|
|
99
|
-
).rejects.toThrowErrorMatchingSnapshot()
|
|
100
|
-
})
|
|
101
|
-
it('resolves to true for admins', () => {
|
|
102
|
-
return expect(
|
|
103
|
-
checkDatasetAdmin('ds000001', '1234', { admin: true }, false),
|
|
104
|
-
).resolves.toBe(true)
|
|
105
|
-
})
|
|
106
|
-
})
|
|
107
|
-
})
|
package/src/graphql/pubsub.js
DELETED
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
import { vi } from 'vitest'
|
|
2
|
-
import { connect } from 'mongoose'
|
|
3
|
-
import request from 'superagent'
|
|
4
|
-
import * as ds from '../dataset'
|
|
5
|
-
|
|
6
|
-
vi.mock('superagent')
|
|
7
|
-
vi.mock('ioredis')
|
|
8
|
-
vi.mock('../../../config.js')
|
|
9
|
-
vi.mock('../../../libs/notifications.js')
|
|
10
|
-
|
|
11
|
-
describe('dataset resolvers', () => {
|
|
12
|
-
beforeAll(() => {
|
|
13
|
-
connect(globalThis.__MONGO_URI__)
|
|
14
|
-
})
|
|
15
|
-
describe('createDataset()', () => {
|
|
16
|
-
it('createDataset mutation succeeds', async () => {
|
|
17
|
-
const { id: dsId } = await ds.createDataset(
|
|
18
|
-
null,
|
|
19
|
-
{ affirmedDefaced: true, affirmedConsent: false },
|
|
20
|
-
{ user: '123456', userInfo: {} },
|
|
21
|
-
)
|
|
22
|
-
expect(dsId).toEqual(expect.stringMatching(/^ds[0-9]{6}$/))
|
|
23
|
-
})
|
|
24
|
-
})
|
|
25
|
-
describe('snapshotCreationComparison()', () => {
|
|
26
|
-
it('sorts array of objects by the "created" and "tag" properties', () => {
|
|
27
|
-
const testArray = [
|
|
28
|
-
{ id: 2, created: new Date('2018-11-20T00:05:43.473Z'), tag: '1.0.0' },
|
|
29
|
-
{ id: 1, created: new Date('2018-11-19T00:05:43.473Z'), tag: '1.0.1' },
|
|
30
|
-
{ id: 3, created: new Date('2018-11-23T00:05:43.473Z'), tag: '1.0.2' },
|
|
31
|
-
{ id: 5, created: new Date('2018-11-23T00:05:43.473Z'), tag: '1.0.10' },
|
|
32
|
-
{ id: 4, created: new Date('2018-11-23T00:05:43.473Z'), tag: '1.0.3' },
|
|
33
|
-
]
|
|
34
|
-
const sorted = testArray.sort(ds.snapshotCreationComparison)
|
|
35
|
-
expect(sorted[0].id).toBe(2)
|
|
36
|
-
expect(sorted[1].id).toBe(1)
|
|
37
|
-
expect(sorted[2].id).toBe(3)
|
|
38
|
-
expect(sorted[3].id).toBe(4)
|
|
39
|
-
expect(sorted[4].id).toBe(5)
|
|
40
|
-
})
|
|
41
|
-
it('sorts array of objects by the "created" property as strings', () => {
|
|
42
|
-
const testArray = [
|
|
43
|
-
{ id: 2, created: '2018-11-20T00:05:43.473Z' },
|
|
44
|
-
{ id: 1, created: '2018-11-19T00:05:43.473Z' },
|
|
45
|
-
{ id: 3, created: '2018-11-23T00:05:43.473Z' },
|
|
46
|
-
]
|
|
47
|
-
const sorted = testArray.sort(ds.snapshotCreationComparison)
|
|
48
|
-
expect(sorted[0].id).toBe(1)
|
|
49
|
-
expect(sorted[1].id).toBe(2)
|
|
50
|
-
expect(sorted[2].id).toBe(3)
|
|
51
|
-
})
|
|
52
|
-
it('sorts non-semver tags mixed with semver tags', () => {
|
|
53
|
-
const testArray = [
|
|
54
|
-
{ id: 2, created: new Date('2018-11-19T00:05:43.473Z'), tag: '1.0.2' },
|
|
55
|
-
{
|
|
56
|
-
id: 1,
|
|
57
|
-
created: new Date('2018-11-19T00:05:43.473Z'),
|
|
58
|
-
tag: '57fed018cce88d000ac1757f',
|
|
59
|
-
},
|
|
60
|
-
{ id: 3, created: new Date('2018-11-19T00:05:43.473Z'), tag: '1.0.1' },
|
|
61
|
-
]
|
|
62
|
-
const sorted = testArray.sort(ds.snapshotCreationComparison)
|
|
63
|
-
expect(sorted[0].id).toBe(2)
|
|
64
|
-
expect(sorted[1].id).toBe(1)
|
|
65
|
-
expect(sorted[2].id).toBe(3)
|
|
66
|
-
})
|
|
67
|
-
it('sorts snapshots with only non-semver tags', () => {
|
|
68
|
-
const testArray = [
|
|
69
|
-
{
|
|
70
|
-
id: 2,
|
|
71
|
-
created: new Date('2018-11-19T00:05:43.473Z'),
|
|
72
|
-
tag: '00001',
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
id: 1,
|
|
76
|
-
created: new Date('2018-11-19T00:05:43.473Z'),
|
|
77
|
-
tag: '57fed018cce88d000ac1757f',
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
id: 3,
|
|
81
|
-
created: new Date('2018-11-19T00:05:43.473Z'),
|
|
82
|
-
tag: '57fed018cce88d000ac1757f',
|
|
83
|
-
},
|
|
84
|
-
]
|
|
85
|
-
const sorted = testArray.sort(ds.snapshotCreationComparison)
|
|
86
|
-
expect(sorted[0].id).toBe(2)
|
|
87
|
-
expect(sorted[1].id).toBe(1)
|
|
88
|
-
expect(sorted[2].id).toBe(3)
|
|
89
|
-
})
|
|
90
|
-
it('sorts very similar creation times by semver order', () => {
|
|
91
|
-
const testSnapshots = [
|
|
92
|
-
{
|
|
93
|
-
id: 'ds002680:1.0.0',
|
|
94
|
-
created: '2020-04-03T23:19:56.000Z',
|
|
95
|
-
tag: '1.0.0',
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
id: 'ds002680:1.2.0',
|
|
99
|
-
created: '2021-10-19T16:26:43.000Z',
|
|
100
|
-
tag: '1.2.0',
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
id: 'ds002680:1.1.0',
|
|
104
|
-
created: '2021-10-19T16:26:44.000Z',
|
|
105
|
-
tag: '1.1.0',
|
|
106
|
-
},
|
|
107
|
-
]
|
|
108
|
-
const sorted = testSnapshots.sort(ds.snapshotCreationComparison)
|
|
109
|
-
expect(sorted[0].id).toBe('ds002680:1.0.0')
|
|
110
|
-
expect(sorted[1].id).toBe('ds002680:1.1.0')
|
|
111
|
-
expect(sorted[2].id).toBe('ds002680:1.2.0')
|
|
112
|
-
})
|
|
113
|
-
it('sorts 000002 (legacy snapshots) before 1.0.1 (current format)', () => {
|
|
114
|
-
const testSnapshots = [
|
|
115
|
-
{
|
|
116
|
-
id: 'ds000247:00002',
|
|
117
|
-
created: '2018-07-18T02:27:39.000Z',
|
|
118
|
-
tag: '00002',
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
id: 'ds000247:00001',
|
|
122
|
-
created: '2018-07-18T02:35:37.000Z',
|
|
123
|
-
tag: '00001',
|
|
124
|
-
},
|
|
125
|
-
{
|
|
126
|
-
id: 'ds000247:1.0.0',
|
|
127
|
-
created: '2021-07-05T15:58:18.000Z',
|
|
128
|
-
tag: '1.0.0',
|
|
129
|
-
},
|
|
130
|
-
{
|
|
131
|
-
id: 'ds000247:1.0.1',
|
|
132
|
-
created: '2021-08-25T23:37:53.000Z',
|
|
133
|
-
tag: '1.0.1',
|
|
134
|
-
},
|
|
135
|
-
]
|
|
136
|
-
const sorted = testSnapshots.sort(ds.snapshotCreationComparison)
|
|
137
|
-
expect(sorted[0].id).toBe('ds000247:00002')
|
|
138
|
-
expect(sorted[1].id).toBe('ds000247:00001')
|
|
139
|
-
expect(sorted[2].id).toBe('ds000247:1.0.0')
|
|
140
|
-
expect(sorted[3].id).toBe('ds000247:1.0.1')
|
|
141
|
-
})
|
|
142
|
-
})
|
|
143
|
-
describe('deleteFiles', () => {
|
|
144
|
-
beforeEach(() => {
|
|
145
|
-
request.post.mockClear()
|
|
146
|
-
})
|
|
147
|
-
it('makes correct delete call to datalad', () => {
|
|
148
|
-
// capture and check datalad delete request
|
|
149
|
-
request.del = url => ({
|
|
150
|
-
set: (header1, headerValue1) => ({
|
|
151
|
-
set: () => ({
|
|
152
|
-
send: ({ filenames }) => {
|
|
153
|
-
expect(url).toEqual('http://datalad-0/datasets/ds999999/files')
|
|
154
|
-
expect(filenames).toEqual([':sub-99'])
|
|
155
|
-
expect(header1).toEqual('Cookie')
|
|
156
|
-
expect(headerValue1).toMatch(/^accessToken=/)
|
|
157
|
-
},
|
|
158
|
-
}),
|
|
159
|
-
}),
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
return ds.deleteFiles(
|
|
163
|
-
null,
|
|
164
|
-
{ datasetId: 'ds999999', files: [{ path: '/sub-99' }] },
|
|
165
|
-
{
|
|
166
|
-
user: 'a_user_id',
|
|
167
|
-
userInfo: {
|
|
168
|
-
// bypass permission checks
|
|
169
|
-
admin: true,
|
|
170
|
-
},
|
|
171
|
-
},
|
|
172
|
-
)
|
|
173
|
-
})
|
|
174
|
-
})
|
|
175
|
-
})
|