@openneuro/server 5.0.0-alpha.0 → 5.1.0

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.
Files changed (98) hide show
  1. package/package.json +8 -5
  2. package/src/app.ts +2 -4
  3. package/src/cache/__tests__/tree.spec.ts +2 -0
  4. package/src/cache/tree.ts +4 -0
  5. package/src/cache/types.ts +1 -0
  6. package/src/datalad/__tests__/contributors.spec.ts +1 -1
  7. package/src/datalad/__tests__/dataRetentionNotifications.spec.ts +11 -11
  8. package/src/datalad/__tests__/files.spec.ts +31 -1
  9. package/src/datalad/__tests__/snapshots.spec.ts +4 -4
  10. package/src/datalad/contributors.ts +2 -2
  11. package/src/datalad/dataRetentionNotifications.ts +5 -5
  12. package/src/datalad/dataset.ts +9 -5
  13. package/src/datalad/description.ts +2 -2
  14. package/src/datalad/draft.ts +8 -3
  15. package/src/datalad/files.ts +71 -12
  16. package/src/datalad/readme.ts +2 -2
  17. package/src/datalad/snapshots.ts +19 -14
  18. package/src/elasticsearch/elastic-client.ts +11 -6
  19. package/src/elasticsearch/reindex-dataset.ts +8 -4
  20. package/src/graphql/__tests__/comment.spec.ts +3 -2
  21. package/src/graphql/__tests__/schema.spec.ts +28 -0
  22. package/src/graphql/builder.ts +42 -0
  23. package/src/graphql/resolvers/__tests__/dataset.spec.ts +6 -119
  24. package/src/graphql/resolvers/__tests__/importRemoteDataset.spec.ts +2 -1
  25. package/src/graphql/resolvers/__tests__/permssions.spec.ts +3 -2
  26. package/src/graphql/resolvers/__tests__/user.spec.ts +39 -11
  27. package/src/graphql/resolvers/brainInitiative.ts +4 -3
  28. package/src/graphql/resolvers/cache.ts +7 -6
  29. package/src/graphql/resolvers/comment.ts +35 -19
  30. package/src/graphql/resolvers/dataset-search.ts +7 -6
  31. package/src/graphql/resolvers/dataset.ts +77 -45
  32. package/src/graphql/resolvers/datasetEvents.ts +18 -16
  33. package/src/graphql/resolvers/description.ts +2 -1
  34. package/src/graphql/resolvers/draft.ts +14 -3
  35. package/src/graphql/resolvers/fileCheck.ts +5 -4
  36. package/src/graphql/resolvers/flaggedFiles.ts +2 -1
  37. package/src/graphql/resolvers/follow.ts +2 -1
  38. package/src/graphql/resolvers/git.ts +2 -1
  39. package/src/graphql/resolvers/gitEvents.ts +2 -1
  40. package/src/graphql/resolvers/history.ts +3 -1
  41. package/src/graphql/resolvers/holdDeletion.ts +1 -1
  42. package/src/graphql/resolvers/importRemoteDataset.ts +3 -2
  43. package/src/graphql/resolvers/issues.ts +2 -1
  44. package/src/graphql/resolvers/metadata.ts +3 -2
  45. package/src/graphql/resolvers/permissions.ts +26 -6
  46. package/src/graphql/resolvers/publish.ts +2 -1
  47. package/src/graphql/resolvers/readme.ts +2 -1
  48. package/src/graphql/resolvers/reexporter.ts +2 -1
  49. package/src/graphql/resolvers/relation.ts +3 -2
  50. package/src/graphql/resolvers/reset.ts +2 -1
  51. package/src/graphql/resolvers/reviewer.ts +14 -6
  52. package/src/graphql/resolvers/snapshots.ts +42 -10
  53. package/src/graphql/resolvers/stars.ts +2 -1
  54. package/src/graphql/resolvers/upload.ts +3 -2
  55. package/src/graphql/resolvers/user.ts +44 -32
  56. package/src/graphql/resolvers/validation.ts +6 -5
  57. package/src/graphql/resolvers/worker.ts +2 -1
  58. package/src/graphql/schema/analytics.ts +12 -0
  59. package/src/graphql/schema/comment.ts +30 -0
  60. package/src/graphql/schema/dataset-events.ts +91 -0
  61. package/src/graphql/schema/dataset-search.ts +32 -0
  62. package/src/graphql/schema/dataset.ts +167 -0
  63. package/src/graphql/schema/description.ts +44 -0
  64. package/src/graphql/schema/draft.ts +80 -0
  65. package/src/graphql/schema/enums.ts +55 -0
  66. package/src/graphql/schema/files.ts +44 -0
  67. package/src/graphql/schema/inputs.ts +231 -0
  68. package/src/graphql/schema/metadata.ts +86 -0
  69. package/src/graphql/schema/misc.ts +154 -0
  70. package/src/graphql/schema/mutation.ts +549 -0
  71. package/src/graphql/schema/pagination.ts +12 -0
  72. package/src/graphql/schema/permissions.ts +21 -0
  73. package/src/graphql/schema/query.ts +119 -0
  74. package/src/graphql/schema/refs.ts +23 -0
  75. package/src/graphql/schema/reviewer.ts +11 -0
  76. package/src/graphql/schema/scalars.ts +9 -0
  77. package/src/graphql/schema/snapshot.ts +111 -0
  78. package/src/graphql/schema/upload.ts +13 -0
  79. package/src/graphql/schema/user.ts +61 -0
  80. package/src/graphql/schema/validation.ts +70 -0
  81. package/src/graphql/schema/worker.ts +16 -0
  82. package/src/graphql/schema.ts +29 -1114
  83. package/src/handlers/subscriptions.ts +1 -1
  84. package/src/libs/apikey.ts +1 -1
  85. package/src/libs/authentication/crypto.ts +14 -9
  86. package/src/libs/notifications.ts +1 -1
  87. package/src/libs/presign.ts +32 -20
  88. package/src/libs/redis.ts +12 -2
  89. package/src/models/comment.ts +2 -4
  90. package/src/models/counter.ts +2 -2
  91. package/src/models/ingestDataset.ts +1 -2
  92. package/src/models/notification.ts +0 -2
  93. package/src/models/subscription.ts +0 -1
  94. package/src/models/user.ts +1 -2
  95. package/src/models/userMigration.ts +1 -1
  96. package/src/models/userNotificationStatus.ts +0 -1
  97. package/src/utils/__tests__/snapshots.spec.ts +120 -0
  98. package/src/utils/snapshots.ts +12 -0
