@openneuro/server 4.5.0 → 4.5.1
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 +2 -2
- package/src/datalad/__tests__/files.spec.js +13 -0
- package/src/datalad/description.js +1 -0
- package/src/datalad/files.js +11 -1
- package/src/datalad/snapshots.js +3 -1
- package/src/graphql/resolvers/dataset.js +1 -5
- package/src/graphql/resolvers/draft.js +8 -1
- package/src/graphql/resolvers/snapshots.js +3 -0
- package/src/graphql/schema.js +4 -0
- package/src/graphql/utils/file.js +0 -29
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openneuro/server",
|
|
3
|
-
"version": "4.5.
|
|
3
|
+
"version": "4.5.1",
|
|
4
4
|
"description": "Core service for the OpenNeuro platform.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "src/server.js",
|
|
@@ -104,5 +104,5 @@
|
|
|
104
104
|
"publishConfig": {
|
|
105
105
|
"access": "public"
|
|
106
106
|
},
|
|
107
|
-
"gitHead": "
|
|
107
|
+
"gitHead": "92a2879d0f00400c240bfe3319f26c38db8ef866"
|
|
108
108
|
}
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
decodeFilePath,
|
|
4
4
|
fileUrl,
|
|
5
5
|
filterFiles,
|
|
6
|
+
computeTotalSize,
|
|
6
7
|
} from '../files.js'
|
|
7
8
|
|
|
8
9
|
jest.mock('../../config.js')
|
|
@@ -104,4 +105,16 @@ describe('datalad files', () => {
|
|
|
104
105
|
expect(filterFiles('sub-01/func')(mockFiles)).toEqual([mockSub01[1]])
|
|
105
106
|
})
|
|
106
107
|
})
|
|
108
|
+
describe('computeTotalSize()', () => {
|
|
109
|
+
const mockFileSizes = [
|
|
110
|
+
{ filename: 'README', size: 234 },
|
|
111
|
+
{ filename: 'dataset_description.json', size: 432 },
|
|
112
|
+
{ filename: 'sub-01/anat/sub-01_T1w.nii.gz', size: 10858 },
|
|
113
|
+
{
|
|
114
|
+
filename: 'sub-01/func/sub-01_task-onebacktask_run-01_bold.nii.gz',
|
|
115
|
+
size: 1945682,
|
|
116
|
+
},
|
|
117
|
+
]
|
|
118
|
+
expect(computeTotalSize(mockFileSizes)).toBe(1957206)
|
|
119
|
+
})
|
|
107
120
|
})
|
|
@@ -127,6 +127,7 @@ export const description = obj => {
|
|
|
127
127
|
return cache
|
|
128
128
|
.get(() => {
|
|
129
129
|
return getFiles(datasetId, revision)
|
|
130
|
+
.then(response => response.files)
|
|
130
131
|
.then(getDescriptionObject(datasetId))
|
|
131
132
|
.then(uncachedDescription => ({ id: revision, ...uncachedDescription }))
|
|
132
133
|
})
|
package/src/datalad/files.js
CHANGED
|
@@ -51,6 +51,12 @@ export const fileUrl = (datasetId, path, filename) => {
|
|
|
51
51
|
export const filesUrl = datasetId =>
|
|
52
52
|
`http://${getDatasetWorker(datasetId)}/datasets/${datasetId}/files`
|
|
53
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Sum all file sizes for total dataset size
|
|
56
|
+
*/
|
|
57
|
+
export const computeTotalSize = files =>
|
|
58
|
+
files.reduce((size, f) => size + f.size, 0)
|
|
59
|
+
|
|
54
60
|
/**
|
|
55
61
|
* Get files for a specific revision
|
|
56
62
|
* Similar to getDraftFiles but different cache key and fixed revisions
|
|
@@ -75,7 +81,11 @@ export const getFiles = (datasetId, hexsha) => {
|
|
|
75
81
|
const {
|
|
76
82
|
body: { files },
|
|
77
83
|
} = response
|
|
78
|
-
|
|
84
|
+
const size = computeTotalSize(files)
|
|
85
|
+
return {
|
|
86
|
+
files: files.map(addFileUrl(datasetId, hexsha)),
|
|
87
|
+
size,
|
|
88
|
+
}
|
|
79
89
|
}
|
|
80
90
|
}),
|
|
81
91
|
)
|
package/src/datalad/snapshots.js
CHANGED
|
@@ -154,7 +154,9 @@ export const createSnapshot = async (
|
|
|
154
154
|
snapshotChanges,
|
|
155
155
|
)
|
|
156
156
|
snapshot.created = new Date()
|
|
157
|
-
|
|
157
|
+
const { files, size } = await getFiles(datasetId, tag)
|
|
158
|
+
snapshot.files = files
|
|
159
|
+
snapshot.size = size
|
|
158
160
|
|
|
159
161
|
await Promise.all([
|
|
160
162
|
// Update the draft status in datasets collection in case any changes were made (DOI, License)
|
|
@@ -16,9 +16,7 @@ import { history } from './history.js'
|
|
|
16
16
|
import * as dataladAnalytics from '../../datalad/analytics.js'
|
|
17
17
|
import DatasetModel from '../../models/dataset'
|
|
18
18
|
import Deletion from '../../models/deletion'
|
|
19
|
-
import fetch from 'node-fetch'
|
|
20
19
|
import { reviewers } from './reviewer'
|
|
21
|
-
import { UpdatedFile } from '../utils/file.js'
|
|
22
20
|
import { getDatasetWorker } from '../../libs/datalad-service.js'
|
|
23
21
|
import { getDraftHead } from '../../datalad/dataset.js'
|
|
24
22
|
import { getFileName } from '../../datalad/files.js'
|
|
@@ -152,9 +150,7 @@ export const deleteFiles = async (
|
|
|
152
150
|
) => {
|
|
153
151
|
try {
|
|
154
152
|
await checkDatasetWrite(datasetId, user, userInfo)
|
|
155
|
-
const deletedFiles = await datalad
|
|
156
|
-
.deleteFiles(datasetId, files, userInfo)
|
|
157
|
-
.then(filenames => filenames.map(filename => new UpdatedFile(filename)))
|
|
153
|
+
const deletedFiles = await datalad.deleteFiles(datasetId, files, userInfo)
|
|
158
154
|
pubsub.publish('filesUpdated', {
|
|
159
155
|
datasetId,
|
|
160
156
|
filesUpdated: {
|
|
@@ -10,11 +10,17 @@ import { filterRemovedAnnexObjects } from '../utils/file.js'
|
|
|
10
10
|
// A draft must have a dataset parent
|
|
11
11
|
const draftFiles = async (dataset, args, { userInfo }) => {
|
|
12
12
|
const hexsha = await getDraftRevision(dataset.id)
|
|
13
|
-
const files = await getFiles(dataset.id, hexsha)
|
|
13
|
+
const { files } = await getFiles(dataset.id, hexsha)
|
|
14
14
|
const prefixFiltered = filterFiles('prefix' in args && args.prefix)(files)
|
|
15
15
|
return filterRemovedAnnexObjects(dataset.id, userInfo)(prefixFiltered)
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
const draftSize = async (dataset, args, { userInfo }) => {
|
|
19
|
+
const hexsha = await getDraftRevision(dataset.id)
|
|
20
|
+
const { size } = await getFiles(dataset.id, hexsha)
|
|
21
|
+
return size
|
|
22
|
+
}
|
|
23
|
+
|
|
18
24
|
/**
|
|
19
25
|
* Deprecated mutation to move the draft HEAD reference forward or backward
|
|
20
26
|
*
|
|
@@ -39,6 +45,7 @@ export const revalidate = async (obj, { datasetId }, { user, userInfo }) => {
|
|
|
39
45
|
const draft = {
|
|
40
46
|
id: obj => obj.id,
|
|
41
47
|
files: draftFiles,
|
|
48
|
+
size: draftSize,
|
|
42
49
|
summary,
|
|
43
50
|
issues,
|
|
44
51
|
modified: obj => obj.modified,
|
|
@@ -29,8 +29,11 @@ export const snapshot = (obj, { datasetId, tag }, context) => {
|
|
|
29
29
|
summary: () => summary({ id: datasetId, revision: snapshot.hexsha }),
|
|
30
30
|
files: ({ prefix }) =>
|
|
31
31
|
getFiles(datasetId, snapshot.hexsha)
|
|
32
|
+
.then(response => response.files)
|
|
32
33
|
.then(filterFiles(prefix))
|
|
33
34
|
.then(filterRemovedAnnexObjects(datasetId, context.userInfo)),
|
|
35
|
+
size: () =>
|
|
36
|
+
getFiles(datasetId, snapshot.hexsha).then(response => response.size),
|
|
34
37
|
deprecated: () => deprecated({ datasetId, tag }),
|
|
35
38
|
related: () => related(datasetId),
|
|
36
39
|
onBrainlife: () => onBrainlife(snapshot),
|
package/src/graphql/schema.js
CHANGED
|
@@ -430,6 +430,8 @@ export const typeDefs = `
|
|
|
430
430
|
uploads: [UploadMetadata]
|
|
431
431
|
# Git commit hash
|
|
432
432
|
head: String
|
|
433
|
+
# Total size in bytes of this draft
|
|
434
|
+
size: Int
|
|
433
435
|
}
|
|
434
436
|
|
|
435
437
|
# Tagged snapshot of a draft
|
|
@@ -461,6 +463,8 @@ export const typeDefs = `
|
|
|
461
463
|
related: [RelatedObject]
|
|
462
464
|
# Is the snapshot available for analysis on Brainlife?
|
|
463
465
|
onBrainlife: Boolean @cacheControl(maxAge: 10080, scope: PUBLIC)
|
|
466
|
+
# Total size in bytes of this snapshot
|
|
467
|
+
size: Int
|
|
464
468
|
}
|
|
465
469
|
|
|
466
470
|
# RelatedObject nature of relationship
|
|
@@ -1,34 +1,5 @@
|
|
|
1
1
|
import BadAnnexObject from '../../models/badAnnexObject'
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* Generates unique id for untracked files.
|
|
5
|
-
* @param {string} filepath - filepath ('/' delimiters)
|
|
6
|
-
* @param {number|string} [size] - of file
|
|
7
|
-
*/
|
|
8
|
-
export const generateFileId = (filepath, size) => `${filepath}:${size}`
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Creates a file object with an ApolloGQL cache-safe id.
|
|
12
|
-
* @class
|
|
13
|
-
* @param {string} filepath ':' delimited
|
|
14
|
-
* @param {string|number} [size]
|
|
15
|
-
*/
|
|
16
|
-
export function UpdatedFile(filepath, size) {
|
|
17
|
-
/**
|
|
18
|
-
* unique id
|
|
19
|
-
* @id UpdatedFile#id
|
|
20
|
-
* @type {string}
|
|
21
|
-
*/
|
|
22
|
-
this.id = generateFileId(filepath, size)
|
|
23
|
-
/**
|
|
24
|
-
* filename with '/' delimiters
|
|
25
|
-
* @filename UpdatedFile#filename
|
|
26
|
-
* @type {string}
|
|
27
|
-
*/
|
|
28
|
-
this.filename = filepath
|
|
29
|
-
if (size) this.size = size
|
|
30
|
-
}
|
|
31
|
-
|
|
32
3
|
export const filterRemovedAnnexObjects =
|
|
33
4
|
(datasetId, userInfo) => async files => {
|
|
34
5
|
const removedAnnexObjectKeys = (
|