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