@openneuro/server 3.36.5 → 3.36.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 -2
- package/src/graphql/resolvers/__tests__/dataset.spec.js +13 -11
- package/src/graphql/resolvers/dataset-search.js +6 -2
- package/src/graphql/resolvers/dataset.js +9 -2
- package/src/graphql/resolvers/summary.js +7 -3
- package/src/libs/authentication/google.js +12 -9
- package/src/libs/authentication/jwt.js +4 -1
- package/src/libs/subscription-server.js +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openneuro/server",
|
|
3
|
-
"version": "3.36.
|
|
3
|
+
"version": "3.36.6-alpha.3",
|
|
4
4
|
"description": "Core service for the OpenNeuro platform.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "src/server.js",
|
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
"react-dom": "^17.0.1",
|
|
62
62
|
"redlock": "^4.0.0",
|
|
63
63
|
"request": "^2.83.0",
|
|
64
|
+
"semver": "^5.5.0",
|
|
64
65
|
"sitemap": "^2.1.0",
|
|
65
66
|
"subscriptions-transport-ws": "0.9.18",
|
|
66
67
|
"superagent": "^3.8.2",
|
|
@@ -81,6 +82,7 @@
|
|
|
81
82
|
"@types/ioredis": "^4.17.1",
|
|
82
83
|
"@types/jest": "^26.0.23",
|
|
83
84
|
"@types/nodemailer": "^6.4.1",
|
|
85
|
+
"@types/semver": "^5",
|
|
84
86
|
"apollo-link-schema": "^1.2.5",
|
|
85
87
|
"babel-eslint": "^10.1.0",
|
|
86
88
|
"core-js": "^3.10.1",
|
|
@@ -102,5 +104,5 @@
|
|
|
102
104
|
"publishConfig": {
|
|
103
105
|
"access": "public"
|
|
104
106
|
},
|
|
105
|
-
"gitHead": "
|
|
107
|
+
"gitHead": "6a4df10b0ebd14c63ce0ec4df651153cb353146d"
|
|
106
108
|
}
|
|
@@ -27,16 +27,20 @@ describe('dataset resolvers', () => {
|
|
|
27
27
|
})
|
|
28
28
|
})
|
|
29
29
|
describe('snapshotCreationComparison()', () => {
|
|
30
|
-
it('sorts array of objects by the "created"
|
|
30
|
+
it('sorts array of objects by the "created" and "tag" properties', () => {
|
|
31
31
|
const testArray = [
|
|
32
|
-
{ id: 2, created: new Date('2018-11-20T00:05:43.473Z') },
|
|
33
|
-
{ id: 1, created: new Date('2018-11-19T00:05:43.473Z') },
|
|
34
|
-
{ id: 3, created: new Date('2018-11-23T00:05:43.473Z') },
|
|
32
|
+
{ id: 2, created: new Date('2018-11-20T00:05:43.473Z'), tag: '1.0.0' },
|
|
33
|
+
{ id: 1, created: new Date('2018-11-19T00:05:43.473Z'), tag: '1.0.1' },
|
|
34
|
+
{ id: 3, created: new Date('2018-11-23T00:05:43.473Z'), tag: '1.0.2' },
|
|
35
|
+
{ id: 5, created: new Date('2018-11-23T00:05:43.473Z'), tag: '1.0.10' },
|
|
36
|
+
{ id: 4, created: new Date('2018-11-23T00:05:43.473Z'), tag: '1.0.3' },
|
|
35
37
|
]
|
|
36
38
|
const sorted = testArray.sort(ds.snapshotCreationComparison)
|
|
37
39
|
expect(sorted[0].id).toBe(1)
|
|
38
40
|
expect(sorted[1].id).toBe(2)
|
|
39
41
|
expect(sorted[2].id).toBe(3)
|
|
42
|
+
expect(sorted[3].id).toBe(4)
|
|
43
|
+
expect(sorted[4].id).toBe(5)
|
|
40
44
|
})
|
|
41
45
|
it('sorts array of objects by the "created" property as strings', () => {
|
|
42
46
|
const testArray = [
|
|
@@ -60,18 +64,16 @@ describe('dataset resolvers', () => {
|
|
|
60
64
|
mockingoose.Dataset.toReturn(true, 'count')
|
|
61
65
|
// capture and check datalad delete request
|
|
62
66
|
request.del = url => ({
|
|
63
|
-
|
|
67
|
+
set: (header1, headerValue1) => ({
|
|
64
68
|
set: () => ({
|
|
65
|
-
|
|
66
|
-
expect(url).toEqual(
|
|
67
|
-
'http://datalad-0/datasets/ds999999/files',
|
|
68
|
-
)
|
|
69
|
+
send: ({ filenames }) => {
|
|
70
|
+
expect(url).toEqual('http://datalad-0/datasets/ds999999/files')
|
|
69
71
|
expect(filenames).toEqual([':sub-99'])
|
|
70
72
|
expect(header1).toEqual('Cookie')
|
|
71
73
|
expect(headerValue1).toMatch(/^accessToken=/)
|
|
72
|
-
}
|
|
73
|
-
}),
|
|
74
|
+
},
|
|
74
75
|
}),
|
|
76
|
+
}),
|
|
75
77
|
})
|
|
76
78
|
|
|
77
79
|
ds.deleteFiles(
|
|
@@ -194,6 +194,7 @@ const parseQuery = async (query, datasetType, datasetStatus, userId) => {
|
|
|
194
194
|
* @param {any} obj
|
|
195
195
|
* @param {object} args
|
|
196
196
|
* @param {object} args.query Stringified Query (DSL) argument for ElasticSearch
|
|
197
|
+
* @param {boolean} args.allDatasets Admin option for returning all datasets (overrides datasetType and datasetStatus, but keeps other search parameters) (default = false)
|
|
197
198
|
* @param {string} args.datasetType Stringified Query (DSL) argument for ElasticSearch
|
|
198
199
|
* @param {string} args.datasetStatus Stringified Query (DSL) argument for ElasticSearch
|
|
199
200
|
* @param {object} args.sortBy Stringified Query (DSL) argument for ElasticSearch
|
|
@@ -202,7 +203,7 @@ const parseQuery = async (query, datasetType, datasetStatus, userId) => {
|
|
|
202
203
|
*/
|
|
203
204
|
export const advancedDatasetSearchConnection = async (
|
|
204
205
|
obj,
|
|
205
|
-
{ query, datasetType, datasetStatus, sortBy, after, first = 25 },
|
|
206
|
+
{ query, allDatasets = false, datasetType, datasetStatus, sortBy, after, first = 25 },
|
|
206
207
|
{ user, userInfo },
|
|
207
208
|
) => {
|
|
208
209
|
const searchId = hashObject({
|
|
@@ -216,7 +217,9 @@ export const advancedDatasetSearchConnection = async (
|
|
|
216
217
|
if (sortBy) sort.unshift(sortBy)
|
|
217
218
|
const requestBody = {
|
|
218
219
|
sort,
|
|
219
|
-
query:
|
|
220
|
+
query: allDatasets
|
|
221
|
+
? query
|
|
222
|
+
: await parseQuery(query, datasetType, datasetStatus, user),
|
|
220
223
|
}
|
|
221
224
|
if (after) {
|
|
222
225
|
try {
|
|
@@ -246,6 +249,7 @@ export const advancedDatasetSearch = {
|
|
|
246
249
|
resolve: advancedDatasetSearchConnection,
|
|
247
250
|
args: {
|
|
248
251
|
query: { type: 'JSON!' },
|
|
252
|
+
allDatasets: { type: 'Boolean' },
|
|
249
253
|
datasetType: { type: 'String' },
|
|
250
254
|
datasetStatus: { type: 'String' },
|
|
251
255
|
sortBy: { type: 'JSON' },
|
|
@@ -23,6 +23,7 @@ import { UpdatedFile } from '../utils/file.js'
|
|
|
23
23
|
import { getDatasetWorker } from '../../libs/datalad-service.js'
|
|
24
24
|
import { getDraftHead } from '../../datalad/dataset.js'
|
|
25
25
|
import { getFileName } from '../../datalad/files.js'
|
|
26
|
+
import semver from 'semver'
|
|
26
27
|
|
|
27
28
|
export const dataset = async (obj, { id }, { user, userInfo }) => {
|
|
28
29
|
await checkDatasetRead(id, user, userInfo)
|
|
@@ -41,8 +42,14 @@ export const datasets = (parent, args, { user, userInfo }) => {
|
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
export const snapshotCreationComparison = (
|
|
45
|
-
|
|
45
|
+
export const snapshotCreationComparison = (
|
|
46
|
+
{ created: a, tag: a_tag },
|
|
47
|
+
{ created: b, tag: b_tag },
|
|
48
|
+
) => {
|
|
49
|
+
return (
|
|
50
|
+
new Date(a).getTime() - new Date(b).getTime() ||
|
|
51
|
+
semver.compare(a_tag, b_tag)
|
|
52
|
+
)
|
|
46
53
|
}
|
|
47
54
|
|
|
48
55
|
/**
|
|
@@ -10,9 +10,13 @@ export const summary = async dataset => {
|
|
|
10
10
|
datasetId: dataset.id,
|
|
11
11
|
}).exec()
|
|
12
12
|
)?.toObject()
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
if (datasetSummary) {
|
|
14
|
+
return {
|
|
15
|
+
...datasetSummary,
|
|
16
|
+
primaryModality: datasetSummary?.modalities[0],
|
|
17
|
+
}
|
|
18
|
+
} else {
|
|
19
|
+
return null
|
|
16
20
|
}
|
|
17
21
|
}
|
|
18
22
|
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import passport from 'passport'
|
|
2
2
|
|
|
3
|
-
export const requestAuth =
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
export const requestAuth = (req, res, next) => (
|
|
4
|
+
passport.authenticate('google', {
|
|
5
|
+
scope: [
|
|
6
|
+
'https://www.googleapis.com/auth/userinfo.email',
|
|
7
|
+
'https://www.googleapis.com/auth/userinfo.profile',
|
|
8
|
+
],
|
|
9
|
+
session: false,
|
|
10
|
+
accessType: 'offline',
|
|
11
|
+
prompt: 'consent',
|
|
12
|
+
state: req.query.redirectPath || null
|
|
13
|
+
})(req, res, next)
|
|
14
|
+
)
|
|
12
15
|
|
|
13
16
|
export const authCallback = passport.authenticate('google', {
|
|
14
17
|
failureRedirect: '/',
|
|
@@ -153,10 +153,13 @@ export const authenticate = (req, res, next) => {
|
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
export const authSuccessHandler = (req, res, next) => {
|
|
156
|
+
const redirectPath = req.query.state
|
|
157
|
+
? Buffer.from(req.query.state, 'base64').toString()
|
|
158
|
+
: '/'
|
|
156
159
|
if (req.user) {
|
|
157
160
|
// Set the JWT associated with this login on a cookie
|
|
158
161
|
res.cookie('accessToken', req.user.token, { sameSite: 'Strict' })
|
|
159
|
-
res.redirect(
|
|
162
|
+
res.redirect(redirectPath)
|
|
160
163
|
} else {
|
|
161
164
|
res.status(401)
|
|
162
165
|
}
|