@openneuro/server 4.20.4 → 4.20.6-alpha.2
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,43 +1,43 @@
|
|
|
1
|
-
import { vi } from
|
|
2
|
-
import {
|
|
3
|
-
import createFetchMock from
|
|
1
|
+
import { vi } from "vitest"
|
|
2
|
+
import { allowedImportUrl, importRemoteDataset } from "../importRemoteDataset"
|
|
3
|
+
import createFetchMock from "vitest-fetch-mock"
|
|
4
4
|
|
|
5
|
-
vi.mock(
|
|
6
|
-
vi.mock(
|
|
7
|
-
vi.mock(
|
|
5
|
+
vi.mock("ioredis")
|
|
6
|
+
vi.mock("../../../config")
|
|
7
|
+
vi.mock("../../permissions")
|
|
8
8
|
|
|
9
|
-
describe(
|
|
10
|
-
it(
|
|
9
|
+
describe("importRemoteDataset mutation", () => {
|
|
10
|
+
it("given a user with access, it creates an import record for later processing", () => {
|
|
11
11
|
const fetchMock = createFetchMock(vi)
|
|
12
12
|
fetchMock.doMock()
|
|
13
13
|
fetchMock.mockOnce(JSON.stringify(true))
|
|
14
14
|
importRemoteDataset(
|
|
15
15
|
{},
|
|
16
|
-
{ datasetId:
|
|
17
|
-
{ user:
|
|
16
|
+
{ datasetId: "ds000000", url: "" },
|
|
17
|
+
{ user: "1234", userInfo: { admin: true } },
|
|
18
18
|
)
|
|
19
19
|
})
|
|
20
|
-
describe(
|
|
21
|
-
it(
|
|
20
|
+
describe("allowedImportUrl()", () => {
|
|
21
|
+
it("allows brainlife.io", () => {
|
|
22
22
|
expect(
|
|
23
|
-
allowedImportUrl(
|
|
23
|
+
allowedImportUrl("https://brainlife.io/ezbids/dataset-to-import.zip"),
|
|
24
24
|
).toBe(true)
|
|
25
25
|
})
|
|
26
|
-
it(
|
|
26
|
+
it("allows a test bucket for OpenNeuro use", () => {
|
|
27
27
|
expect(
|
|
28
28
|
allowedImportUrl(
|
|
29
|
-
|
|
29
|
+
"https://openneuro-test-import-bucket.s3.us-west-2.amazonaws.com/ds000003.zip",
|
|
30
30
|
),
|
|
31
31
|
).toBe(true)
|
|
32
32
|
})
|
|
33
|
-
it(
|
|
34
|
-
expect(allowedImportUrl(
|
|
35
|
-
expect(allowedImportUrl(
|
|
36
|
-
expect(allowedImportUrl(
|
|
33
|
+
it("does not allow other URLs", () => {
|
|
34
|
+
expect(allowedImportUrl("https://openneuro.org")).toBe(false)
|
|
35
|
+
expect(allowedImportUrl("iiajsdfoijawe")).toBe(false)
|
|
36
|
+
expect(allowedImportUrl("http://google.com/some-zip-file.zip")).toBe(
|
|
37
37
|
false,
|
|
38
38
|
)
|
|
39
39
|
expect(
|
|
40
|
-
allowedImportUrl(
|
|
40
|
+
allowedImportUrl("http://github.com/brainlife.io/somewhere-else.zip"),
|
|
41
41
|
).toBe(false)
|
|
42
42
|
})
|
|
43
43
|
})
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { vi } from "vitest"
|
|
2
|
+
import { updatePermissions } from "../permissions"
|
|
3
|
+
|
|
4
|
+
vi.mock("ioredis")
|
|
5
|
+
vi.mock("../../permissions", () => ({
|
|
6
|
+
checkDatasetAdmin: async () => Promise.resolve(),
|
|
7
|
+
}))
|
|
8
|
+
|
|
9
|
+
const mockExec = vi.fn()
|
|
10
|
+
|
|
11
|
+
vi.mock("../../../models/user", () => ({
|
|
12
|
+
find: () => ({
|
|
13
|
+
exec: mockExec,
|
|
14
|
+
}),
|
|
15
|
+
}))
|
|
16
|
+
|
|
17
|
+
describe("permissions resolvers", () => {
|
|
18
|
+
describe("updatePermissions()", () => {
|
|
19
|
+
it("throws an error when no users are found", async () => {
|
|
20
|
+
mockExec.mockResolvedValue([])
|
|
21
|
+
let error
|
|
22
|
+
try {
|
|
23
|
+
await updatePermissions(
|
|
24
|
+
{},
|
|
25
|
+
{ datasetId: "ds01234", userEmail: "fake@test.com" },
|
|
26
|
+
{ user: "1234", userInfo: { id: "1234" } },
|
|
27
|
+
)
|
|
28
|
+
} catch (err) {
|
|
29
|
+
error = err
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return expect(error).toBeInstanceOf(Error)
|
|
33
|
+
})
|
|
34
|
+
})
|
|
35
|
+
})
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { vi } from "vitest"
|
|
2
|
+
import { filterLatestSnapshot, matchKnownObjects } from "../snapshots"
|
|
3
|
+
|
|
4
|
+
vi.mock("ioredis")
|
|
5
|
+
vi.mock("../../../config.ts")
|
|
6
|
+
|
|
7
|
+
describe("snapshot resolvers", () => {
|
|
8
|
+
describe("matchKnownObjects()", () => {
|
|
9
|
+
it("should return NDA as a source when given a description containing 10.15154 DOIs", () => {
|
|
10
|
+
expect(
|
|
11
|
+
matchKnownObjects({
|
|
12
|
+
ReferencesAndLinks: [
|
|
13
|
+
"10.18112/openneuro.ds000001.v1.0.0",
|
|
14
|
+
"10.15154/1503209",
|
|
15
|
+
],
|
|
16
|
+
}).sort(),
|
|
17
|
+
).toEqual([
|
|
18
|
+
{
|
|
19
|
+
id: "10.18112/openneuro.ds000001.v1.0.0",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: "10.15154/1503209",
|
|
23
|
+
source: "NDA",
|
|
24
|
+
type: "dataset",
|
|
25
|
+
},
|
|
26
|
+
])
|
|
27
|
+
})
|
|
28
|
+
})
|
|
29
|
+
describe("filterLatestSnapshot()", () => {
|
|
30
|
+
it("returns the latest snapshot", () => {
|
|
31
|
+
const testSnapshots = [
|
|
32
|
+
{
|
|
33
|
+
id: "ds000247:00002",
|
|
34
|
+
created: "2018-07-18T02:27:39.000Z",
|
|
35
|
+
tag: "00002",
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: "ds000247:00001",
|
|
39
|
+
created: "2018-07-18T02:35:37.000Z",
|
|
40
|
+
tag: "00001",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: "ds000247:1.0.0",
|
|
44
|
+
created: "2021-07-05T15:58:18.000Z",
|
|
45
|
+
tag: "1.0.0",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: "ds000247:1.0.1",
|
|
49
|
+
created: "2021-08-25T23:37:53.000Z",
|
|
50
|
+
tag: "1.0.1",
|
|
51
|
+
},
|
|
52
|
+
]
|
|
53
|
+
expect(filterLatestSnapshot(testSnapshots)).toBe("1.0.1")
|
|
54
|
+
})
|
|
55
|
+
it("returns null with no snapshots", () => {
|
|
56
|
+
expect(filterLatestSnapshot([])).toBeNull()
|
|
57
|
+
})
|
|
58
|
+
})
|
|
59
|
+
})
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { vi } from "vitest"
|
|
2
|
+
import { users } from "../user.js"
|
|
3
|
+
|
|
4
|
+
vi.mock("ioredis")
|
|
5
|
+
|
|
6
|
+
describe("user resolvers", () => {
|
|
7
|
+
describe("users()", () => {
|
|
8
|
+
it("throws an error for non-admins", () => {
|
|
9
|
+
expect(
|
|
10
|
+
users(
|
|
11
|
+
null,
|
|
12
|
+
{ id: "3311cfe8-9764-434d-b80e-1b1ee72c686d" },
|
|
13
|
+
{ userInfo: {} },
|
|
14
|
+
),
|
|
15
|
+
).rejects.toEqual(new Error("You must be a site admin to retrieve users"))
|
|
16
|
+
})
|
|
17
|
+
})
|
|
18
|
+
})
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DatasetOrSnapshot,
|
|
3
3
|
getDatasetFromSnapshotId,
|
|
4
|
-
} from
|
|
4
|
+
} from "../../utils/datasetOrSnapshot"
|
|
5
5
|
|
|
6
6
|
interface BrainlifeFindQuery {
|
|
7
7
|
removed: boolean
|
|
@@ -19,7 +19,7 @@ export function brainlifeQuery(dataset: DatasetOrSnapshot): URL {
|
|
|
19
19
|
removed: false,
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
if (
|
|
22
|
+
if ("tag" in dataset) {
|
|
23
23
|
find.path = {
|
|
24
24
|
$regex: `^OpenNeuro/${getDatasetFromSnapshotId(dataset.id)}`,
|
|
25
25
|
}
|
|
@@ -28,8 +28,8 @@ export function brainlifeQuery(dataset: DatasetOrSnapshot): URL {
|
|
|
28
28
|
find.path = { $regex: `^OpenNeuro/${dataset.id}` }
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
const url = new URL(
|
|
32
|
-
url.searchParams.append(
|
|
31
|
+
const url = new URL("https://brainlife.io/api/warehouse/datalad/datasets")
|
|
32
|
+
url.searchParams.append("find", JSON.stringify(find))
|
|
33
33
|
|
|
34
34
|
return url
|
|
35
35
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { redis } from
|
|
2
|
-
import CacheItem from
|
|
3
|
-
import { CacheType } from
|
|
1
|
+
import { redis } from "../../libs/redis.js"
|
|
2
|
+
import CacheItem from "../../cache/item"
|
|
3
|
+
import { CacheType } from "../../cache/types"
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Clear the snapshotDownload cache after exports
|
|
@@ -11,7 +11,7 @@ export async function cacheClear(
|
|
|
11
11
|
{ userInfo }: { userInfo: { admin: boolean } },
|
|
12
12
|
): Promise<boolean> {
|
|
13
13
|
// Check for admin and validate datasetId argument
|
|
14
|
-
if (userInfo?.admin && datasetId.length == 8 && datasetId.startsWith(
|
|
14
|
+
if (userInfo?.admin && datasetId.length == 8 && datasetId.startsWith("ds")) {
|
|
15
15
|
const downloadCache = new CacheItem(redis, CacheType.snapshotDownload, [
|
|
16
16
|
datasetId,
|
|
17
17
|
tag,
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import Comment from
|
|
2
|
-
import notifications from
|
|
3
|
-
import { user } from
|
|
4
|
-
import { checkAdmin } from
|
|
1
|
+
import Comment from "../../models/comment"
|
|
2
|
+
import notifications from "../../libs/notifications"
|
|
3
|
+
import { user } from "./user.js"
|
|
4
|
+
import { checkAdmin } from "../permissions"
|
|
5
5
|
|
|
6
6
|
export const comment = (obj, { id }) => {
|
|
7
7
|
return Comment.findOne({ _id: id }).exec()
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
export const datasetComments = obj => {
|
|
10
|
+
export const datasetComments = (obj) => {
|
|
11
11
|
return Comment.find({ datasetId: obj.id }).exec()
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
export const userComments = obj => {
|
|
15
|
-
return Comment.find({
|
|
14
|
+
export const userComments = (obj) => {
|
|
15
|
+
return Comment.find({ "user._id": obj.id }).exec()
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
const replies = obj => {
|
|
18
|
+
const replies = (obj) => {
|
|
19
19
|
return Comment.find({ parentId: obj._id }).exec()
|
|
20
20
|
}
|
|
21
21
|
|
|
@@ -24,14 +24,14 @@ const replies = obj => {
|
|
|
24
24
|
* @param {*[][]} arr
|
|
25
25
|
* @returns {*[]}
|
|
26
26
|
*/
|
|
27
|
-
export const flatten = arr => [].concat(...arr)
|
|
27
|
+
export const flatten = (arr) => [].concat(...arr)
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
30
|
* returns a flat array of all the dependencies of the given comment
|
|
31
31
|
* @param {import('../../models/comment').CommentDocument} obj
|
|
32
32
|
* @returns {Promise<import('../../models/comment').CommentDocument[]>}
|
|
33
33
|
*/
|
|
34
|
-
const allNestedReplies = async obj => {
|
|
34
|
+
const allNestedReplies = async (obj) => {
|
|
35
35
|
const replies = await Comment.find({ parentId: obj._id }).exec()
|
|
36
36
|
if (!replies.length) {
|
|
37
37
|
return replies
|
|
@@ -51,7 +51,7 @@ export const addComment = (
|
|
|
51
51
|
) => {
|
|
52
52
|
if (!user) {
|
|
53
53
|
return Promise.reject(
|
|
54
|
-
new Error(
|
|
54
|
+
new Error("You must be logged in to write a comment."),
|
|
55
55
|
)
|
|
56
56
|
}
|
|
57
57
|
const newComment = new Comment({
|
|
@@ -60,7 +60,7 @@ export const addComment = (
|
|
|
60
60
|
text,
|
|
61
61
|
user: { _id: user },
|
|
62
62
|
})
|
|
63
|
-
return newComment.save().then(commentInsert => {
|
|
63
|
+
return newComment.save().then((commentInsert) => {
|
|
64
64
|
notifications.commentCreated(commentInsert)
|
|
65
65
|
return commentInsert._id
|
|
66
66
|
})
|
|
@@ -77,7 +77,7 @@ export const editComment = async (
|
|
|
77
77
|
existingComment.text = text
|
|
78
78
|
return existingComment.save().then(() => true)
|
|
79
79
|
} else {
|
|
80
|
-
return Promise.reject(new Error(
|
|
80
|
+
return Promise.reject(new Error("You may only edit your own comments."))
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
|
|
@@ -93,7 +93,7 @@ export const deleteComment = async (
|
|
|
93
93
|
if (deleteChildren) {
|
|
94
94
|
targetComments.push(...(await allNestedReplies(existingComment)))
|
|
95
95
|
}
|
|
96
|
-
const deletedCommentIds = targetComments.map(c => c._id)
|
|
96
|
+
const deletedCommentIds = targetComments.map((c) => c._id)
|
|
97
97
|
return Comment.deleteMany({
|
|
98
98
|
_id: {
|
|
99
99
|
$in: deletedCommentIds,
|
|
@@ -103,9 +103,9 @@ export const deleteComment = async (
|
|
|
103
103
|
|
|
104
104
|
//"5c9bf7e3088cea6fa775c42a"
|
|
105
105
|
const CommentFields = {
|
|
106
|
-
parent: obj => comment(obj, { id: obj.parentId }),
|
|
106
|
+
parent: (obj) => comment(obj, { id: obj.parentId }),
|
|
107
107
|
replies,
|
|
108
|
-
user: obj => user(obj, { id: obj.user._id }),
|
|
108
|
+
user: (obj) => user(obj, { id: obj.user._id }),
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
export default CommentFields
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { elasticClient } from
|
|
2
|
-
import { dataset } from
|
|
3
|
-
import Star from
|
|
4
|
-
import Subscription from
|
|
5
|
-
import Permission from
|
|
6
|
-
import { hashObject } from
|
|
1
|
+
import { elasticClient } from "../../elasticsearch/elastic-client"
|
|
2
|
+
import { dataset } from "./dataset"
|
|
3
|
+
import Star from "../../models/stars"
|
|
4
|
+
import Subscription from "../../models/subscription"
|
|
5
|
+
import Permission from "../../models/permission"
|
|
6
|
+
import { hashObject } from "../../libs/authentication/crypto"
|
|
7
7
|
|
|
8
|
-
const elasticIndex =
|
|
8
|
+
const elasticIndex = "datasets"
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Remove a dataset from the index, used when deleting datasets to clean up
|
|
@@ -13,7 +13,7 @@ const elasticIndex = 'datasets'
|
|
|
13
13
|
* @param {string} id Dataset accession number id
|
|
14
14
|
* @returns {Promise}
|
|
15
15
|
*/
|
|
16
|
-
export const removeDatasetSearchDocument = id =>
|
|
16
|
+
export const removeDatasetSearchDocument = (id) =>
|
|
17
17
|
elasticClient.delete({ id, index: elasticIndex })
|
|
18
18
|
|
|
19
19
|
/**
|
|
@@ -21,16 +21,16 @@ export const removeDatasetSearchDocument = id =>
|
|
|
21
21
|
* @param {Array<*>} sort
|
|
22
22
|
* @returns {string}
|
|
23
23
|
*/
|
|
24
|
-
export const encodeCursor = sort =>
|
|
25
|
-
Buffer.from(JSON.stringify(sort)).toString(
|
|
24
|
+
export const encodeCursor = (sort) =>
|
|
25
|
+
Buffer.from(JSON.stringify(sort)).toString("base64")
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* Accepts a cursor and returns the deserialized elastic search search_after array
|
|
29
29
|
* @param {string} cursor
|
|
30
30
|
* @returns {Array<*>}
|
|
31
31
|
*/
|
|
32
|
-
export const decodeCursor = cursor =>
|
|
33
|
-
JSON.parse(Buffer.from(cursor,
|
|
32
|
+
export const decodeCursor = (cursor) =>
|
|
33
|
+
JSON.parse(Buffer.from(cursor, "base64").toString("utf-8"))
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
36
|
* Return a relay cursor from an elastic search result
|
|
@@ -50,7 +50,7 @@ export const elasticRelayConnection = (
|
|
|
50
50
|
const hasNextPage = Boolean(body.hits.hits[size - 1])
|
|
51
51
|
return {
|
|
52
52
|
id,
|
|
53
|
-
edges: body.hits.hits.map(hit => {
|
|
53
|
+
edges: body.hits.hits.map((hit) => {
|
|
54
54
|
const node = childResolvers.dataset(
|
|
55
55
|
null,
|
|
56
56
|
{ id: hit._source.id },
|
|
@@ -88,7 +88,8 @@ export const datasetSearchConnection = async (
|
|
|
88
88
|
) => {
|
|
89
89
|
const searchId = hashObject({ q })
|
|
90
90
|
const requestBody = {
|
|
91
|
-
sort: [{ _score:
|
|
91
|
+
sort: [{ _score: "asc", id: "desc" }],
|
|
92
|
+
search_after: undefined,
|
|
92
93
|
}
|
|
93
94
|
if (after) {
|
|
94
95
|
try {
|
|
@@ -108,12 +109,12 @@ export const datasetSearchConnection = async (
|
|
|
108
109
|
|
|
109
110
|
export const datasetSearch = {
|
|
110
111
|
search: {
|
|
111
|
-
type:
|
|
112
|
+
type: "DatasetConnection",
|
|
112
113
|
resolve: datasetSearchConnection,
|
|
113
114
|
args: {
|
|
114
|
-
q: { type:
|
|
115
|
-
after: { type:
|
|
116
|
-
first: { type:
|
|
115
|
+
q: { type: "String!" },
|
|
116
|
+
after: { type: "String" },
|
|
117
|
+
first: { type: "Int" },
|
|
117
118
|
},
|
|
118
119
|
},
|
|
119
120
|
}
|
|
@@ -127,15 +128,15 @@ const addClause = (query, type, clause) => {
|
|
|
127
128
|
}
|
|
128
129
|
|
|
129
130
|
const parseQuery = async (query, datasetType, datasetStatus, userId) => {
|
|
130
|
-
if (datasetType ===
|
|
131
|
-
addClause(query,
|
|
131
|
+
if (datasetType === "All Public") {
|
|
132
|
+
addClause(query, "filter", {
|
|
132
133
|
term: {
|
|
133
134
|
public: {
|
|
134
135
|
value: true,
|
|
135
136
|
},
|
|
136
137
|
},
|
|
137
138
|
})
|
|
138
|
-
} else if (datasetType ===
|
|
139
|
+
} else if (datasetType === "Following") {
|
|
139
140
|
const results = await Subscription.find({ userId })
|
|
140
141
|
const followedDatasets = results.map(({ datasetId }) => datasetId)
|
|
141
142
|
const termsClause = {
|
|
@@ -143,8 +144,8 @@ const parseQuery = async (query, datasetType, datasetStatus, userId) => {
|
|
|
143
144
|
id: followedDatasets,
|
|
144
145
|
},
|
|
145
146
|
}
|
|
146
|
-
addClause(query,
|
|
147
|
-
} else if (datasetType ===
|
|
147
|
+
addClause(query, "filter", termsClause)
|
|
148
|
+
} else if (datasetType === "My Bookmarks") {
|
|
148
149
|
const results = await Star.find({ userId })
|
|
149
150
|
const bookmarkedDatasets = results.map(({ datasetId }) => datasetId)
|
|
150
151
|
const termsClause = {
|
|
@@ -152,8 +153,8 @@ const parseQuery = async (query, datasetType, datasetStatus, userId) => {
|
|
|
152
153
|
id: bookmarkedDatasets,
|
|
153
154
|
},
|
|
154
155
|
}
|
|
155
|
-
addClause(query,
|
|
156
|
-
} else if (datasetType ===
|
|
156
|
+
addClause(query, "filter", termsClause)
|
|
157
|
+
} else if (datasetType === "My Datasets") {
|
|
157
158
|
const results = await Permission.find({ userId })
|
|
158
159
|
const bookmarkedDatasets = results.map(({ datasetId }) => datasetId)
|
|
159
160
|
const termsClause = {
|
|
@@ -161,26 +162,26 @@ const parseQuery = async (query, datasetType, datasetStatus, userId) => {
|
|
|
161
162
|
id: bookmarkedDatasets,
|
|
162
163
|
},
|
|
163
164
|
}
|
|
164
|
-
addClause(query,
|
|
165
|
+
addClause(query, "filter", termsClause)
|
|
165
166
|
|
|
166
|
-
if (datasetStatus ===
|
|
167
|
-
addClause(query,
|
|
167
|
+
if (datasetStatus === "Public") {
|
|
168
|
+
addClause(query, "filter", {
|
|
168
169
|
term: {
|
|
169
170
|
public: {
|
|
170
171
|
value: true,
|
|
171
172
|
},
|
|
172
173
|
},
|
|
173
174
|
})
|
|
174
|
-
} else if (datasetStatus ===
|
|
175
|
-
addClause(query,
|
|
175
|
+
} else if (datasetStatus === "Shared with Me") {
|
|
176
|
+
addClause(query, "filter", {
|
|
176
177
|
terms: {
|
|
177
|
-
[
|
|
178
|
+
["permissions.userPermissions.level"]: ["ro", "rw"],
|
|
178
179
|
},
|
|
179
180
|
})
|
|
180
|
-
} else if (datasetStatus ===
|
|
181
|
-
addClause(query,
|
|
181
|
+
} else if (datasetStatus === "Invalid") {
|
|
182
|
+
addClause(query, "filter", {
|
|
182
183
|
term: {
|
|
183
|
-
[
|
|
184
|
+
["draft.issues.severity"]: "error",
|
|
184
185
|
},
|
|
185
186
|
})
|
|
186
187
|
}
|
|
@@ -221,13 +222,14 @@ export const advancedDatasetSearchConnection = async (
|
|
|
221
222
|
sortBy,
|
|
222
223
|
user,
|
|
223
224
|
})
|
|
224
|
-
const sort = [{ _score:
|
|
225
|
+
const sort = [{ _score: "desc" }, { id: "desc" }]
|
|
225
226
|
if (sortBy) sort.unshift(sortBy)
|
|
226
227
|
const requestBody = {
|
|
227
228
|
sort,
|
|
228
229
|
query: allDatasets
|
|
229
230
|
? query
|
|
230
231
|
: await parseQuery(query, datasetType, datasetStatus, user),
|
|
232
|
+
search_after: undefined,
|
|
231
233
|
}
|
|
232
234
|
if (after) {
|
|
233
235
|
try {
|
|
@@ -253,16 +255,16 @@ export const advancedDatasetSearchConnection = async (
|
|
|
253
255
|
|
|
254
256
|
export const advancedDatasetSearch = {
|
|
255
257
|
advancedSearch: {
|
|
256
|
-
type:
|
|
258
|
+
type: "DatasetConnection",
|
|
257
259
|
resolve: advancedDatasetSearchConnection,
|
|
258
260
|
args: {
|
|
259
|
-
query: { type:
|
|
260
|
-
allDatasets: { type:
|
|
261
|
-
datasetType: { type:
|
|
262
|
-
datasetStatus: { type:
|
|
263
|
-
sortBy: { type:
|
|
264
|
-
after: { type:
|
|
265
|
-
first: { type:
|
|
261
|
+
query: { type: "JSON!" },
|
|
262
|
+
allDatasets: { type: "Boolean" },
|
|
263
|
+
datasetType: { type: "String" },
|
|
264
|
+
datasetStatus: { type: "String" },
|
|
265
|
+
sortBy: { type: "JSON" },
|
|
266
|
+
after: { type: "String" },
|
|
267
|
+
first: { type: "Int" },
|
|
266
268
|
},
|
|
267
269
|
},
|
|
268
270
|
}
|