@@ -0,0 +1,549 @@
1
+ import { builder } from "../builder"
2
+ import { DatasetEventRef, DatasetRef, SnapshotRef, UserRef } from "./refs"
3
+ import { DatasetPermissions } from "./permissions"
4
+ import { Description, UpdateContributorsPayload } from "./description"
5
+ import { Summary } from "./metadata"
6
+ import { Metadata } from "./metadata"
7
+ import { UploadMetadata } from "./upload"
8
+ import { FileCheck, RepoMetadata, UserNotificationStatus } from "./misc"
9
+ import { DatasetReviewer } from "./reviewer"
10
+ import { WorkerTask } from "./worker"
11
+ import { FollowDatasetResponse, StarDatasetResponse } from "./misc"
12
+ import {
13
+ AnalyticTypes,
14
+ NotificationStatusType,
15
+ RelatedObjectKind,
16
+ RelatedObjectRelation,
17
+ ResponseStatusType,
18
+ } from "./enums"
19
+ import {
20
+ AnnexFsckInput,
21
+ ContributorInput,
22
+ DeleteFile,
23
+ MetadataInput,
24
+ SummaryInput,
25
+ ValidatorInput,
26
+ } from "./inputs"
27
+
28
+ import Mutation from '../resolvers/mutation'
29
+
30
+ builder.mutationType({
31
+ fields: (t) => ({
32
+ createDataset: t.field({
33
+ type: DatasetRef,
34
+ args: {
35
+ affirmedDefaced: t.arg.boolean(),
36
+ affirmedConsent: t.arg.boolean(),
37
+ },
38
+ resolve: (root, args, ctx) =>
39
+ Mutation.createDataset(root, args as never, ctx),
40
+ }),
41
+ deleteDataset: t.boolean({
42
+ args: {
43
+ id: t.arg.id({ required: true }),
44
+ reason: t.arg.string(),
45
+ redirect: t.arg.string(),
46
+ },
47
+ resolve: (root, args, ctx) =>
48
+ Mutation.deleteDataset(root, args as never, ctx),
49
+ }),
50
+ createSnapshot: t.field({
51
+ type: SnapshotRef,
52
+ args: {
53
+ datasetId: t.arg.id({ required: true }),
54
+ tag: t.arg.string({ required: true }),
55
+ changes: t.arg.stringList(),
56
+ },
57
+ resolve: (root, args, ctx) =>
58
+ Mutation.createSnapshot(root, args as never, ctx),
59
+ }),
60
+ deleteSnapshot: t.boolean({
61
+ nullable: false,
62
+ args: {
63
+ datasetId: t.arg.id({ required: true }),
64
+ tag: t.arg.string({ required: true }),
65
+ },
66
+ resolve: (root, args, ctx) =>
67
+ Mutation.deleteSnapshot(root, args as never, ctx),
68
+ }),
69
+ removeAnnexObject: t.boolean({
70
+ args: {
71
+ datasetId: t.arg.id({ required: true }),
72
+ snapshot: t.arg.string({ required: true }),
73
+ annexKey: t.arg.string({ required: true }),
74
+ path: t.arg.string(),
75
+ filename: t.arg.string(),
76
+ },
77
+ resolve: (root, args, ctx) =>
78
+ Mutation.removeAnnexObject(root, args as never, ctx),
79
+ }),
80
+ flagAnnexObject: t.boolean({
81
+ args: {
82
+ datasetId: t.arg.id({ required: true }),
83
+ snapshot: t.arg.string({ required: true }),
84
+ filepath: t.arg.string({ required: true }),
85
+ annexKey: t.arg.string({ required: true }),
86
+ },
87
+ resolve: (root, args, ctx) =>
88
+ Mutation.flagAnnexObject(root, args as never, ctx),
89
+ }),
90
+ deleteFiles: t.boolean({
91
+ args: {
92
+ datasetId: t.arg.id({ required: true }),
93
+ files: t.arg({ type: [DeleteFile] }),
94
+ },
95
+ resolve: (root, args, ctx) =>
96
+ Mutation.deleteFiles(root, args as never, ctx),
97
+ }),
98
+ updatePublic: t.boolean({
99
+ nullable: false,
100
+ args: {
101
+ datasetId: t.arg.id({ required: true }),
102
+ publicFlag: t.arg.boolean({ required: true }),
103
+ },
104
+ resolve: (root, args, ctx) =>
105
+ Mutation.updatePublic(root, args as never, ctx) as never,
106
+ }),
107
+ updateSummary: t.field({
108
+ type: Summary,
109
+ args: {
110
+ summary: t.arg({ type: SummaryInput, required: true }),
111
+ },
112
+ resolve: (root, args) => Mutation.updateSummary(root, args as never),
113
+ }),
114
+ updateValidation: t.boolean({
115
+ args: {
116
+ validation: t.arg({ type: ValidatorInput, required: true }),
117
+ },
118
+ resolve: (root, args) => Mutation.updateValidation(root, args as never),
119
+ }),
120
+ updatePermissions: t.field({
121
+ type: DatasetPermissions,
122
+ args: {
123
+ datasetId: t.arg.id({ required: true }),
124
+ userEmail: t.arg.string({ required: true }),
125
+ level: t.arg.string({ required: true }),
126
+ },
127
+ resolve: (root, args, ctx) =>
128
+ Mutation.updatePermissions(root, args as never, ctx),
129
+ }),
130
+ updateOrcidPermissions: t.field({
131
+ type: DatasetPermissions,
132
+ args: {
133
+ datasetId: t.arg.id({ required: true }),
134
+ userOrcid: t.arg.string({ required: true }),
135
+ level: t.arg.string({ required: true }),
136
+ },
137
+ resolve: (root, args, ctx) =>
138
+ Mutation.updateOrcidPermissions(root, args as never, ctx),
139
+ }),
140
+ removePermissions: t.boolean({
141
+ args: {
142
+ datasetId: t.arg.id({ required: true }),
143
+ userId: t.arg.string({ required: true }),
144
+ },
145
+ resolve: (root, args) => Mutation.removePermissions(root, args as never) as never,
146
+ }),
147
+ removeUser: t.boolean({
148
+ args: {
149
+ id: t.arg.id({ required: true }),
150
+ },
151
+ resolve: (root, args, ctx) =>
152
+ Mutation.removeUser(root, args as never, ctx) as never,
153
+ }),
154
+ setAdmin: t.field({
155
+ type: UserRef,
156
+ args: {
157
+ id: t.arg.id({ required: true }),
158
+ admin: t.arg.boolean({ required: true }),
159
+ },
160
+ resolve: (root, args, ctx) =>
161
+ Mutation.setAdmin(root, args as never, ctx) as never,
162
+ }),
163
+ setBlocked: t.field({
164
+ type: UserRef,
165
+ args: {
166
+ id: t.arg.id({ required: true }),
167
+ blocked: t.arg.boolean({ required: true }),
168
+ },
169
+ resolve: (root, args, ctx) =>
170
+ Mutation.setBlocked(root, args as never, ctx) as never,
171
+ }),
172
+ updateUser: t.field({
173
+ type: UserRef,
174
+ args: {
175
+ id: t.arg.id({ required: true }),
176
+ location: t.arg.string(),
177
+ institution: t.arg.string(),
178
+ links: t.arg.stringList(),
179
+ orcidConsent: t.arg.boolean(),
180
+ },
181
+ resolve: (root, args, ctx) =>
182
+ Mutation.updateUser(root, args as never, ctx),
183
+ }),
184
+ trackAnalytics: t.boolean({
185
+ args: {
186
+ datasetId: t.arg.id({ required: true }),
187
+ tag: t.arg.string(),
188
+ type: t.arg({ type: AnalyticTypes }),
189
+ },
190
+ resolve: (root, args) => Mutation.trackAnalytics(root, args as never),
191
+ }),
192
+ followDataset: t.field({
193
+ type: FollowDatasetResponse,
194
+ args: {
195
+ datasetId: t.arg.id({ required: true }),
196
+ },
197
+ resolve: (root, args, ctx) =>
198
+ Mutation.followDataset(root, args as never, ctx),
199
+ }),
200
+ starDataset: t.field({
201
+ type: StarDatasetResponse,
202
+ args: {
203
+ datasetId: t.arg.id({ required: true }),
204
+ },
205
+ resolve: (root, args, ctx) =>
206
+ Mutation.starDataset(root, args as never, ctx),
207
+ }),
208
+ publishDataset: t.boolean({
209
+ args: {
210
+ datasetId: t.arg.id({ required: true }),
211
+ },
212
+ resolve: (root, args, ctx) =>
213
+ Mutation.publishDataset(root, args as never, ctx),
214
+ }),
215
+ updateDescription: t.field({
216
+ type: Description,
217
+ args: {
218
+ datasetId: t.arg.id({ required: true }),
219
+ field: t.arg.string({ required: true }),
220
+ value: t.arg.string({ required: true }),
221
+ },
222
+ resolve: (root, args, ctx) =>
223
+ Mutation.updateDescription(root, args as never, ctx),
224
+ }),
225
+ updateDescriptionList: t.field({
226
+ type: Description,
227
+ args: {
228
+ datasetId: t.arg.id({ required: true }),
229
+ field: t.arg.string({ required: true }),
230
+ value: t.arg.stringList(),
231
+ },
232
+ resolve: (root, args, ctx) =>
233
+ Mutation.updateDescriptionList(root, args as never, ctx),
234
+ }),
235
+ updateReadme: t.boolean({
236
+ args: {
237
+ datasetId: t.arg.id({ required: true }),
238
+ value: t.arg.string({ required: true }),
239
+ },
240
+ resolve: (root, args, ctx) =>
241
+ Mutation.updateReadme(root, args as never, ctx),
242
+ }),
243
+ addComment: t.id({
244
+ args: {
245
+ datasetId: t.arg.id({ required: true }),
246
+ parentId: t.arg.id(),
247
+ comment: t.arg.string({ required: true }),
248
+ },
249
+ resolve: (root, args, ctx) =>
250
+ Mutation.addComment(root, args as never, ctx),
251
+ }),
252
+ editComment: t.boolean({
253
+ args: {
254
+ commentId: t.arg.id({ required: true }),
255
+ comment: t.arg.string({ required: true }),
256
+ },
257
+ resolve: (root, args, ctx) =>
258
+ Mutation.editComment(root, args as never, ctx),
259
+ }),
260
+ deleteComment: t.stringList({
261
+ nullable: { list: true, items: true },
262
+ args: {
263
+ commentId: t.arg.id({ required: true }),
264
+ deleteChildren: t.arg.boolean(),
265
+ },
266
+ resolve: (root, args, ctx) =>
267
+ Mutation.deleteComment(root, args as never, ctx),
268
+ }),
269
+ subscribeToNewsletter: t.boolean({
270
+ args: {
271
+ email: t.arg.string({ required: true }),
272
+ },
273
+ resolve: (root, args) =>
274
+ Mutation.subscribeToNewsletter(root, args as never),
275
+ }),
276
+ addMetadata: t.field({
277
+ type: Metadata,
278
+ args: {
279
+ datasetId: t.arg.id({ required: true }),
280
+ metadata: t.arg({ type: MetadataInput, required: true }),
281
+ },
282
+ resolve: (root, args) => Mutation.addMetadata(root, args as never),
283
+ }),
284
+ prepareUpload: t.field({
285
+ type: UploadMetadata,
286
+ args: {
287
+ datasetId: t.arg.id({ required: true }),
288
+ uploadId: t.arg.id({ required: true }),
289
+ },
290
+ resolve: (root, args, ctx) =>
291
+ Mutation.prepareUpload(root, args as never, ctx) as never,
292
+ }),
293
+ finishUpload: t.boolean({
294
+ args: {
295
+ uploadId: t.arg.id({ required: true }),
296
+ },
297
+ resolve: (root, args, ctx) =>
298
+ Mutation.finishUpload(root, args as never, ctx),
299
+ }),
300
+ cacheClear: t.boolean({
301
+ args: {
302
+ datasetId: t.arg.id({ required: true }),
303
+ },
304
+ resolve: (root, args, ctx) =>
305
+ Mutation.cacheClear(root as never, args as never, ctx),
306
+ }),
307
+ fsckDataset: t.boolean({
308
+ args: {
309
+ datasetId: t.arg.id({ required: true }),
310
+ },
311
+ resolve: Mutation.fsckDataset,
312
+ }),
313
+ holdDeletion: t.boolean({
314
+ args: {
315
+ datasetId: t.arg.id({ required: true }),
316
+ hold: t.arg.boolean({ required: true }),
317
+ },
318
+ resolve: Mutation.holdDeletion,
319
+ }),
320
+ revalidate: t.boolean({
321
+ args: {
322
+ datasetId: t.arg.id({ required: true }),
323
+ ref: t.arg.string({ required: true }),
324
+ },
325
+ resolve: (root, args, ctx) =>
326
+ Mutation.revalidate(root, args as never, ctx),
327
+ }),
328
+ prepareRepoAccess: t.field({
329
+ type: RepoMetadata,
330
+ args: {
331
+ datasetId: t.arg.id({ required: true }),
332
+ },
333
+ resolve: (root, args, ctx) =>
334
+ Mutation.prepareRepoAccess(root as never, args as never, ctx),
335
+ }),
336
+ reexportRemotes: t.boolean({
337
+ args: {
338
+ datasetId: t.arg.id({ required: true }),
339
+ },
340
+ resolve: (root, args, ctx) =>
341
+ Mutation.reexportRemotes(root, args as never, ctx),
342
+ }),
343
+ resetDraft: t.boolean({
344
+ args: {
345
+ datasetId: t.arg.id({ required: true }),
346
+ ref: t.arg.string({ required: true }),
347
+ },
348
+ resolve: (root, args, ctx) =>
349
+ Mutation.resetDraft(root, args as never, ctx),
350
+ }),
351
+ deprecateSnapshot: t.field({
352
+ type: SnapshotRef,
353
+ args: {
354
+ datasetId: t.arg.id({ required: true }),
355
+ tag: t.arg.string({ required: true }),
356
+ reason: t.arg.string({ required: true }),
357
+ },
358
+ resolve: (root, args, ctx) =>
359
+ Mutation.deprecateSnapshot(root, args as never, ctx) as never,
360
+ }),
361
+ undoDeprecateSnapshot: t.field({
362
+ type: SnapshotRef,
363
+ args: {
364
+ datasetId: t.arg.id({ required: true }),
365
+ tag: t.arg.string({ required: true }),
366
+ },
367
+ resolve: (root, args, ctx) =>
368
+ Mutation.undoDeprecateSnapshot(root, args as never, ctx) as never,
369
+ }),
370
+ createReviewer: t.field({
371
+ type: DatasetReviewer,
372
+ args: {
373
+ datasetId: t.arg.id({ required: true }),
374
+ },
375
+ resolve: (root, args, ctx) =>
376
+ Mutation.createReviewer(root, args as never, ctx),
377
+ }),
378
+ deleteReviewer: t.field({
379
+ type: DatasetReviewer,
380
+ args: {
381
+ datasetId: t.arg.id({ required: true }),
382
+ id: t.arg.id({ required: true }),
383
+ },
384
+ resolve: (root, args, ctx) =>
385
+ Mutation.deleteReviewer(root, args as never, ctx),
386
+ }),
387
+ createRelation: t.field({
388
+ type: DatasetRef,
389
+ args: {
390
+ datasetId: t.arg.id({ required: true }),
391
+ doi: t.arg.string({ required: true }),
392
+ relation: t.arg({ type: RelatedObjectRelation, required: true }),
393
+ kind: t.arg({ type: RelatedObjectKind, required: true }),
394
+ description: t.arg.string(),
395
+ },
396
+ resolve: (root, args, ctx) =>
397
+ Mutation.createRelation(root, args as never, ctx),
398
+ }),
399
+ deleteRelation: t.field({
400
+ type: DatasetRef,
401
+ args: {
402
+ datasetId: t.arg.id({ required: true }),
403
+ doi: t.arg.string({ required: true }),
404
+ },
405
+ resolve: (root, args, ctx) =>
406
+ Mutation.deleteRelation(root, args as never, ctx),
407
+ }),
408
+ importRemoteDataset: t.id({
409
+ args: {
410
+ datasetId: t.arg.id({ required: true }),
411
+ url: t.arg.string({ required: true }),
412
+ },
413
+ resolve: (root, args, ctx) =>
414
+ Mutation.importRemoteDataset(
415
+ root as never,
416
+ args as never,
417
+ ctx,
418
+ ),
419
+ }),
420
+ finishImportRemoteDataset: t.boolean({
421
+ args: {
422
+ id: t.arg.id({ required: true }),
423
+ success: t.arg.boolean({ required: true }),
424
+ message: t.arg.string(),
425
+ },
426
+ resolve: (root, args, ctx) =>
427
+ Mutation.finishImportRemoteDataset(
428
+ root as never,
429
+ args as never,
430
+ ctx,
431
+ ),
432
+ }),
433
+ saveAdminNote: t.field({
434
+ type: DatasetEventRef,
435
+ args: {
436
+ id: t.arg.id(),
437
+ datasetId: t.arg.id({ required: true }),
438
+ note: t.arg.string({ required: true }),
439
+ },
440
+ resolve: (root, args, ctx) =>
441
+ Mutation.saveAdminNote(root, args as never, ctx),
442
+ }),
443
+ createGitEvent: t.field({
444
+ type: DatasetEventRef,
445
+ args: {
446
+ datasetId: t.arg.id({ required: true }),
447
+ commit: t.arg.string({ required: true }),
448
+ reference: t.arg.string({ required: true }),
449
+ },
450
+ resolve: (root, args, ctx) =>
451
+ Mutation.createGitEvent(root, args as never, ctx),
452
+ }),
453
+ createContributorRequestEvent: t.field({
454
+ type: DatasetEventRef,
455
+ args: {
456
+ datasetId: t.arg.id({ required: true }),
457
+ },
458
+ resolve: (root, args, ctx) =>
459
+ Mutation.createContributorRequestEvent(
460
+ root,
461
+ args as never,
462
+ ctx,
463
+ ),
464
+ }),
465
+ processContributorRequest: t.field({
466
+ type: DatasetEventRef,
467
+ args: {
468
+ datasetId: t.arg.id({ required: true }),
469
+ targetUserId: t.arg.id({ required: true }),
470
+ requestId: t.arg.id({ required: true }),
471
+ resolutionStatus: t.arg({ type: ResponseStatusType, required: true }),
472
+ reason: t.arg.string(),
473
+ },
474
+ resolve: (root, args, ctx) =>
475
+ Mutation.processContributorRequest(root, args as never, ctx),
476
+ }),
477
+ updateFileCheck: t.field({
478
+ type: FileCheck,
479
+ args: {
480
+ datasetId: t.arg.id({ required: true }),
481
+ hexsha: t.arg.string({ required: true }),
482
+ refs: t.arg.stringList({ required: true }),
483
+ annexFsck: t.arg({ type: [AnnexFsckInput], required: true }),
484
+ remote: t.arg.string(),
485
+ },
486
+ resolve: (root, args, ctx) =>
487
+ Mutation.updateFileCheck(root, args as never, ctx),
488
+ }),
489
+ updateEventStatus: t.field({
490
+ type: UserNotificationStatus,
491
+ args: {
492
+ eventId: t.arg.id({ required: true }),
493
+ status: t.arg({ type: NotificationStatusType, required: true }),
494
+ },
495
+ resolve: (root, args, ctx) =>
496
+ Mutation.updateEventStatus(root, args as never, ctx),
497
+ }),
498
+ updateContributors: t.field({
499
+ type: UpdateContributorsPayload,
500
+ nullable: false,
501
+ args: {
502
+ datasetId: t.arg.string({ required: true }),
503
+ newContributors: t.arg({ type: [ContributorInput], required: true }),
504
+ },
505
+ resolve: (root, args, ctx) =>
506
+ Mutation.updateContributors(root as never, args as never, ctx) as never,
507
+ }),
508
+ createContributorCitationEvent: t.field({
509
+ type: DatasetEventRef,
510
+ args: {
511
+ datasetId: t.arg.id({ required: true }),
512
+ targetUserId: t.arg.id({ required: true }),
513
+ contributorData: t.arg({ type: ContributorInput, required: true }),
514
+ },
515
+ resolve: (root, args, ctx) =>
516
+ Mutation.createContributorCitationEvent(
517
+ root,
518
+ args as never,
519
+ ctx,
520
+ ),
521
+ }),
522
+ processContributorCitation: t.field({
523
+ type: DatasetEventRef,
524
+ args: {
525
+ eventId: t.arg.id({ required: true }),
526
+ status: t.arg({ type: ResponseStatusType, required: true }),
527
+ },
528
+ resolve: (root, args, ctx) =>
529
+ Mutation.processContributorCitation(root, args as never, ctx),
530
+ }),
531
+ updateWorkerTask: t.field({
532
+ type: WorkerTask,
533
+ args: {
534
+ id: t.arg.id({ required: true }),
535
+ args: t.arg({ type: "JSON" }),
536
+ kwargs: t.arg({ type: "JSON" }),
537
+ taskName: t.arg.string(),
538
+ worker: t.arg.string(),
539
+ queuedAt: t.arg({ type: "DateTime" }),
540
+ startedAt: t.arg({ type: "DateTime" }),
541
+ finishedAt: t.arg({ type: "DateTime" }),
542
+ error: t.arg.string(),
543
+ executionTime: t.arg.int(),
544
+ },
545
+ resolve: (root, args, ctx) =>
546
+ Mutation.updateWorkerTask(root, args as never, ctx),
547
+ }),
548
+ }),
549
+ })
@@ -0,0 +1,12 @@
1
+ import { builder } from "../builder"
2
+
3
+ export const PageInfo = builder.simpleObject("PageInfo", {
4
+ description: "Information for pagination in a connection.",
5
+ fields: (t) => ({
6
+ hasNextPage: t.boolean({ nullable: false }),
7
+ hasPreviousPage: t.boolean({ nullable: false }),
8
+ startCursor: t.string(),
9
+ endCursor: t.string(),
10
+ count: t.int(),
11
+ }),
12
+ })
@@ -0,0 +1,21 @@
1
+ import { builder } from "../builder"
2
+ import { UserRef } from "./refs"
3
+
4
+ export const Permission = builder.simpleObject("Permission", {
5
+ fields: (t) => ({
6
+ datasetId: t.id({ nullable: false }),
7
+ userId: t.string({ nullable: false }),
8
+ level: t.string({ nullable: false }),
9
+ user: t.field({ type: UserRef }),
10
+ }),
11
+ })
12
+
13
+ export const DatasetPermissions = builder.simpleObject("DatasetPermissions", {
14
+ fields: (t) => ({
15
+ id: t.id({ nullable: false }),
16
+ userPermissions: t.field({
17
+ type: [Permission],
18
+ nullable: { list: true, items: true },
19
+ }),
20
+ }),
21
+ })
@@ -0,0 +1,119 @@
1
+ import { builder } from "../builder"
2
+ import { DatasetConnection } from "./dataset"
3
+ import { DatasetRef, SnapshotRef, UserRef } from "./refs"
4
+ import { UserList } from "./user"
5
+ import { FlaggedFile } from "./misc"
6
+ import { Metadata } from "./metadata"
7
+ import { DatasetFilter, DatasetSort, UserSortInput } from "./inputs"
8
+ import Query from "../resolvers/query"
9
+
10
+ builder.queryType({
11
+ fields: (t) => ({
12
+ dataset: t.field({
13
+ type: DatasetRef,
14
+ args: {
15
+ id: t.arg.id({ required: true }),
16
+ },
17
+ resolve: (root, args, ctx) =>
18
+ Query.dataset(root, args as never, ctx),
19
+ }),
20
+ datasets: t.field({
21
+ type: DatasetConnection,
22
+ args: {
23
+ first: t.arg.int({
24
+ defaultValue: 25,
25
+ description: "Limit results, default 25, max 100",
26
+ }),
27
+ after: t.arg.string({
28
+ description: "Cursor key used to fetch later results",
29
+ }),
30
+ before: t.arg.string({
31
+ description: "Cursor key used to fetch earlier results",
32
+ }),
33
+ orderBy: t.arg({
34
+ type: DatasetSort,
35
+ defaultValue: { created: "ascending" },
36
+ description: "Sorting fields",
37
+ }),
38
+ filterBy: t.arg({
39
+ type: DatasetFilter,
40
+ defaultValue: {},
41
+ description: "Filtering fields",
42
+ }),
43
+ myDatasets: t.arg.boolean({
44
+ description:
45
+ "Query user's datasets only - excludes public datasets from other filters",
46
+ }),
47
+ modality: t.arg.string({
48
+ description: "Query datasets of a specific modality",
49
+ }),
50
+ },
51
+ resolve: (root, args, ctx) =>
52
+ Query.datasets(root, args as never, ctx),
53
+ }),
54
+ user: t.field({
55
+ type: UserRef,
56
+ args: {
57
+ id: t.arg.id({ required: true }),
58
+ },
59
+ resolve: (root, args, ctx) =>
60
+ Query.user(root, args as never, ctx),
61
+ }),
62
+ users: t.field({
63
+ type: UserList,
64
+ nullable: false,
65
+ args: {
66
+ orderBy: t.arg({ type: [UserSortInput] }),
67
+ isAdmin: t.arg.boolean(),
68
+ isBlocked: t.arg.boolean(),
69
+ search: t.arg.string(),
70
+ limit: t.arg.int(),
71
+ offset: t.arg.int(),
72
+ },
73
+ resolve: (root, args, ctx) =>
74
+ Query.users(root, args as never, ctx) as never,
75
+ }),
76
+ participantCount: t.int({
77
+ directives: { cacheControl: { maxAge: 3600 } },
78
+ args: {
79
+ modality: t.arg.string(),
80
+ },
81
+ resolve: (root, args) => Query.participantCount(root, args as never),
82
+ }),
83
+ snapshot: t.field({
84
+ type: SnapshotRef,
85
+ args: {
86
+ datasetId: t.arg.id({ required: true }),
87
+ tag: t.arg.string({ required: true }),
88
+ },
89
+ resolve: (root, args, ctx) =>
90
+ Query.snapshot(root, args as never, ctx),
91
+ }),
92
+ flaggedFiles: t.field({
93
+ type: [FlaggedFile],
94
+ nullable: { list: true, items: true },
95
+ args: {
96
+ flagged: t.arg.boolean({
97
+ defaultValue: true,
98
+ description: "Get files that have been flagged, default true.",
99
+ }),
100
+ deleted: t.arg.boolean({
101
+ defaultValue: false,
102
+ description:
103
+ "Get files that have already been deleted, default false.",
104
+ }),
105
+ },
106
+ resolve: (root, args, ctx) =>
107
+ Query.flaggedFiles(root, args as never, ctx) as never,
108
+ }),
109
+ publicMetadata: t.field({
110
+ type: [Metadata],
111
+ nullable: { list: true, items: true },
112
+ directives: { cacheControl: { maxAge: 86400 } },
113
+ resolve: (root) => Query.publicMetadata(root),
114
+ }),
115
+ orcidConsent: t.boolean({
116
+ resolve: (_root, _args, ctx) => ctx.userInfo?.orcidConsent ?? null,
117
+ }),
118
+ }),
119
+ })