@openneuro/server 4.20.5 → 4.20.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 -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,22 +1,21 @@
|
|
|
1
1
|
/*eslint no-console: ["error", { allow: ["log"] }] */
|
|
2
|
-
import config from
|
|
3
|
-
import { send as emailSend } from
|
|
4
|
-
import request from
|
|
5
|
-
import User from
|
|
6
|
-
import Subscription from
|
|
7
|
-
import { format } from
|
|
8
|
-
import url from
|
|
9
|
-
import
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import { datasetImportFailed } from '../libs/email/templates/dataset-import-failed'
|
|
2
|
+
import config from "../config"
|
|
3
|
+
import { send as emailSend } from "./email"
|
|
4
|
+
import request from "superagent"
|
|
5
|
+
import User from "../models/user"
|
|
6
|
+
import Subscription from "../models/subscription"
|
|
7
|
+
import { format } from "date-fns"
|
|
8
|
+
import url from "url"
|
|
9
|
+
import { convertFromRaw, EditorState } from "draft-js"
|
|
10
|
+
import { stateToHTML } from "draft-js-export-html"
|
|
11
|
+
import { getDatasetWorker } from "./datalad-service"
|
|
12
|
+
import { commentCreated } from "./email/templates/comment-created"
|
|
13
|
+
import { datasetDeleted } from "./email/templates/dataset-deleted"
|
|
14
|
+
import { ownerUnsubscribed } from "./email/templates/owner-unsubscribed"
|
|
15
|
+
import { snapshotCreated } from "./email/templates/snapshot-created"
|
|
16
|
+
import { snapshotReminder } from "./email/templates/snapshot-reminder"
|
|
17
|
+
import { datasetImportEmail } from "./email/templates/dataset-imported"
|
|
18
|
+
import { datasetImportFailed } from "./email/templates/dataset-import-failed"
|
|
20
19
|
|
|
21
20
|
// public api ---------------------------------------------
|
|
22
21
|
|
|
@@ -25,7 +24,7 @@ const notifications = {
|
|
|
25
24
|
* Send
|
|
26
25
|
*/
|
|
27
26
|
send(notification) {
|
|
28
|
-
if (notification.type ===
|
|
27
|
+
if (notification.type === "email") {
|
|
29
28
|
emailSend(notification.email)
|
|
30
29
|
}
|
|
31
30
|
},
|
|
@@ -42,18 +41,20 @@ const notifications = {
|
|
|
42
41
|
const tag = body.tag
|
|
43
42
|
const uploaderId = uploader ? uploader.id : null
|
|
44
43
|
const URI = getDatasetWorker(datasetId)
|
|
45
|
-
const datasetDescriptionUrl =
|
|
46
|
-
|
|
44
|
+
const datasetDescriptionUrl =
|
|
45
|
+
`${URI}/datasets/${datasetId}/snapshots/${tag}/files/dataset_description.json`
|
|
46
|
+
const changesUrl =
|
|
47
|
+
`${URI}/datasets/${datasetId}/snapshots/${tag}/files/CHANGES`
|
|
47
48
|
|
|
48
49
|
// get the dataset description
|
|
49
50
|
const descriptionResponse = await request.get(datasetDescriptionUrl)
|
|
50
51
|
const description = descriptionResponse.body
|
|
51
|
-
const datasetLabel = description.Name ? description.Name :
|
|
52
|
+
const datasetLabel = description.Name ? description.Name : "Unnamed Dataset"
|
|
52
53
|
|
|
53
54
|
// get the snapshot changelog
|
|
54
55
|
const changesResponse = await request
|
|
55
56
|
.get(changesUrl)
|
|
56
|
-
.responseType(
|
|
57
|
+
.responseType("application/octet-stream")
|
|
57
58
|
const changelog = changesResponse.body
|
|
58
59
|
? changesResponse.body.toString()
|
|
59
60
|
: null
|
|
@@ -62,25 +63,24 @@ const notifications = {
|
|
|
62
63
|
datasetId: datasetId,
|
|
63
64
|
}).exec()
|
|
64
65
|
// create the email object for each user
|
|
65
|
-
subscriptions.forEach(async subscription => {
|
|
66
|
+
subscriptions.forEach(async (subscription) => {
|
|
66
67
|
const user = await User.findOne({ id: subscription.userId }).exec()
|
|
67
68
|
if (user && user.id !== uploaderId) {
|
|
68
69
|
const emailContent = {
|
|
69
|
-
_id: datasetId +
|
|
70
|
-
type:
|
|
70
|
+
_id: datasetId + "_" + user._id + "_" + "snapshot_created",
|
|
71
|
+
type: "email",
|
|
71
72
|
email: {
|
|
72
73
|
to: user.email,
|
|
73
74
|
name: user.name,
|
|
74
|
-
subject:
|
|
75
|
+
subject: "Snapshot Created",
|
|
75
76
|
html: snapshotCreated({
|
|
76
77
|
name: user.name,
|
|
77
78
|
datasetLabel: datasetLabel,
|
|
78
|
-
datasetId:
|
|
79
|
+
datasetId: datasetId,
|
|
79
80
|
versionNumber: tag,
|
|
80
81
|
changelog: changelog,
|
|
81
|
-
siteUrl:
|
|
82
|
-
|
|
83
|
-
'//' +
|
|
82
|
+
siteUrl: url.parse(config.url).protocol +
|
|
83
|
+
"//" +
|
|
84
84
|
url.parse(config.url).hostname,
|
|
85
85
|
}),
|
|
86
86
|
},
|
|
@@ -103,12 +103,13 @@ const notifications = {
|
|
|
103
103
|
const datasetLabel = comment.datasetLabel
|
|
104
104
|
? comment.datasetLabel
|
|
105
105
|
: comment.datasetId
|
|
106
|
-
const userId =
|
|
107
|
-
|
|
106
|
+
const userId = comment.user && comment.user.email
|
|
107
|
+
? comment.user.email
|
|
108
|
+
: null
|
|
108
109
|
const content = comment.text
|
|
109
110
|
const commentId = comment._id ? comment._id : null
|
|
110
111
|
const isReply = comment.parentId ? comment.parentId : null
|
|
111
|
-
const commentStatus = isReply ?
|
|
112
|
+
const commentStatus = isReply ? "reply to a comment" : "comment"
|
|
112
113
|
const editorState = EditorState.createWithContent(
|
|
113
114
|
convertFromRaw(JSON.parse(content)),
|
|
114
115
|
)
|
|
@@ -118,44 +119,41 @@ const notifications = {
|
|
|
118
119
|
// get all users that are subscribed to the dataset
|
|
119
120
|
Subscription.find({ datasetId: datasetId })
|
|
120
121
|
.exec()
|
|
121
|
-
.then(subscriptions => {
|
|
122
|
+
.then((subscriptions) => {
|
|
122
123
|
// create the email object for each user, using subscription userid and scitran
|
|
123
|
-
subscriptions.forEach(subscription => {
|
|
124
|
+
subscriptions.forEach((subscription) => {
|
|
124
125
|
User.findOne({ id: subscription.userId })
|
|
125
126
|
.exec()
|
|
126
|
-
.then(user => {
|
|
127
|
+
.then((user) => {
|
|
127
128
|
if (user && user.email !== userId) {
|
|
128
129
|
const emailContent = {
|
|
129
|
-
_id:
|
|
130
|
-
|
|
131
|
-
'_' +
|
|
130
|
+
_id: datasetId +
|
|
131
|
+
"_" +
|
|
132
132
|
subscription._id +
|
|
133
|
-
|
|
133
|
+
"_" +
|
|
134
134
|
comment._id +
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
type:
|
|
135
|
+
"_" +
|
|
136
|
+
"comment_created",
|
|
137
|
+
type: "email",
|
|
138
138
|
email: {
|
|
139
139
|
to: user.email,
|
|
140
140
|
name: user.name,
|
|
141
|
-
from:
|
|
142
|
-
'reply-' +
|
|
141
|
+
from: "reply-" +
|
|
143
142
|
encodeURIComponent(comment._id) +
|
|
144
|
-
|
|
143
|
+
"-" +
|
|
145
144
|
encodeURIComponent(user._id),
|
|
146
|
-
subject:
|
|
145
|
+
subject: "Comment Created",
|
|
147
146
|
html: commentCreated({
|
|
148
147
|
name: user.name,
|
|
149
|
-
datasetName:
|
|
148
|
+
datasetName: datasetId,
|
|
150
149
|
datasetLabel: datasetLabel,
|
|
151
150
|
commentUserId: userId,
|
|
152
151
|
commentId: commentId,
|
|
153
|
-
dateCreated: format(comment.createDate,
|
|
152
|
+
dateCreated: format(comment.createDate, "MMMM Do"),
|
|
154
153
|
commentContent: htmlContent,
|
|
155
154
|
commentStatus: commentStatus,
|
|
156
|
-
siteUrl:
|
|
157
|
-
|
|
158
|
-
'//' +
|
|
155
|
+
siteUrl: url.parse(config.url).protocol +
|
|
156
|
+
"//" +
|
|
159
157
|
url.parse(config.url).hostname,
|
|
160
158
|
}),
|
|
161
159
|
},
|
|
@@ -176,39 +174,34 @@ const notifications = {
|
|
|
176
174
|
* them that a the dataset has been deleted.
|
|
177
175
|
*/
|
|
178
176
|
datasetDeleted(datasetId) {
|
|
179
|
-
console.log(
|
|
180
|
-
'datasetDeleted notification sent with datasetName:',
|
|
181
|
-
bidsId.decodeId(datasetId),
|
|
182
|
-
)
|
|
177
|
+
console.log("datasetDeleted notification sent with datasetName:", datasetId)
|
|
183
178
|
|
|
184
179
|
// get all users that are subscribed to the dataset
|
|
185
180
|
Subscription.find({ datasetId: datasetId })
|
|
186
181
|
.exec()
|
|
187
|
-
.then(subscriptions => {
|
|
182
|
+
.then((subscriptions) => {
|
|
188
183
|
// create the email object for each user, using subscription userid and scitran
|
|
189
|
-
subscriptions.forEach(subscription => {
|
|
184
|
+
subscriptions.forEach((subscription) => {
|
|
190
185
|
User.findOne({ id: subscription.userId })
|
|
191
186
|
.exec()
|
|
192
|
-
.then(user => {
|
|
187
|
+
.then((user) => {
|
|
193
188
|
if (user) {
|
|
194
189
|
const emailContent = {
|
|
195
|
-
_id:
|
|
196
|
-
|
|
197
|
-
'_' +
|
|
190
|
+
_id: datasetId +
|
|
191
|
+
"_" +
|
|
198
192
|
subscription._id +
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
type:
|
|
193
|
+
"_" +
|
|
194
|
+
"dataset_deleted",
|
|
195
|
+
type: "email",
|
|
202
196
|
email: {
|
|
203
197
|
to: user.email,
|
|
204
198
|
name: user.name,
|
|
205
|
-
subject:
|
|
199
|
+
subject: "Dataset Deleted",
|
|
206
200
|
html: datasetDeleted({
|
|
207
201
|
name: user.name,
|
|
208
|
-
datasetName:
|
|
209
|
-
siteUrl:
|
|
210
|
-
|
|
211
|
-
'//' +
|
|
202
|
+
datasetName: datasetId,
|
|
203
|
+
siteUrl: url.parse(config.url).protocol +
|
|
204
|
+
"//" +
|
|
212
205
|
url.parse(config.url).hostname,
|
|
213
206
|
}),
|
|
214
207
|
},
|
|
@@ -229,38 +222,36 @@ const notifications = {
|
|
|
229
222
|
*/
|
|
230
223
|
ownerUnsubscribed(datasetId) {
|
|
231
224
|
console.log(
|
|
232
|
-
|
|
233
|
-
|
|
225
|
+
"ownerUnsubscribed notification sent with datasetName:",
|
|
226
|
+
datasetId,
|
|
234
227
|
)
|
|
235
228
|
|
|
236
229
|
// get all users that are subscribed to the dataset
|
|
237
230
|
Subscription.find({ datasetId: datasetId })
|
|
238
231
|
.exec()
|
|
239
|
-
.then(subscriptions => {
|
|
232
|
+
.then((subscriptions) => {
|
|
240
233
|
// create the email object for each user, using subscription userid and scitran
|
|
241
|
-
subscriptions.forEach(subscription => {
|
|
234
|
+
subscriptions.forEach((subscription) => {
|
|
242
235
|
User.findOne({ id: subscription.userId })
|
|
243
236
|
.exec()
|
|
244
|
-
.then(user => {
|
|
237
|
+
.then((user) => {
|
|
245
238
|
if (user) {
|
|
246
239
|
const emailContent = {
|
|
247
|
-
_id:
|
|
248
|
-
|
|
249
|
-
'_' +
|
|
240
|
+
_id: datasetId +
|
|
241
|
+
"_" +
|
|
250
242
|
subscription._id +
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
type:
|
|
243
|
+
"_" +
|
|
244
|
+
"owner_unsubscribed",
|
|
245
|
+
type: "email",
|
|
254
246
|
email: {
|
|
255
247
|
to: user.email,
|
|
256
248
|
name: user.name,
|
|
257
|
-
subject:
|
|
249
|
+
subject: "Owner Unsubscribed",
|
|
258
250
|
html: ownerUnsubscribed({
|
|
259
251
|
name: user.name,
|
|
260
|
-
datasetName:
|
|
261
|
-
siteUrl:
|
|
262
|
-
|
|
263
|
-
'//' +
|
|
252
|
+
datasetName: datasetId,
|
|
253
|
+
siteUrl: url.parse(config.url).protocol +
|
|
254
|
+
"//" +
|
|
264
255
|
url.parse(config.url).hostname,
|
|
265
256
|
}),
|
|
266
257
|
},
|
|
@@ -281,38 +272,36 @@ const notifications = {
|
|
|
281
272
|
*/
|
|
282
273
|
async snapshotReminder(datasetId) {
|
|
283
274
|
console.log(
|
|
284
|
-
|
|
285
|
-
|
|
275
|
+
"snapshotReminder notification sent with datasetName:",
|
|
276
|
+
datasetId,
|
|
286
277
|
)
|
|
287
278
|
|
|
288
279
|
// get all users that are subscribed to the dataset
|
|
289
280
|
await Subscription.find({ datasetId: datasetId })
|
|
290
281
|
.exec()
|
|
291
|
-
.then(subscriptions => {
|
|
282
|
+
.then((subscriptions) => {
|
|
292
283
|
// create the email object for each user, using subscription userid and scitran
|
|
293
|
-
subscriptions.forEach(subscription => {
|
|
284
|
+
subscriptions.forEach((subscription) => {
|
|
294
285
|
User.findOne({ id: subscription.userId })
|
|
295
286
|
.exec()
|
|
296
|
-
.then(user => {
|
|
287
|
+
.then((user) => {
|
|
297
288
|
if (user) {
|
|
298
289
|
const emailContent = {
|
|
299
|
-
_id:
|
|
300
|
-
|
|
301
|
-
'_' +
|
|
290
|
+
_id: datasetId +
|
|
291
|
+
"_" +
|
|
302
292
|
subscription._id +
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
type:
|
|
293
|
+
"_" +
|
|
294
|
+
"snapshot_reminder",
|
|
295
|
+
type: "email",
|
|
306
296
|
email: {
|
|
307
297
|
to: user.email,
|
|
308
298
|
name: user.name,
|
|
309
|
-
subject:
|
|
299
|
+
subject: "Snapshot Reminder",
|
|
310
300
|
html: snapshotReminder({
|
|
311
301
|
name: user.name,
|
|
312
|
-
datasetName:
|
|
313
|
-
siteUrl:
|
|
314
|
-
|
|
315
|
-
'//' +
|
|
302
|
+
datasetName: datasetId,
|
|
303
|
+
siteUrl: url.parse(config.url).protocol +
|
|
304
|
+
"//" +
|
|
316
305
|
url.parse(config.url).hostname,
|
|
317
306
|
datasetId,
|
|
318
307
|
}),
|
|
@@ -340,30 +329,28 @@ const notifications = {
|
|
|
340
329
|
html = datasetImportEmail({
|
|
341
330
|
name: user.name,
|
|
342
331
|
datasetId: datasetId,
|
|
343
|
-
siteUrl:
|
|
344
|
-
|
|
345
|
-
'//' +
|
|
332
|
+
siteUrl: url.parse(config.url).protocol +
|
|
333
|
+
"//" +
|
|
346
334
|
url.parse(config.url).hostname,
|
|
347
335
|
})
|
|
348
336
|
} else {
|
|
349
337
|
html = datasetImportFailed({
|
|
350
338
|
name: user.name,
|
|
351
339
|
datasetId: datasetId,
|
|
352
|
-
message: success ?
|
|
353
|
-
siteUrl:
|
|
354
|
-
|
|
355
|
-
'//' +
|
|
340
|
+
message: success ? "" : message,
|
|
341
|
+
siteUrl: url.parse(config.url).protocol +
|
|
342
|
+
"//" +
|
|
356
343
|
url.parse(config.url).hostname,
|
|
357
344
|
retryUrl: retryUrl,
|
|
358
345
|
})
|
|
359
346
|
}
|
|
360
347
|
const emailContent = {
|
|
361
|
-
_id: datasetId +
|
|
362
|
-
type:
|
|
348
|
+
_id: datasetId + "_" + user._id + "_" + "dataset_imported",
|
|
349
|
+
type: "email",
|
|
363
350
|
email: {
|
|
364
351
|
to: user.email,
|
|
365
352
|
name: user.name,
|
|
366
|
-
subject: `Dataset Import ${success ?
|
|
353
|
+
subject: `Dataset Import ${success ? "Success" : "Failed"}`,
|
|
367
354
|
html: html,
|
|
368
355
|
},
|
|
369
356
|
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// Camel case rule is disabled since ORCID API uses snake case variables
|
|
2
|
-
import request from
|
|
3
|
-
import xmldoc from
|
|
4
|
-
import config from
|
|
2
|
+
import request from "request"
|
|
3
|
+
import xmldoc from "xmldoc"
|
|
4
|
+
import config from "../config"
|
|
5
5
|
|
|
6
6
|
export default {
|
|
7
7
|
getProfile(token) {
|
|
8
8
|
return new Promise((resolve, reject) => {
|
|
9
|
-
const data = token.split(
|
|
9
|
+
const data = token.split(":")
|
|
10
10
|
if (data.length != 2) {
|
|
11
|
-
reject(
|
|
11
|
+
reject("Invalid token")
|
|
12
12
|
}
|
|
13
13
|
const orcid = data[0]
|
|
14
14
|
const accessToken = data[1]
|
|
@@ -22,7 +22,7 @@ export default {
|
|
|
22
22
|
if (err) {
|
|
23
23
|
return reject({
|
|
24
24
|
message:
|
|
25
|
-
|
|
25
|
+
"An unexpected ORCID login failure occurred, please try again later.",
|
|
26
26
|
})
|
|
27
27
|
}
|
|
28
28
|
let doc
|
|
@@ -31,36 +31,36 @@ export default {
|
|
|
31
31
|
doc = new xmldoc.XmlDocument(res.body)
|
|
32
32
|
} catch (err) {
|
|
33
33
|
return reject({
|
|
34
|
-
type:
|
|
34
|
+
type: "config",
|
|
35
35
|
message:
|
|
36
|
-
|
|
36
|
+
"ORCID auth response invalid, most likely this is a misconfigured ORCID_API_ENDPOINT value",
|
|
37
37
|
})
|
|
38
38
|
}
|
|
39
39
|
let name = doc.valueWithPath(
|
|
40
|
-
|
|
40
|
+
"person:person.person:name.personal-details:credit-name",
|
|
41
41
|
)
|
|
42
42
|
const firstname = doc.valueWithPath(
|
|
43
|
-
|
|
43
|
+
"person:person.person:name.personal-details:given-names",
|
|
44
44
|
)
|
|
45
45
|
const lastname = doc.valueWithPath(
|
|
46
|
-
|
|
46
|
+
"person:person.person:name.personal-details:family-name",
|
|
47
47
|
)
|
|
48
48
|
const email = doc.valueWithPath(
|
|
49
|
-
|
|
49
|
+
"person:person.email:emails.email:email.email:email",
|
|
50
50
|
)
|
|
51
51
|
|
|
52
52
|
if (!name) {
|
|
53
53
|
if (!firstname) {
|
|
54
54
|
return reject({
|
|
55
|
-
type:
|
|
55
|
+
type: "given",
|
|
56
56
|
message:
|
|
57
|
-
|
|
57
|
+
"Your ORCID account does not have a given name, or it is not public. Please fix your account before continuing.",
|
|
58
58
|
})
|
|
59
59
|
} else if (!lastname) {
|
|
60
60
|
return reject({
|
|
61
|
-
type:
|
|
61
|
+
type: "family",
|
|
62
62
|
message:
|
|
63
|
-
|
|
63
|
+
"Your ORCID account does not have a family name, or it is not public. Please fix your account before continuing.",
|
|
64
64
|
})
|
|
65
65
|
} else {
|
|
66
66
|
name = `${firstname} ${lastname}`
|
|
@@ -69,9 +69,9 @@ export default {
|
|
|
69
69
|
|
|
70
70
|
if (!email) {
|
|
71
71
|
return reject({
|
|
72
|
-
type:
|
|
72
|
+
type: "email",
|
|
73
73
|
message:
|
|
74
|
-
|
|
74
|
+
"Your ORCID account does not have an e-mail, or your e-mail is not public. Please fix your account before continuing.",
|
|
75
75
|
})
|
|
76
76
|
}
|
|
77
77
|
|
|
@@ -92,7 +92,7 @@ export default {
|
|
|
92
92
|
client_id: config.auth.orcid.clientID,
|
|
93
93
|
client_secret: config.auth.orcid.clientSecret,
|
|
94
94
|
redirect_uri: config.auth.orcid.redirectURI,
|
|
95
|
-
grant_type:
|
|
95
|
+
grant_type: "refresh_token",
|
|
96
96
|
refresh_token: refreshToken,
|
|
97
97
|
},
|
|
98
98
|
json: true,
|
|
@@ -115,7 +115,7 @@ export default {
|
|
|
115
115
|
client_id: config.auth.orcid.clientID,
|
|
116
116
|
client_secret: config.auth.orcid.clientSecret,
|
|
117
117
|
redirect_uri: config.auth.orcid.redirectURI,
|
|
118
|
-
grant_type:
|
|
118
|
+
grant_type: "authorization_code",
|
|
119
119
|
code,
|
|
120
120
|
},
|
|
121
121
|
json: true,
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/*eslint no-console: ["error", { allow: ["log"] }] */
|
|
2
2
|
|
|
3
3
|
// dependencies --------------------------------------------------
|
|
4
|
-
import Redis from
|
|
5
|
-
import Redlock from
|
|
4
|
+
import Redis from "ioredis"
|
|
5
|
+
import Redlock from "redlock"
|
|
6
6
|
|
|
7
7
|
let redis = null
|
|
8
8
|
let redlock = null
|
|
9
9
|
|
|
10
|
-
const connect = async config => {
|
|
11
|
-
return new Promise(resolve => {
|
|
10
|
+
const connect = async (config) => {
|
|
11
|
+
return new Promise((resolve) => {
|
|
12
12
|
if (!redis) {
|
|
13
13
|
console.log(
|
|
14
14
|
'Connecting to Redis "redis://%s:%d/0"',
|
|
@@ -17,7 +17,7 @@ const connect = async config => {
|
|
|
17
17
|
)
|
|
18
18
|
redis = new Redis(config)
|
|
19
19
|
redlock = new Redlock([redis])
|
|
20
|
-
redis.on(
|
|
20
|
+
redis.on("connect", () => {
|
|
21
21
|
resolve(redis)
|
|
22
22
|
})
|
|
23
23
|
} else {
|
|
@@ -27,4 +27,4 @@ const connect = async config => {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
export default { connect }
|
|
30
|
-
export { redis, redlock
|
|
30
|
+
export { connect, redis, redlock }
|
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
import { vi } from
|
|
2
|
-
import IngestDataset from
|
|
1
|
+
import { vi } from "vitest"
|
|
2
|
+
import IngestDataset from "../ingestDataset"
|
|
3
3
|
|
|
4
|
-
vi.mock(
|
|
4
|
+
vi.mock("ioredis")
|
|
5
5
|
|
|
6
|
-
describe(
|
|
7
|
-
it(
|
|
6
|
+
describe("IngestDataset model", () => {
|
|
7
|
+
it("IngestDataset model fails if required fields are missing", () => {
|
|
8
8
|
const model = new IngestDataset()
|
|
9
9
|
const result = model.validateSync()
|
|
10
|
-
expect(result.name).toEqual(
|
|
10
|
+
expect(result.name).toEqual("ValidationError")
|
|
11
11
|
})
|
|
12
|
-
it(
|
|
12
|
+
it("IngestDataset model URL validation fails with a bad URL", async () => {
|
|
13
13
|
const badUrlModel = new IngestDataset({
|
|
14
|
-
datasetId:
|
|
15
|
-
userId:
|
|
16
|
-
url:
|
|
14
|
+
datasetId: "ds00000",
|
|
15
|
+
userId: "b3df6399-d1be-4e07-b997-9f7aa3ed1f8e",
|
|
16
|
+
url: "this is not a valid URL",
|
|
17
17
|
imported: false,
|
|
18
18
|
notified: false,
|
|
19
19
|
})
|
|
20
20
|
const result = badUrlModel.validateSync()
|
|
21
|
-
expect(result.name).toEqual(
|
|
21
|
+
expect(result.name).toEqual("ValidationError")
|
|
22
22
|
})
|
|
23
|
-
it(
|
|
23
|
+
it("IngestDataset model URL validation succeeds with a good URL", async () => {
|
|
24
24
|
const goodUrlModel = new IngestDataset({
|
|
25
|
-
datasetId:
|
|
26
|
-
userId:
|
|
27
|
-
url:
|
|
25
|
+
datasetId: "ds00000",
|
|
26
|
+
userId: "b3df6399-d1be-4e07-b997-9f7aa3ed1f8e",
|
|
27
|
+
url: "https://example.com",
|
|
28
28
|
imported: false,
|
|
29
29
|
notified: false,
|
|
30
30
|
})
|
package/src/models/analytics.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import mongoose, { Document } from
|
|
1
|
+
import mongoose, { Document } from "mongoose"
|
|
2
2
|
const { Schema, model } = mongoose
|
|
3
3
|
|
|
4
4
|
export interface AnalyticsDocument extends Document {
|
|
@@ -17,6 +17,6 @@ const analyticsSchema = new Schema({
|
|
|
17
17
|
views: { type: Number, required: false },
|
|
18
18
|
})
|
|
19
19
|
|
|
20
|
-
const Analytics = model<AnalyticsDocument>(
|
|
20
|
+
const Analytics = model<AnalyticsDocument>("Analytics", analyticsSchema)
|
|
21
21
|
|
|
22
22
|
export default Analytics
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import mongoose, { Document } from
|
|
2
|
-
import { UserDocument } from
|
|
1
|
+
import mongoose, { Document } from "mongoose"
|
|
2
|
+
import { UserDocument } from "./user"
|
|
3
3
|
const ObjectId = mongoose.Schema.Types.ObjectId
|
|
4
4
|
|
|
5
5
|
export interface BadAnnexObject extends Document {
|
|
@@ -24,17 +24,17 @@ const badAnnexObject = new mongoose.Schema(
|
|
|
24
24
|
filepath: String,
|
|
25
25
|
annexKey: String,
|
|
26
26
|
removed: { type: Boolean, default: false },
|
|
27
|
-
remover: { type: ObjectId, ref:
|
|
27
|
+
remover: { type: ObjectId, ref: "User" },
|
|
28
28
|
flagged: { type: Boolean, default: false },
|
|
29
|
-
flagger: { type: ObjectId, ref:
|
|
29
|
+
flagger: { type: ObjectId, ref: "User" },
|
|
30
30
|
},
|
|
31
|
-
{ timestamps: { createdAt:
|
|
31
|
+
{ timestamps: { createdAt: "created_at" } },
|
|
32
32
|
)
|
|
33
33
|
|
|
34
34
|
badAnnexObject.index({ datasetId: 1, annexKey: 1 }, { unique: true })
|
|
35
35
|
|
|
36
36
|
const BadAnnexObject = mongoose.model<BadAnnexObject>(
|
|
37
|
-
|
|
37
|
+
"BadAnnexObject",
|
|
38
38
|
badAnnexObject,
|
|
39
39
|
)
|
|
40
40
|
|
package/src/models/comment.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import mongoose, { Document } from
|
|
1
|
+
import mongoose, { Document } from "mongoose"
|
|
2
2
|
const { Schema, model } = mongoose
|
|
3
3
|
|
|
4
4
|
export interface CommentDocument extends Document {
|
|
@@ -26,21 +26,21 @@ const commentSchema = new Schema(
|
|
|
26
26
|
)
|
|
27
27
|
|
|
28
28
|
// Foreign key virtuals
|
|
29
|
-
commentSchema.virtual(
|
|
30
|
-
ref:
|
|
31
|
-
localField:
|
|
32
|
-
foreignField:
|
|
29
|
+
commentSchema.virtual("poster", {
|
|
30
|
+
ref: "User",
|
|
31
|
+
localField: "user._id",
|
|
32
|
+
foreignField: "id",
|
|
33
33
|
justOne: true,
|
|
34
34
|
})
|
|
35
35
|
|
|
36
36
|
// Foreign key virtuals
|
|
37
|
-
commentSchema.virtual(
|
|
38
|
-
ref:
|
|
39
|
-
localField:
|
|
40
|
-
foreignField:
|
|
37
|
+
commentSchema.virtual("parent", {
|
|
38
|
+
ref: "Comment",
|
|
39
|
+
localField: "parentId",
|
|
40
|
+
foreignField: "_id",
|
|
41
41
|
justOne: true,
|
|
42
42
|
})
|
|
43
43
|
|
|
44
|
-
const Comment = model<CommentDocument>(
|
|
44
|
+
const Comment = model<CommentDocument>("Comment", commentSchema)
|
|
45
45
|
|
|
46
46
|
export default Comment
|