@dmptool/utils 1.0.4 → 1.0.6

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/dist/maDMP.js CHANGED
@@ -9,9 +9,6 @@ const types_1 = require("@dmptool/types");
9
9
  const maDMPTypes_1 = require("./maDMPTypes");
10
10
  const ROR_REGEX = /^https?:\/\/ror\.org\/[0-9a-zA-Z]+$/;
11
11
  const DOI_REGEX = /^(https?:\/\/)?(doi\.org\/)?(doi:)?(10\.\d{4,9}\/[-._;()/:\w]+)$/;
12
- const ORCID_BASE_URL = process.env.ENV && ['stg', 'prd'].includes(process.env.ENV)
13
- ? 'https://orcid.org/'
14
- : 'https://sandbox.orcid.org/';
15
12
  const ORCID_REGEX = /^(https?:\/\/)?(www\.|pub\.)?(sandbox\.)?(orcid\.org\/)?([0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{3}[0-9X])$/;
16
13
  class DMPValidationError extends Error {
17
14
  constructor(message) {
@@ -25,14 +22,17 @@ class DMPValidationError extends Error {
25
22
  * @param orcidIn the ORCID to check
26
23
  * @returns the ORCID in the correct format or null if it is not in the correct format
27
24
  */
28
- function formatORCID(orcidIn) {
25
+ function formatORCID(env, orcidIn) {
29
26
  // If it is blank or already in the correct format, return it
30
27
  if (orcidIn && (orcidIn.match(ORCID_REGEX) && orcidIn.startsWith('http'))) {
31
28
  return (0, general_1.normaliseHttpProtocol)(orcidIn);
32
29
  }
30
+ const baseURL = env && ['stg', 'prd'].includes(env)
31
+ ? 'https://orcid.org/'
32
+ : 'https://sandbox.orcid.org/';
33
33
  // If it matches the ORCID format but didn't start with http then its just the id
34
34
  if (orcidIn && orcidIn.match(ORCID_REGEX)) {
35
- return (0, general_1.normaliseHttpProtocol)(`${ORCID_BASE_URL}${orcidIn.split('/').pop()}`);
35
+ return (0, general_1.normaliseHttpProtocol)(`${baseURL}${orcidIn.split('/').pop()}`);
36
36
  }
37
37
  // Otherwise it's not an ORCID
38
38
  return null;
@@ -97,21 +97,24 @@ function convertFiveCharToThreeChar(language) {
97
97
  /**
98
98
  * Function to generate the base of an internal ID namespace
99
99
  *
100
+ * @param applicationName the name of the application/service
100
101
  * @param projectId the Project ID to use for the internal ID namespace
101
102
  * @param planId the Plan ID to use for the internal ID namespace
102
103
  * @returns the base of the internal ID namespace
103
104
  */
104
- function internalIdBase(projectId, planId) {
105
- return `${process.env.APPLICATION_NAME}.projects.${projectId}.dmp.${planId}`;
105
+ function internalIdBase(applicationName, projectId, planId) {
106
+ return `${applicationName}.projects.${projectId}.dmp.${planId}`;
106
107
  }
107
108
  /**
108
109
  * Fetch the default MemberRole from the MySQL database
109
110
  *
111
+ * @param rdsConnectionParams the connection parameters for the MySQL database
110
112
  * @returns the default MemberRole as a string (or undefined if there is no default)
111
113
  */
112
- const loadDefaultMemberRole = async () => {
114
+ const loadDefaultMemberRole = async (rdsConnectionParams) => {
113
115
  const sql = 'SELECT * FROM memberRoles WHERE isDefault = 1';
114
- const resp = await (0, rds_1.queryTable)(sql, []);
116
+ rdsConnectionParams.logger.debug({ sql }, 'Fetching default role');
117
+ const resp = await (0, rds_1.queryTable)(rdsConnectionParams, sql, []);
115
118
  if (resp && Array.isArray(resp.results) && resp.results.length > 0) {
116
119
  return resp.results[0].id;
117
120
  }
@@ -121,11 +124,12 @@ const loadDefaultMemberRole = async () => {
121
124
  * Fetches the Plan information needed to construct the DMP Common Standard from
122
125
  * the MySQL database
123
126
  *
127
+ * @param rdsConnectionParams the connection parameters for the MySQL database
124
128
  * @param planId the Plan ID to fetch the Plan information for
125
129
  * @returns the Plan information needed to construct the DMP Common Standard
126
130
  */
127
131
  // Fetch the Plan info needed from the MySQL database
128
- const loadPlanInfo = async (planId) => {
132
+ const loadPlanInfo = async (rdsConnectionParams, planId) => {
129
133
  const sql = `
130
134
  SELECT id, dmpId, projectId, versionedTemplateId,
131
135
  createdById, created, modifiedById, modified, title,
@@ -134,7 +138,8 @@ const loadPlanInfo = async (planId) => {
134
138
  FROM plans
135
139
  WHERE id = ?
136
140
  `;
137
- const resp = await (0, rds_1.queryTable)(sql, [planId.toString()]);
141
+ rdsConnectionParams.logger.debug({ planId, sql }, 'Fetching plan information');
142
+ const resp = await (0, rds_1.queryTable)(rdsConnectionParams, sql, [planId.toString()]);
138
143
  if (resp && Array.isArray(resp.results) && resp.results.length > 0) {
139
144
  return resp.results[0];
140
145
  }
@@ -144,16 +149,18 @@ const loadPlanInfo = async (planId) => {
144
149
  * Fetches the Project information needed to construct the DMP Common Standard
145
150
  * from the MySQL database
146
151
  *
152
+ * @param rdsConnectionParams the connection parameters for the MySQL database
147
153
  * @param projectId the Project ID to fetch the Project information for
148
154
  * @returns the Project information needed to construct the DMP Common Standard
149
155
  */
150
- const loadProjectInfo = async (projectId) => {
156
+ const loadProjectInfo = async (rdsConnectionParams, projectId) => {
151
157
  const sql = `
152
158
  SELECT id, title, abstractText, startDate, endDate
153
159
  FROM projects
154
160
  WHERE id = ?
155
161
  `;
156
- const resp = await (0, rds_1.queryTable)(sql, [projectId.toString()]);
162
+ rdsConnectionParams.logger.debug({ projectId, sql }, 'Fetching project information');
163
+ const resp = await (0, rds_1.queryTable)(rdsConnectionParams, sql, [projectId.toString()]);
157
164
  if (resp && Array.isArray(resp.results) && resp.results.length > 0) {
158
165
  return resp.results[0];
159
166
  }
@@ -163,10 +170,11 @@ const loadProjectInfo = async (projectId) => {
163
170
  * Fetches the PlanFunding information needed to construct the DMP Common Standard
164
171
  * from the MySQL database
165
172
  *
173
+ * @param rdsConnectionParams the connection parameters for the MySQL database
166
174
  * @param planId the Plan ID to fetch the PlanFunding information for
167
175
  * @returns the Funding information needed to construct the DMP Common Standard
168
176
  */
169
- const loadFundingInfo = async (planId) => {
177
+ const loadFundingInfo = async (rdsConnectionParams, planId) => {
170
178
  const sql = `
171
179
  SELECT pf.id, a.uri, a.name, prf.status, prf.grantId,
172
180
  prf.funderProjectNumber, prf.funderOpportunityNumber
@@ -175,7 +183,8 @@ const loadFundingInfo = async (planId) => {
175
183
  LEFT JOIN affiliations a ON prf.affiliationId = a.uri
176
184
  WHERE pf.planId = ?
177
185
  `;
178
- const resp = await (0, rds_1.queryTable)(sql, [planId.toString()]);
186
+ rdsConnectionParams.logger.debug({ planId, sql }, 'Fetching plan funding information');
187
+ const resp = await (0, rds_1.queryTable)(rdsConnectionParams, sql, [planId.toString()]);
179
188
  if (resp && Array.isArray(resp.results) && resp.results.length > 0) {
180
189
  const fundings = resp.results.filter((row) => !(0, general_1.isNullOrUndefined)(row));
181
190
  fundings.forEach((funding) => funding.status = planFundingStatusToDMPFundingStatus(funding.status));
@@ -187,10 +196,11 @@ const loadFundingInfo = async (planId) => {
187
196
  * Fetches the Plan's owner information needed to construct the DMP Common Standard
188
197
  * from the MySQL database
189
198
  *
199
+ * @param rdsConnectionParams the connection parameters for the MySQL database
190
200
  * @param ownerId the user id for the plan's owner
191
201
  * @returns the contact information needed to construct the DMP Common Standard
192
202
  */
193
- async function loadContactFromPlanOwner(ownerId) {
203
+ async function loadContactFromPlanOwner(rdsConnectionParams, ownerId) {
194
204
  const sql = `
195
205
  SELECT u.id, u.givenName, u.surName, u.orcid, a.uri, a.name,
196
206
  (SELECT ue.email
@@ -200,7 +210,8 @@ async function loadContactFromPlanOwner(ownerId) {
200
210
  LEFT JOIN affiliations a ON u.affiliationId = a.id
201
211
  WHERE u.id = ?
202
212
  `;
203
- const resp = await (0, rds_1.queryTable)(sql, [ownerId.toString()]);
213
+ rdsConnectionParams.logger.debug({ ownerId, sql }, 'Fetching plan owner information');
214
+ const resp = await (0, rds_1.queryTable)(rdsConnectionParams, sql, [ownerId.toString()]);
204
215
  if (resp && Array.isArray(resp.results) && resp.results.length > 0) {
205
216
  return resp.results.filter((row) => !(0, general_1.isNullOrUndefined)(row))[0];
206
217
  }
@@ -210,10 +221,11 @@ async function loadContactFromPlanOwner(ownerId) {
210
221
  * Fetches the PlanMember information needed to construct the DMP Common Standard
211
222
  * from the MySQL database
212
223
  *
224
+ * @param rdsConnectionParams the connection parameters for the MySQL database
213
225
  * @param planId the Plan ID to fetch the PlanMember information for
214
226
  * @returns the contributor information needed to construct the DMP Common Standard
215
227
  */
216
- const loadMemberInfo = async (planId) => {
228
+ const loadMemberInfo = async (rdsConnectionParams, planId) => {
217
229
  const sql = `
218
230
  SELECT pc.id, a.uri, a.name, pctr.email, pctr.givenName, pctr.surName,
219
231
  pctr.orcid, pc.isPrimaryContact, GROUP_CONCAT(r.uri) as roles
@@ -226,7 +238,8 @@ const loadMemberInfo = async (planId) => {
226
238
  GROUP BY a.uri, a.name, pctr.email, pctr.givenName, pctr.surName,
227
239
  pctr.orcid, pc.isPrimaryContact;
228
240
  `;
229
- const resp = await (0, rds_1.queryTable)(sql, [planId.toString()]);
241
+ rdsConnectionParams.logger.debug({ planId, sql }, 'Fetching plan member information');
242
+ const resp = await (0, rds_1.queryTable)(rdsConnectionParams, sql, [planId.toString()]);
230
243
  if (resp && Array.isArray(resp.results) && resp.results.length > 0) {
231
244
  return resp.results.filter((row) => !(0, general_1.isNullOrUndefined)(row));
232
245
  }
@@ -236,14 +249,15 @@ const loadMemberInfo = async (planId) => {
236
249
  * Returns a default RDA Common Standard Dataset entry for the DMP.
237
250
  * This is used when the Plan has no Answers to a Research Outputs question.
238
251
  *
252
+ * @param applicationName the name of the application/service
239
253
  * @param projectId the Project ID to use for the Dataset entry
240
254
  * @param planId the Plan ID to use for the Dataset entry
241
255
  * @returns a generic default Dataset entry
242
256
  */
243
- const defaultDataset = (projectId, planId) => {
257
+ const defaultDataset = (applicationName, projectId, planId) => {
244
258
  return {
245
259
  dataset_id: {
246
- identifier: `${internalIdBase(projectId, planId)}.outputs.1`,
260
+ identifier: `${internalIdBase(applicationName, projectId, planId)}.outputs.1`,
247
261
  type: 'other'
248
262
  },
249
263
  personal_data: 'unknown',
@@ -257,12 +271,14 @@ const defaultDataset = (projectId, planId) => {
257
271
  * from the MySQL database this information is extracted from the Answers table
258
272
  * for Research Output Questions
259
273
  *
274
+ * @param rdssConnectionParams the connection parameters for the MySQL database
275
+ * @param applicationName the name of the application/service
260
276
  * @param projectId the Project ID to fetch the Dataset information for
261
277
  * @param planId the Plan ID to fetch the Dataset information for
262
278
  * @param language the language to use for the Dataset information
263
279
  * @returns the dataset information needed to construct the DMP Common Standard
264
280
  */
265
- const loadDatasetInfo = async (projectId, planId, language = 'eng') => {
281
+ const loadDatasetInfo = async (rdsConnectionParams, applicationName, projectId, planId, language = 'eng') => {
266
282
  const datasets = [];
267
283
  const sql = `
268
284
  SELECT a.json
@@ -270,7 +286,8 @@ const loadDatasetInfo = async (projectId, planId, language = 'eng') => {
270
286
  WHERE a.planId = ?
271
287
  AND a.json LIKE '%"researchOutputsTable"%';
272
288
  `;
273
- const resp = await (0, rds_1.queryTable)(sql, [planId.toString()]);
289
+ rdsConnectionParams.logger.debug({ projectId, planId, sql }, 'Fetching research output information');
290
+ const resp = await (0, rds_1.queryTable)(rdsConnectionParams, sql, [planId.toString()]);
274
291
  // There would typically only be one research outputs question per plan but
275
292
  // we need to allow for multiples just in case.
276
293
  if (resp && Array.isArray(resp.results) && resp.results.length > 0) {
@@ -281,22 +298,24 @@ const loadDatasetInfo = async (projectId, planId, language = 'eng') => {
281
298
  // Loop through the rows and construct the RDA Common Standard Dataset object
282
299
  for (let idx = 0; idx < json.answer.length; idx++) {
283
300
  const row = json.answer[idx];
284
- datasets.push(buildDataset(idx, row, projectId, planId, lang));
301
+ datasets.push(buildDataset(applicationName, idx, row, projectId, planId, lang));
285
302
  }
286
303
  }
287
304
  }
288
305
  else {
289
- return [defaultDataset(projectId, planId)];
306
+ rdsConnectionParams.logger.debug({ projectId, planId }, 'Using the default dataset');
307
+ return [defaultDataset(applicationName, projectId, planId)];
290
308
  }
291
309
  return datasets;
292
310
  };
293
311
  /**
294
312
  * Builds the RDA Common Standard Related Identifier entries for the DMP
295
313
  *
314
+ * @param rdsConnectionParams the connection parameters for the MySQL database
296
315
  * @param projectId the Project ID to fetch the Related Works information for
297
316
  * @returns the RDA Common Standard Related Identifier entries for the DMP
298
317
  */
299
- const loadRelatedWorksInfo = async (projectId) => {
318
+ const loadRelatedWorksInfo = async (rdsConnectionParams, projectId) => {
300
319
  const sql = `
301
320
  SELECT w.doi AS identifier, LOWER(wv.workType) AS workType,
302
321
  FROM relatedWorks rw
@@ -304,7 +323,8 @@ const loadRelatedWorksInfo = async (projectId) => {
304
323
  JOIN works w ON wv.workId = w.id
305
324
  WHERE rw.projectId = ?;
306
325
  `;
307
- const resp = await (0, rds_1.queryTable)(sql, [projectId.toString()]);
326
+ rdsConnectionParams.logger.debug({ projectId, sql }, 'Fetching related works information');
327
+ const resp = await (0, rds_1.queryTable)(rdsConnectionParams, sql, [projectId.toString()]);
308
328
  if (resp && Array.isArray(resp.results) && resp.results.length > 0) {
309
329
  const works = resp.results.filter((row) => !(0, general_1.isNullOrUndefined)(row));
310
330
  // Determine the identifier types
@@ -323,10 +343,11 @@ const loadRelatedWorksInfo = async (projectId) => {
323
343
  /**
324
344
  * Builds the DMP Tool Narrative extension for the DMP
325
345
  *
346
+ * @param rdssConnectionParams the connection parameters for the MySQL database
326
347
  * @param planId the Plan ID to fetch the narrative information for
327
348
  * @returns the DMP Tool Narrative extension for the DMP
328
349
  */
329
- const loadNarrativeTemplateInfo = async (planId) => {
350
+ const loadNarrativeTemplateInfo = async (rdsConnectionParams, planId) => {
330
351
  // Fetch the template, sections, questions and answers all at once
331
352
  const sql = `
332
353
  SELECT t.id templateId, t.name templateTitle, t.description templateDescription,
@@ -342,7 +363,8 @@ const loadNarrativeTemplateInfo = async (planId) => {
342
363
  WHERE p.id = ?
343
364
  ORDER BY s.displayOrder, q.displayOrder;
344
365
  `;
345
- const resp = await (0, rds_1.queryTable)(sql, [planId.toString()]);
366
+ rdsConnectionParams.logger.debug({ planId, sql }, 'Fetching narrative information');
367
+ const resp = await (0, rds_1.queryTable)(rdsConnectionParams, sql, [planId.toString()]);
346
368
  let results = [];
347
369
  // Filter out any null or undefined results
348
370
  if (resp && Array.isArray(resp.results) && resp.results.length > 0) {
@@ -388,12 +410,13 @@ const loadNarrativeTemplateInfo = async (planId) => {
388
410
  /**
389
411
  * Builds the RDA Common Standard Contact entry for the DMP
390
412
  *
413
+ * @param rdssConnectionParams the connection parameters for the MySQL database
391
414
  * @param plan the Plan information retrieve from the MySQL database
392
415
  * @param members the PlanMembers information retrieve from the MySQL database
393
416
  * @returns the RDA Common Standard Contact entry for the DMP
394
417
  * @throws DMPValidationError if no primary contact is found for the DMP
395
418
  */
396
- const buildContact = async (plan, members) => {
419
+ const buildContact = async (rdsConnectionParams, env, plan, members) => {
397
420
  // Extract the primary contact from the members
398
421
  const memberContact = members.find((c) => {
399
422
  return c === null || c === void 0 ? void 0 : c.isPrimaryContact;
@@ -401,9 +424,9 @@ const buildContact = async (plan, members) => {
401
424
  // If no primary contact is available, use the plan owner
402
425
  const primary = memberContact && memberContact.email
403
426
  ? memberContact
404
- : await loadContactFromPlanOwner(Number(plan.createdById));
427
+ : await loadContactFromPlanOwner(rdsConnectionParams, Number(plan.createdById));
405
428
  if (primary && primary.email) {
406
- const orcid = primary.orcid ? formatORCID(primary.orcid) : null;
429
+ const orcid = primary.orcid ? formatORCID(env, primary.orcid) : null;
407
430
  // Build the contact entry for the DMP
408
431
  const contactEntry = {
409
432
  contact_id: [{
@@ -436,13 +459,14 @@ const buildContact = async (plan, members) => {
436
459
  /**
437
460
  * Builds the RDA Common Standard Contributor array for the DMP from the PlanMembers
438
461
  *
462
+ * @param applicationName the name of the application/service
439
463
  * @param planId the Plan ID
440
464
  * @param projectId the Project ID
441
465
  * @param members the PlanMembers information retrieve from the MySQL database
442
466
  * @param defaultRole the default role to use if the member doesn't have a role'
443
467
  * @returns the RDA Common Standard Contributor array for the DMP
444
468
  */
445
- const buildContributors = (planId, projectId, members, defaultRole) => {
469
+ const buildContributors = (applicationName, env, planId, projectId, members, defaultRole) => {
446
470
  if (!Array.isArray(members) || members.length <= 0) {
447
471
  return [];
448
472
  }
@@ -458,7 +482,7 @@ const buildContributors = (planId, projectId, members, defaultRole) => {
458
482
  role: roles,
459
483
  };
460
484
  // Use the member's ORCID if it exists, otherwise generate a new one'
461
- const formatted = member.orcid ? formatORCID(member.orcid) : null;
485
+ const formatted = member.orcid ? formatORCID(env, member.orcid) : null;
462
486
  if (formatted !== null) {
463
487
  contrib.contributor_id = [{
464
488
  identifier: formatted,
@@ -468,7 +492,7 @@ const buildContributors = (planId, projectId, members, defaultRole) => {
468
492
  else {
469
493
  // RDA Common Standard requires an id so generate one
470
494
  contrib.contributor_id = [{
471
- identifier: `${internalIdBase(projectId, planId)}.members.${member.id}`,
495
+ identifier: `${internalIdBase(applicationName, projectId, planId)}.members.${member.id}`,
472
496
  type: 'other'
473
497
  }];
474
498
  }
@@ -488,25 +512,28 @@ const buildContributors = (planId, projectId, members, defaultRole) => {
488
512
  /**
489
513
  * Builds the DMP Tool extensions to the RDA Common Standard
490
514
  *
515
+ * @param rdsConnectionParams the connection parameters for the MySQL database
516
+ * @param applicationName the name of the application/service
517
+ * @param domainName the domain name of the DMP Tool
491
518
  * @param plan the Plan information retrieve from the MySQL database
492
519
  * @param project the Project information retrieve from the MySQL database
493
520
  * @param funding the Funding information retrieve from the MySQL database
494
521
  * @returns the DMP metadata with extensions from the DMP Tool
495
522
  */
496
- const buildDMPToolExtensions = async (plan, project, funding) => {
523
+ const buildDMPToolExtensions = async (rdsConnectionParams, applicationName, domainName, plan, project, funding) => {
497
524
  var _a, _b, _c, _d, _e, _f;
498
525
  const extensions = {
499
526
  rda_schema_version: types_1.RDA_COMMON_STANDARD_VERSION,
500
527
  // Ignoring the `!` assertion here because we know we check the env variable
501
528
  // when the entrypoint function is called.
502
529
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
503
- provenance: process.env.APPLICATION_NAME,
530
+ provenance: applicationName,
504
531
  featured: plan.featured ? 'yes' : 'no',
505
532
  privacy: (_b = (_a = plan.visibility) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== null && _b !== void 0 ? _b : 'private',
506
533
  status: (_d = (_c = plan.status) === null || _c === void 0 ? void 0 : _c.toLowerCase()) !== null && _d !== void 0 ? _d : 'draft',
507
534
  };
508
535
  // Generate the DMP Narrative
509
- const narrative = await loadNarrativeTemplateInfo(plan.id);
536
+ const narrative = await loadNarrativeTemplateInfo(rdsConnectionParams, plan.id);
510
537
  // Fetch the research domain if one was specified
511
538
  const research_domain = project.dmptool_research_domain
512
539
  ? { name: project.dmptool_research_domain }
@@ -515,12 +542,12 @@ const buildDMPToolExtensions = async (plan, project, funding) => {
515
542
  let funderOpportunity = undefined;
516
543
  if (funding) {
517
544
  const projectId = {
518
- identifier: internalIdBase(project.id, plan.id),
545
+ identifier: internalIdBase(applicationName, project.id, plan.id),
519
546
  type: maDMPTypes_1.StandardIdentifierType.OTHER
520
547
  };
521
548
  const funderId = funding.uri === undefined
522
549
  ? {
523
- identifier: `${internalIdBase(project.id, plan.id)}.fundings.${funding.id}`,
550
+ identifier: `${internalIdBase(applicationName, project.id, plan.id)}.fundings.${funding.id}`,
524
551
  type: maDMPTypes_1.StandardIdentifierType.OTHER
525
552
  }
526
553
  : {
@@ -577,7 +604,7 @@ const buildDMPToolExtensions = async (plan, project, funding) => {
577
604
  }
578
605
  if (!(0, general_1.isNullOrUndefined)(narrative)) {
579
606
  extensions.narrative = {
580
- download_url: `https://${process.env.DOMAIN_NAME}/dmps/${plan.dmpId}/narrative`,
607
+ download_url: `https://${domainName}/dmps/${plan.dmpId}/narrative`,
581
608
  template: narrative
582
609
  };
583
610
  }
@@ -586,12 +613,13 @@ const buildDMPToolExtensions = async (plan, project, funding) => {
586
613
  /**
587
614
  * Builds the Project and Funding info for the RDA Common Standard
588
615
  *
616
+ * @param applicationName the name of the application/service
589
617
  * @param planId the Plan ID
590
618
  * @param project the Project information retrieve from the MySQL database
591
619
  * @param funding the Funding information retrieve from the MySQL database
592
620
  * @returns the Project and Funding info for the RDA Common Standard
593
621
  */
594
- const buildProject = (planId, project, funding) => {
622
+ const buildProject = (applicationName, planId, project, funding) => {
595
623
  var _a, _b, _c, _d, _e;
596
624
  if ((0, general_1.isNullOrUndefined)(project)) {
597
625
  return undefined;
@@ -611,7 +639,7 @@ const buildProject = (planId, project, funding) => {
611
639
  type: ((_b = (funding).uri) === null || _b === void 0 ? void 0 : _b.match(ROR_REGEX)) ? 'ror' : 'url'
612
640
  }
613
641
  : {
614
- identifier: `${internalIdBase(project.id, planId)}.fundings.${funding.id}`,
642
+ identifier: `${internalIdBase(applicationName, project.id, planId)}.fundings.${funding.id}`,
615
643
  type: 'other'
616
644
  };
617
645
  // The RDA Common Standard requires the funder name and status to be present
@@ -633,7 +661,7 @@ const buildProject = (planId, project, funding) => {
633
661
  start: (_d = project.startDate) !== null && _d !== void 0 ? _d : undefined,
634
662
  end: (_e = project.endDate) !== null && _e !== void 0 ? _e : undefined,
635
663
  project_id: [{
636
- identifier: internalIdBase(project.id, planId),
664
+ identifier: internalIdBase(applicationName, project.id, planId),
637
665
  type: 'other'
638
666
  }],
639
667
  funding: fundingObject
@@ -677,6 +705,7 @@ const byteSizeToBytes = (size) => {
677
705
  * Convert a @dmptool/types researchOutputTable answer row into an RDA Common
678
706
  * Standard Dataset object.
679
707
  *
708
+ * @param applicationName the name of the application/service
680
709
  * @param rowIdx the index of the answer row
681
710
  * @param row the answer row
682
711
  * @param projectId the ID of the project that the dataset belongs to
@@ -684,7 +713,7 @@ const byteSizeToBytes = (size) => {
684
713
  * @param language the language of the dataset (defaults to 'eng')
685
714
  * @returns a RDA Common Standard Dataset object
686
715
  */
687
- const buildDataset = (rowIdx, row, projectId, planId, language = 'eng') => {
716
+ const buildDataset = (applicationName, rowIdx, row, projectId, planId, language = 'eng') => {
688
717
  const title = findColumnById('title', row.columns);
689
718
  const desc = findColumnById('description', row.columns);
690
719
  const typ = findColumnById('type', row.columns);
@@ -761,7 +790,7 @@ const buildDataset = (rowIdx, row, projectId, planId, language = 'eng') => {
761
790
  type: (0, general_1.isNullOrUndefined)(typ) ? 'dataset' : typ.answer,
762
791
  description: (0, general_1.isNullOrUndefined)(desc) ? undefined : desc.answer,
763
792
  dataset_id: {
764
- identifier: `${internalIdBase(projectId, planId)}.outputs.${rowIdx + 1}`,
793
+ identifier: `${internalIdBase(applicationName, projectId, planId)}.outputs.${rowIdx + 1}`,
765
794
  type: 'other'
766
795
  },
767
796
  personal_data: (0, general_1.isNullOrUndefined)(flags) ?
@@ -800,11 +829,13 @@ const buildDataset = (rowIdx, row, projectId, planId, language = 'eng') => {
800
829
  * Validate the specified DMP metadata record against the RDA Common Standard
801
830
  * and DMP Tool extensions schema
802
831
  *
832
+ * @param logger the logger to use for logging
803
833
  * @param dmp The DMP metadata record to validate
804
834
  * @returns the DMP metadata record if it is valid
805
835
  * @throws DMPValidationError if the record is invalid with the error message(s)
806
836
  */
807
- const validateRDACommonStandard = (dmp) => {
837
+ const validateRDACommonStandard = (logger, dmp) => {
838
+ var _a, _b;
808
839
  const validationErrors = [];
809
840
  const validator = new jsonschema_1.Validator();
810
841
  // Validate against the RDA Common Standard schema
@@ -813,7 +844,9 @@ const validateRDACommonStandard = (dmp) => {
813
844
  validationErrors.push(...rdaResult.errors.map(e => `${e.path.join('.')} - ${e.message}`));
814
845
  }
815
846
  if (validationErrors.length > 0) {
816
- throw new DMPValidationError(`Invalid RDA Common Standard: ${validationErrors.join('; ')}`);
847
+ const msg = `Invalid RDA Common Standard: ${validationErrors.join('; ')}`;
848
+ logger.warn({ dmpId: (_b = (_a = dmp === null || dmp === void 0 ? void 0 : dmp.dmp) === null || _a === void 0 ? void 0 : _a.dmp_id) === null || _b === void 0 ? void 0 : _b.identifier }, msg);
849
+ throw new DMPValidationError(msg);
817
850
  }
818
851
  return dmp;
819
852
  };
@@ -822,11 +855,12 @@ exports.validateRDACommonStandard = validateRDACommonStandard;
822
855
  * Validate the specified DMP metadata record against the RDA Common Standard
823
856
  * and DMP Tool extensions schema
824
857
  *
858
+ * @param logger the logger to use for logging
825
859
  * @param dmp The DMP metadata record to validate
826
860
  * @returns the DMP metadata record if it is valid
827
861
  * @throws DMPValidationError if the record is invalid with the error message(s)
828
862
  */
829
- const validateDMPToolExtensions = (dmp) => {
863
+ const validateDMPToolExtensions = (logger, dmpId, dmp) => {
830
864
  var _a;
831
865
  const validationErrors = [];
832
866
  // Next validate against the DMP Tool extension schema
@@ -835,7 +869,9 @@ const validateDMPToolExtensions = (dmp) => {
835
869
  validationErrors.push(...extResult.error.issues.map(e => `${e.path.join('.')} - ${e.message}`));
836
870
  }
837
871
  if (validationErrors.length > 0) {
838
- throw new DMPValidationError(`Invalid DMP Tool extensions: ${validationErrors.join('; ')}`);
872
+ const msg = `Invalid DMP Tool extensions: ${validationErrors.join('; ')}`;
873
+ logger.warn({ dmpId }, msg);
874
+ throw new DMPValidationError(msg);
839
875
  }
840
876
  return dmp;
841
877
  };
@@ -877,48 +913,51 @@ const cleanRDACommonStandard = (plan, dmp) => {
877
913
  * - The `registered` indicates whether the DMP is published/registered with DataCite/EZID
878
914
  * - The `tombstoned` indicates that it was published/registered but is now removed
879
915
  *
916
+ * @param rdsConnectionParams the connection parameters for the RDS instance
917
+ * @param applicationName the name of the application/service
918
+ * @param domainName the domain name of the application/service website
880
919
  * @param planId the ID of the plan to generate the DMP for
920
+ * @param env The environment from EnvironmentEnum (defaults to EnvironmentEnum.DEV)
881
921
  * @returns a JSON representation of the DMP
882
922
  */
883
- async function planToDMPCommonStandard(planId) {
884
- if ((0, general_1.isNullOrUndefined)(process.env.ENV)) {
885
- throw new Error('ENV environment variable is not set');
886
- }
887
- if ((0, general_1.isNullOrUndefined)(process.env.DOMAIN_NAME)) {
888
- throw new Error('DOMAIN_NAME environment variable is not set');
889
- }
890
- if ((0, general_1.isNullOrUndefined)(process.env.APPLICATION_NAME)) {
891
- throw new Error('APPLICATION_NAME environment variable is not set');
923
+ async function planToDMPCommonStandard(rdsConnectionParams, applicationName, domainName, env = general_1.EnvironmentEnum.DEV, planId) {
924
+ if (!rdsConnectionParams || !applicationName || !domainName || !planId) {
925
+ throw new Error('Invalid arguments provided to planToDMPCommonStandard');
892
926
  }
893
927
  // Fetch the Plan data
894
- const plan = await loadPlanInfo(planId);
928
+ const plan = await loadPlanInfo(rdsConnectionParams, planId);
895
929
  if (plan === undefined) {
930
+ rdsConnectionParams.logger.error({ planId, applicationName, env }, 'Plan not found');
896
931
  throw new DMPValidationError(`Plan not found: ${planId}`);
897
932
  }
898
933
  if ((0, general_1.isNullOrUndefined)(plan.title)) {
934
+ rdsConnectionParams.logger.error({ planId, applicationName, env }, 'Plan title not found');
899
935
  throw new DMPValidationError(`Plan title not found for plan: ${planId}`);
900
936
  }
901
937
  if ((0, general_1.isNullOrUndefined)(plan.dmpId)) {
938
+ rdsConnectionParams.logger.error({ planId, applicationName, env }, 'Plan dmpId not found');
902
939
  throw new DMPValidationError(`DMP ID not found for plan: ${planId}`);
903
940
  }
904
941
  // Get the Project data
905
- const project = await loadProjectInfo(plan.projectId);
942
+ const project = await loadProjectInfo(rdsConnectionParams, plan.projectId);
906
943
  if (project === undefined || !project.title) {
944
+ rdsConnectionParams.logger.error({ planId, applicationName, env }, 'Project not found');
907
945
  throw new DMPValidationError(`Project not found: ${plan.projectId}`);
908
946
  }
909
947
  // Get all the plan members and determine the primary contact
910
- const members = plan.id ? await loadMemberInfo(plan.id) : [];
911
- const contact = await buildContact(plan, members);
948
+ const members = plan.id ? await loadMemberInfo(rdsConnectionParams, plan.id) : [];
949
+ const contact = await buildContact(rdsConnectionParams, env, plan, members);
912
950
  if (!contact) {
951
+ rdsConnectionParams.logger.error({ planId, applicationName, env }, 'Could not build primary contact');
913
952
  throw new DMPValidationError(`Could not establish a primary contact for plan: ${planId}`);
914
953
  }
915
954
  // Get all the funding and narrative info
916
- const datasets = await loadDatasetInfo(project.id, plan.id, plan.languageId);
955
+ const datasets = await loadDatasetInfo(rdsConnectionParams, applicationName, project.id, plan.id, plan.languageId);
917
956
  // We only allow one funding per plan at this time
918
- const fundings = await loadFundingInfo(plan.id);
957
+ const fundings = await loadFundingInfo(rdsConnectionParams, plan.id);
919
958
  const funding = fundings.length > 0 ? fundings[0] : undefined;
920
- const works = await loadRelatedWorksInfo(plan.projectId);
921
- const defaultRole = await loadDefaultMemberRole();
959
+ const works = await loadRelatedWorksInfo(rdsConnectionParams, plan.projectId);
960
+ const defaultRole = await loadDefaultMemberRole(rdsConnectionParams);
922
961
  // If the plan is registered, use the DOI as the identifier, otherwise convert to a URL
923
962
  const dmpId = plan.registered
924
963
  ? {
@@ -926,7 +965,7 @@ async function planToDMPCommonStandard(planId) {
926
965
  type: 'doi'
927
966
  }
928
967
  : {
929
- identifier: `https://${process.env.DOMAIN_NAME}/projects/${project.id}/dmp/${plan.id}`,
968
+ identifier: `https://${domainName}/projects/${project.id}/dmp/${plan.id}`,
930
969
  type: 'url'
931
970
  };
932
971
  // Examine the datasets to determine the status of ethical issues
@@ -958,8 +997,8 @@ async function planToDMPCommonStandard(planId) {
958
997
  dataset: datasets,
959
998
  },
960
999
  };
961
- const dmpProject = buildProject(plan.id, project, funding);
962
- const dmpContributor = buildContributors(plan.id, project.id, members, defaultRole !== null && defaultRole !== void 0 ? defaultRole : 'other');
1000
+ const dmpProject = buildProject(applicationName, plan.id, project, funding);
1001
+ const dmpContributor = buildContributors(applicationName, env, plan.id, project.id, members, defaultRole !== null && defaultRole !== void 0 ? defaultRole : 'other');
963
1002
  // Add the contributor, project and related identifier properties if they have values
964
1003
  if (!(0, general_1.isNullOrUndefined)(dmpProject)) {
965
1004
  dmp.dmp.project = [(0, general_1.removeNullAndUndefinedFromObject)(dmpProject)];
@@ -974,9 +1013,10 @@ async function planToDMPCommonStandard(planId) {
974
1013
  }
975
1014
  const cleaned = cleanRDACommonStandard(plan, dmp);
976
1015
  // Generate the DMP Tool extensions to the RDA Common Standard
977
- const extensions = await buildDMPToolExtensions(plan, project, funding);
1016
+ const extensions = await buildDMPToolExtensions(rdsConnectionParams, applicationName, domainName, plan, project, funding);
1017
+ rdsConnectionParams.logger.debug({ applicationName, domainName, planId, env, dmpId: plan.dmpId }, 'Generated maDMP metadata record');
978
1018
  // Return the combined DMP metadata record
979
1019
  return {
980
- dmp: Object.assign(Object.assign({}, (0, exports.validateRDACommonStandard)(cleaned).dmp), (0, exports.validateDMPToolExtensions)(extensions))
1020
+ dmp: Object.assign(Object.assign({}, (0, exports.validateRDACommonStandard)(rdsConnectionParams.logger, cleaned).dmp), (0, exports.validateDMPToolExtensions)(rdsConnectionParams.logger, plan.dmpId, extensions))
981
1021
  };
982
1022
  }
package/dist/rds.d.ts CHANGED
@@ -1,11 +1,21 @@
1
+ import { Logger } from 'pino';
2
+ export interface ConnectionParams {
3
+ logger: Logger;
4
+ host: string;
5
+ port: number;
6
+ user: string;
7
+ password: string;
8
+ database: string;
9
+ }
1
10
  /**
2
11
  * Function to run a SQL query against the MySQL database.
3
12
  *
4
13
  * @param query the SQL query to run
14
+ * @param connectionParams the connection parameters to use for the connection
5
15
  * @param params the parameters to use in the query
6
16
  * @returns the results of the query
7
17
  */
8
- export declare const queryTable: (query: string, params?: any[]) => Promise<{
18
+ export declare const queryTable: (connectionParams: ConnectionParams, query: string, params?: any[]) => Promise<{
9
19
  results: any[];
10
20
  fields: any[];
11
21
  }>;