From 9aa8adf31e55b3cc72ac3db04559bad407b06fea Mon Sep 17 00:00:00 2001 From: Austen Sorochak Date: Tue, 30 Jan 2024 15:39:35 -0800 Subject: [PATCH 01/15] update datacite to use parameterized config --- firebase-functions/functions/datacite.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/firebase-functions/functions/datacite.js b/firebase-functions/functions/datacite.js index 0b956e60..3c20e817 100644 --- a/firebase-functions/functions/datacite.js +++ b/firebase-functions/functions/datacite.js @@ -1,14 +1,16 @@ const baseUrl = "https://api.datacite.org/dois/"; -const { DATACITE_AUTH_HASH } = process.env; +// const { DATACITE_AUTH_HASH } = process.env; const functions = require("firebase-functions"); const axios = require("axios"); +const dataciteAuthHash = functions.config().DATACITE_AUTH_HASH; + exports.createDraftDoi = functions.https.onCall(async (record) => { try{ const url = `${baseUrl}`; const response = await axios.post(url, record, { headers: { - 'Authorization': `Basic ${DATACITE_AUTH_HASH}`, + 'Authorization': `Basic ${dataciteAuthHash}`, 'Content-Type': 'application/json', }, }); From f88d872b183eeaa3c1ed29f458166906eb6d3df4 Mon Sep 17 00:00:00 2001 From: Austen Sorochak Date: Thu, 1 Feb 2024 13:07:17 -0800 Subject: [PATCH 02/15] update to use parameterized config --- firebase-functions/functions/datacite.js | 10 +++++----- firebase-functions/functions/issue.js | 5 +++-- firebase-functions/functions/notify.js | 6 ++++-- firebase-functions/functions/translate.js | 11 +++++++---- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/firebase-functions/functions/datacite.js b/firebase-functions/functions/datacite.js index 3c20e817..be130951 100644 --- a/firebase-functions/functions/datacite.js +++ b/firebase-functions/functions/datacite.js @@ -1,16 +1,16 @@ const baseUrl = "https://api.datacite.org/dois/"; -// const { DATACITE_AUTH_HASH } = process.env; const functions = require("firebase-functions"); +const { defineString } = require('firebase-functions/params'); const axios = require("axios"); -const dataciteAuthHash = functions.config().DATACITE_AUTH_HASH; +const dataciteAuthHash = defineString('DATACITE_AUTH_HASH'); exports.createDraftDoi = functions.https.onCall(async (record) => { try{ const url = `${baseUrl}`; const response = await axios.post(url, record, { headers: { - 'Authorization': `Basic ${dataciteAuthHash}`, + 'Authorization': `Basic ${dataciteAuthHash.value()}`, 'Content-Type': 'application/json', }, }); @@ -53,7 +53,7 @@ exports.updateDraftDoi = functions.https.onCall(async (data) => { const url = `${baseUrl}${data.doi}/`; const response = await axios.put(url, data.data, { headers: { - 'Authorization': `Basic ${DATACITE_AUTH_HASH}`, + 'Authorization': `Basic ${dataciteAuthHash.value()}`, 'Content-Type': "application/json", }, }); @@ -98,7 +98,7 @@ exports.deleteDraftDoi = functions.https.onCall(async (draftDoi) => { try { const url = `${baseUrl}${draftDoi}/`; const response = await axios.delete(url, { - headers: { 'Authorization': `Basic ${DATACITE_AUTH_HASH}` }, + headers: { 'Authorization': `Basic ${dataciteAuthHash.value()}` }, }); return response.status; } catch (err) { diff --git a/firebase-functions/functions/issue.js b/firebase-functions/functions/issue.js index a9f6a9b6..b2634c5b 100644 --- a/firebase-functions/functions/issue.js +++ b/firebase-functions/functions/issue.js @@ -1,7 +1,8 @@ const { Octokit } = require("octokit"); const fs = require("fs"); +const { defineString } = require('firebase-functions/params'); -const { GITHUB_AUTH } = process.env; +const githubAuth = defineString('GITHUB_AUTH'); function readIssueText(filename) { try { return fs.readFileSync(filename, "utf8"); @@ -13,7 +14,7 @@ function readIssueText(filename) { async function createIssue(title, url) { const octokit = new Octokit({ - auth: GITHUB_AUTH, + auth: githubAuth.value(), }); const issueText = readIssueText("dataset-name.md"); const input = { diff --git a/firebase-functions/functions/notify.js b/firebase-functions/functions/notify.js index c36546d6..a5a3a841 100644 --- a/firebase-functions/functions/notify.js +++ b/firebase-functions/functions/notify.js @@ -1,5 +1,6 @@ const functions = require("firebase-functions"); const admin = require("firebase-admin"); +const { defineString } = require('firebase-functions/params'); const nodemailer = require("nodemailer"); const { mailOptionsReviewer, mailOptionsAuthor } = require("./mailoutText"); const createIssue = require("./issue"); @@ -7,11 +8,12 @@ const createIssue = require("./issue"); /** * Here we're using Gmail to send */ -const { GMAIL_USER, GMAIL_PASS } = process.env; +const gmailUser = defineString('GMAIL_USER'); +const gmailPass = defineString('GMAIL_PASS'); const transporter = nodemailer.createTransport({ service: "gmail", - auth: { user: GMAIL_USER, pass: GMAIL_PASS }, + auth: { user: gmailUser.value(), pass: gmailPass.value() }, }); /* Email the reviewers for the region when a form is submitted for review diff --git a/firebase-functions/functions/translate.js b/firebase-functions/functions/translate.js index 951418e7..71067f89 100644 --- a/firebase-functions/functions/translate.js +++ b/firebase-functions/functions/translate.js @@ -1,12 +1,15 @@ const functions = require("firebase-functions"); +const { defineString } = require('firebase-functions/params'); const AWS = require("aws-sdk"); -const { AWS_REGION, AWS_ACCESSKEYID, AWS_SECRETACCESSKEY } = process.env; +const awsRegion = defineString('AWS_REGION'); +const awsAccessKeyId = defineString('AWS_ACCESSKEYID'); +const awsSecretAccessKey = defineString('AWS_SECRETACCESSKEY'); const awsAuth = { - region: AWS_REGION, - accessKeyId: AWS_ACCESSKEYID, - secretAccessKey: AWS_SECRETACCESSKEY, + region: awsRegion.value(), + accessKeyId: awsAccessKeyId.value(), + secretAccessKey: awsSecretAccessKey.value(), }; AWS.config = new AWS.Config(awsAuth); From c28e6bedad657320b8b5783d9702fd0277af3d5c Mon Sep 17 00:00:00 2001 From: Austen Sorochak Date: Thu, 1 Feb 2024 13:48:56 -0800 Subject: [PATCH 03/15] update for deployment through both local development and GH Actions --- firebase-functions/functions/datacite.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/firebase-functions/functions/datacite.js b/firebase-functions/functions/datacite.js index be130951..aee86a42 100644 --- a/firebase-functions/functions/datacite.js +++ b/firebase-functions/functions/datacite.js @@ -5,12 +5,22 @@ const axios = require("axios"); const dataciteAuthHash = defineString('DATACITE_AUTH_HASH'); +// Helper function to decide between GitHub Actions env var and Firebase parameter config +const getDataciteAuthHash = () => { + // Check if the environment variable is set (e.g., in GitHub Actions) + if (process.env.DATACITE_AUTH_HASH) { + return process.env.DATACITE_AUTH_HASH; + } + // Otherwise, use the Firebase parameter (e.g., in local development) + return dataciteAuthParam.value(); +} + exports.createDraftDoi = functions.https.onCall(async (record) => { try{ const url = `${baseUrl}`; const response = await axios.post(url, record, { headers: { - 'Authorization': `Basic ${dataciteAuthHash.value()}`, + 'Authorization': `Basic ${getDataciteAuthHash()}`, 'Content-Type': 'application/json', }, }); @@ -53,7 +63,7 @@ exports.updateDraftDoi = functions.https.onCall(async (data) => { const url = `${baseUrl}${data.doi}/`; const response = await axios.put(url, data.data, { headers: { - 'Authorization': `Basic ${dataciteAuthHash.value()}`, + 'Authorization': `Basic ${getDataciteAuthHash()}`, 'Content-Type': "application/json", }, }); @@ -98,7 +108,7 @@ exports.deleteDraftDoi = functions.https.onCall(async (draftDoi) => { try { const url = `${baseUrl}${draftDoi}/`; const response = await axios.delete(url, { - headers: { 'Authorization': `Basic ${dataciteAuthHash.value()}` }, + headers: { 'Authorization': `Basic ${getDataciteAuthHash()}` }, }); return response.status; } catch (err) { From 8c7b3b78860f317ce5794e0274ebf14014445795 Mon Sep 17 00:00:00 2001 From: Austen Sorochak Date: Thu, 1 Feb 2024 16:40:24 -0800 Subject: [PATCH 04/15] add util function --- firebase-functions/functions/datacite.js | 22 +++++---------------- firebase-functions/functions/issue.js | 6 +++--- firebase-functions/functions/notify.js | 8 ++++---- firebase-functions/functions/serverUtils.js | 16 +++++++++++++++ firebase-functions/functions/translate.js | 12 ++++------- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/firebase-functions/functions/datacite.js b/firebase-functions/functions/datacite.js index aee86a42..f2d88ff2 100644 --- a/firebase-functions/functions/datacite.js +++ b/firebase-functions/functions/datacite.js @@ -1,26 +1,14 @@ const baseUrl = "https://api.datacite.org/dois/"; const functions = require("firebase-functions"); -const { defineString } = require('firebase-functions/params'); const axios = require("axios"); - -const dataciteAuthHash = defineString('DATACITE_AUTH_HASH'); - -// Helper function to decide between GitHub Actions env var and Firebase parameter config -const getDataciteAuthHash = () => { - // Check if the environment variable is set (e.g., in GitHub Actions) - if (process.env.DATACITE_AUTH_HASH) { - return process.env.DATACITE_AUTH_HASH; - } - // Otherwise, use the Firebase parameter (e.g., in local development) - return dataciteAuthParam.value(); -} +const { getConfigVar } = require('.serverUtils'); exports.createDraftDoi = functions.https.onCall(async (record) => { try{ const url = `${baseUrl}`; const response = await axios.post(url, record, { headers: { - 'Authorization': `Basic ${getDataciteAuthHash()}`, + 'Authorization': `Basic ${getConfigVar('DATACITE_AUTH_HASH')}`, 'Content-Type': 'application/json', }, }); @@ -63,7 +51,7 @@ exports.updateDraftDoi = functions.https.onCall(async (data) => { const url = `${baseUrl}${data.doi}/`; const response = await axios.put(url, data.data, { headers: { - 'Authorization': `Basic ${getDataciteAuthHash()}`, + 'Authorization': `Basic ${getConfigVar('DATACITE_AUTH_HASH')}`, 'Content-Type': "application/json", }, }); @@ -108,7 +96,7 @@ exports.deleteDraftDoi = functions.https.onCall(async (draftDoi) => { try { const url = `${baseUrl}${draftDoi}/`; const response = await axios.delete(url, { - headers: { 'Authorization': `Basic ${getDataciteAuthHash()}` }, + headers: { 'Authorization': `Basic ${getConfigVar('DATACITE_AUTH_HASH')}` }, }); return response.status; } catch (err) { @@ -148,7 +136,7 @@ exports.getDoiStatus = functions.https.onCall(async (data) => { // TODO: limit response to just the state field. elasticsearch query syntax? const response = await axios.get(url, { headers: { - 'Authorization': `Basic ${DATACITE_AUTH_HASH}` + 'Authorization': `Basic ${getConfigVar('DATACITE_AUTH_HASH')}` }, }); return response.data.data.attributes.state; diff --git a/firebase-functions/functions/issue.js b/firebase-functions/functions/issue.js index b2634c5b..ad2e85ab 100644 --- a/firebase-functions/functions/issue.js +++ b/firebase-functions/functions/issue.js @@ -1,8 +1,8 @@ const { Octokit } = require("octokit"); const fs = require("fs"); -const { defineString } = require('firebase-functions/params'); +const { getConfigVar } = require('.serverUtils'); + -const githubAuth = defineString('GITHUB_AUTH'); function readIssueText(filename) { try { return fs.readFileSync(filename, "utf8"); @@ -14,7 +14,7 @@ function readIssueText(filename) { async function createIssue(title, url) { const octokit = new Octokit({ - auth: githubAuth.value(), + auth: getConfigVar('GITHUB_AUTH'), }); const issueText = readIssueText("dataset-name.md"); const input = { diff --git a/firebase-functions/functions/notify.js b/firebase-functions/functions/notify.js index a5a3a841..f7bd5a5c 100644 --- a/firebase-functions/functions/notify.js +++ b/firebase-functions/functions/notify.js @@ -1,19 +1,19 @@ const functions = require("firebase-functions"); const admin = require("firebase-admin"); -const { defineString } = require('firebase-functions/params'); const nodemailer = require("nodemailer"); const { mailOptionsReviewer, mailOptionsAuthor } = require("./mailoutText"); const createIssue = require("./issue"); +const { getConfigVar } = require('.serverUtils'); /** * Here we're using Gmail to send */ -const gmailUser = defineString('GMAIL_USER'); -const gmailPass = defineString('GMAIL_PASS'); +// const gmailUser = defineString('GMAIL_USER'); +// const gmailPass = defineString('GMAIL_PASS'); const transporter = nodemailer.createTransport({ service: "gmail", - auth: { user: gmailUser.value(), pass: gmailPass.value() }, + auth: { user: getConfigVar('GMAIL_USER'), pass: getConfigVar('GMAIL_PASS') }, }); /* Email the reviewers for the region when a form is submitted for review diff --git a/firebase-functions/functions/serverUtils.js b/firebase-functions/functions/serverUtils.js index 7ba0676e..535f7a58 100644 --- a/firebase-functions/functions/serverUtils.js +++ b/firebase-functions/functions/serverUtils.js @@ -1,6 +1,22 @@ const functions = require("firebase-functions"); +const { defineString } = require('firebase-functions/params'); const fetch = require('node-fetch'); +// Helper function to decide between GitHub Actions secret and Firebase parameter config +export const getConfigVar = (paramName) => { + + // Define the Firebase parameter using defineString + const firebaseParam = defineString(paramName); + + // Check if the environment variable is set + if (process.env[paramName]) { + return process.env[paramName]; + } + + // Otherwise fallback to the Firebase parameter + return firebaseParam.value(); + } + // Function to check if a given URL is active exports.checkURLActive = functions.https.onCall(async (data) => { let url = data; diff --git a/firebase-functions/functions/translate.js b/firebase-functions/functions/translate.js index 71067f89..379f704b 100644 --- a/firebase-functions/functions/translate.js +++ b/firebase-functions/functions/translate.js @@ -1,15 +1,11 @@ const functions = require("firebase-functions"); -const { defineString } = require('firebase-functions/params'); const AWS = require("aws-sdk"); - -const awsRegion = defineString('AWS_REGION'); -const awsAccessKeyId = defineString('AWS_ACCESSKEYID'); -const awsSecretAccessKey = defineString('AWS_SECRETACCESSKEY'); +const { getConfigVar } = require('.serverUtils'); const awsAuth = { - region: awsRegion.value(), - accessKeyId: awsAccessKeyId.value(), - secretAccessKey: awsSecretAccessKey.value(), + region: getConfigVar('AWS_REGION'), + accessKeyId: getConfigVar('AWS_ACCESSKEYID'), + secretAccessKey: getConfigVar('AWS_SECRETACCESSKEY'), }; AWS.config = new AWS.Config(awsAuth); From 9db3cddb932b6fdaf8ed31889f26b5c887de4b8c Mon Sep 17 00:00:00 2001 From: Austen Sorochak Date: Thu, 1 Feb 2024 17:58:37 -0800 Subject: [PATCH 05/15] use env and parameters config --- firebase-functions/functions/datacite.js | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/firebase-functions/functions/datacite.js b/firebase-functions/functions/datacite.js index be130951..9bd935b8 100644 --- a/firebase-functions/functions/datacite.js +++ b/firebase-functions/functions/datacite.js @@ -6,11 +6,14 @@ const axios = require("axios"); const dataciteAuthHash = defineString('DATACITE_AUTH_HASH'); exports.createDraftDoi = functions.https.onCall(async (record) => { + + const dataciteCred = process.env.DATACITE_AUTH_HASH || dataciteAuthHash.value() + try{ const url = `${baseUrl}`; const response = await axios.post(url, record, { headers: { - 'Authorization': `Basic ${dataciteAuthHash.value()}`, + 'Authorization': `Basic ${dataciteCred}`, 'Content-Type': 'application/json', }, }); @@ -49,11 +52,14 @@ exports.createDraftDoi = functions.https.onCall(async (record) => { }); exports.updateDraftDoi = functions.https.onCall(async (data) => { + + const dataciteCred = process.env.DATACITE_AUTH_HASH || dataciteAuthHash.value() + try { const url = `${baseUrl}${data.doi}/`; const response = await axios.put(url, data.data, { headers: { - 'Authorization': `Basic ${dataciteAuthHash.value()}`, + 'Authorization': `Basic ${dataciteCred}`, 'Content-Type': "application/json", }, }); @@ -95,10 +101,13 @@ exports.updateDraftDoi = functions.https.onCall(async (data) => { }); exports.deleteDraftDoi = functions.https.onCall(async (draftDoi) => { + + const dataciteCred = process.env.DATACITE_AUTH_HASH || dataciteAuthHash.value() + try { const url = `${baseUrl}${draftDoi}/`; const response = await axios.delete(url, { - headers: { 'Authorization': `Basic ${dataciteAuthHash.value()}` }, + headers: { 'Authorization': `Basic ${dataciteCred}` }, }); return response.status; } catch (err) { @@ -133,12 +142,15 @@ exports.deleteDraftDoi = functions.https.onCall(async (draftDoi) => { }); exports.getDoiStatus = functions.https.onCall(async (data) => { + + const dataciteCred = process.env.DATACITE_AUTH_HASH || dataciteAuthHash.value() + try { const url = `${baseUrl}${data.doi}/`; // TODO: limit response to just the state field. elasticsearch query syntax? const response = await axios.get(url, { headers: { - 'Authorization': `Basic ${DATACITE_AUTH_HASH}` + 'Authorization': `Basic ${dataciteCred}` }, }); return response.data.data.attributes.state; From 9121d84254a562eecfe64ad0c95d6eb81d4f466a Mon Sep 17 00:00:00 2001 From: Austen Sorochak Date: Thu, 1 Feb 2024 18:03:54 -0800 Subject: [PATCH 06/15] update workflow --- .github/workflows/firebase-deploy.yaml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/workflows/firebase-deploy.yaml b/.github/workflows/firebase-deploy.yaml index 081f3a41..52c724a4 100644 --- a/.github/workflows/firebase-deploy.yaml +++ b/.github/workflows/firebase-deploy.yaml @@ -25,13 +25,12 @@ jobs: with: args: deploy --only functions env: - FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }} - GMAIL_USER: ${{ secrets.GMAIL_USER }} - GMAIL_PASS: ${{ secrets.GMAIL_PASS }} - DATACITE_USER: ${{ secrets.DATACITE_USER }} - DATACITE_PASS: ${{ secrets.DATACITE_PASS }} - AWS_REGION: ${{ secrets.AWS_REGION }} - AWS_ACCESSKEYID: ${{ secrets.AWS_ACCESSKEYID }} - AWS_SECRETACCESSKEY: ${{ secrets.AWS_SECRETACCESSKEY }} - GITHUB_AUTH: ${{ secrets.ISSUE_CREATOR_PAT }} + # FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }} + # GMAIL_USER: ${{ secrets.GMAIL_USER }} + # GMAIL_PASS: ${{ secrets.GMAIL_PASS }} + DATACITE_AUTH_HASH: ${{ secrets.DATACITE_AUTH_HASH }} + # AWS_REGION: ${{ secrets.AWS_REGION }} + # AWS_ACCESSKEYID: ${{ secrets.AWS_ACCESSKEYID }} + # AWS_SECRETACCESSKEY: ${{ secrets.AWS_SECRETACCESSKEY }} + # GITHUB_AUTH: ${{ secrets.ISSUE_CREATOR_PAT }} PROJECT_PATH: ./firebase-functions From 1a5af2cec3776cfab4f8c85677111f56d9f3b45e Mon Sep 17 00:00:00 2001 From: Austen Sorochak Date: Thu, 1 Feb 2024 18:08:18 -0800 Subject: [PATCH 07/15] tweak workflow --- .github/workflows/firebase-deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/firebase-deploy.yaml b/.github/workflows/firebase-deploy.yaml index 52c724a4..590b636b 100644 --- a/.github/workflows/firebase-deploy.yaml +++ b/.github/workflows/firebase-deploy.yaml @@ -25,7 +25,7 @@ jobs: with: args: deploy --only functions env: - # FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }} + FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }} # GMAIL_USER: ${{ secrets.GMAIL_USER }} # GMAIL_PASS: ${{ secrets.GMAIL_PASS }} DATACITE_AUTH_HASH: ${{ secrets.DATACITE_AUTH_HASH }} From 3b2871909023397ab4a312db65c4fdc1f23f90f4 Mon Sep 17 00:00:00 2001 From: Austen Sorochak Date: Thu, 1 Feb 2024 18:17:34 -0800 Subject: [PATCH 08/15] update datacite --- firebase-functions/functions/datacite.js | 66 ++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 5 deletions(-) diff --git a/firebase-functions/functions/datacite.js b/firebase-functions/functions/datacite.js index ea39d162..9bd935b8 100644 --- a/firebase-functions/functions/datacite.js +++ b/firebase-functions/functions/datacite.js @@ -1,14 +1,19 @@ const baseUrl = "https://api.datacite.org/dois/"; -const { DATACITE_AUTH_HASH } = process.env; const functions = require("firebase-functions"); +const { defineString } = require('firebase-functions/params'); const axios = require("axios"); +const dataciteAuthHash = defineString('DATACITE_AUTH_HASH'); + exports.createDraftDoi = functions.https.onCall(async (record) => { + + const dataciteCred = process.env.DATACITE_AUTH_HASH || dataciteAuthHash.value() + try{ const url = `${baseUrl}`; const response = await axios.post(url, record, { headers: { - 'Authorization': `Basic ${DATACITE_AUTH_HASH}`, + 'Authorization': `Basic ${dataciteCred}`, 'Content-Type': 'application/json', }, }); @@ -47,11 +52,14 @@ exports.createDraftDoi = functions.https.onCall(async (record) => { }); exports.updateDraftDoi = functions.https.onCall(async (data) => { - try{ + + const dataciteCred = process.env.DATACITE_AUTH_HASH || dataciteAuthHash.value() + + try { const url = `${baseUrl}${data.doi}/`; const response = await axios.put(url, data.data, { headers: { - 'Authorization': `Basic ${DATACITE_AUTH_HASH}`, + 'Authorization': `Basic ${dataciteCred}`, 'Content-Type': "application/json", }, }); @@ -93,10 +101,13 @@ exports.updateDraftDoi = functions.https.onCall(async (data) => { }); exports.deleteDraftDoi = functions.https.onCall(async (draftDoi) => { + + const dataciteCred = process.env.DATACITE_AUTH_HASH || dataciteAuthHash.value() + try { const url = `${baseUrl}${draftDoi}/`; const response = await axios.delete(url, { - headers: { 'Authorization': `Basic ${DATACITE_AUTH_HASH}` }, + headers: { 'Authorization': `Basic ${dataciteCred}` }, }); return response.status; } catch (err) { @@ -129,3 +140,48 @@ exports.deleteDraftDoi = functions.https.onCall(async (draftDoi) => { throw new functions.https.HttpsError('unknown',errMessage); } }); + +exports.getDoiStatus = functions.https.onCall(async (data) => { + + const dataciteCred = process.env.DATACITE_AUTH_HASH || dataciteAuthHash.value() + + try { + const url = `${baseUrl}${data.doi}/`; + // TODO: limit response to just the state field. elasticsearch query syntax? + const response = await axios.get(url, { + headers: { + 'Authorization': `Basic ${dataciteCred}` + }, + }); + return response.data.data.attributes.state; + } catch (err) { + // if the error is a 401, throw a HttpsError with the code 'unauthenticated' + if (err.response && err.response.status === 401) { + throw new functions.https.HttpsError( + 'unauthenticated', + 'Error from DataCite API: Unauthorized. Please check your API credentials.' + ); + } + // if the error is a 404, throw a HttpsError with the code 'not-found' + if (err.response && err.response.status === 404) { + if (data.doi.startsWith(`${data.prefix}/`)) { + return 'not found' + } + return 'unknown' + } + // initialize a default error message + let errMessage = 'An error occurred while fetching the DOI.'; + + // if there is an error response from DataCite, include the status and statusText from the API error + // if the error doesn't have a response, include the error message + if (err.response) { + errMessage = `from DataCite API: ${err.response.status} - ${err.response.statusText}`; + } else if (err.message) { + errMessage = err.message; + } + + // throw a default HttpsError with the code 'unknown' and the error message + throw new functions.https.HttpsError('unknown', errMessage); + } + +}); From c9d6c89cef6d501a1c0c5c9f6414e579eb20f7b3 Mon Sep 17 00:00:00 2001 From: Austen Sorochak Date: Thu, 1 Feb 2024 18:18:03 -0800 Subject: [PATCH 09/15] update workflow --- .github/workflows/firebase-deploy.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/firebase-deploy.yaml b/.github/workflows/firebase-deploy.yaml index 081f3a41..a14a4aeb 100644 --- a/.github/workflows/firebase-deploy.yaml +++ b/.github/workflows/firebase-deploy.yaml @@ -28,8 +28,7 @@ jobs: FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }} GMAIL_USER: ${{ secrets.GMAIL_USER }} GMAIL_PASS: ${{ secrets.GMAIL_PASS }} - DATACITE_USER: ${{ secrets.DATACITE_USER }} - DATACITE_PASS: ${{ secrets.DATACITE_PASS }} + DATACITE_AUTH_HASH: ${{ secrets.DATACITE_AUTH_HASH }} AWS_REGION: ${{ secrets.AWS_REGION }} AWS_ACCESSKEYID: ${{ secrets.AWS_ACCESSKEYID }} AWS_SECRETACCESSKEY: ${{ secrets.AWS_SECRETACCESSKEY }} From 2265c825359ca14c88a538703d74a8f0913f7bbd Mon Sep 17 00:00:00 2001 From: Austen Sorochak Date: Fri, 2 Feb 2024 11:01:13 -0800 Subject: [PATCH 10/15] create .env file in workflow --- .github/workflows/firebase-deploy.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/firebase-deploy.yaml b/.github/workflows/firebase-deploy.yaml index a14a4aeb..51b32786 100644 --- a/.github/workflows/firebase-deploy.yaml +++ b/.github/workflows/firebase-deploy.yaml @@ -20,6 +20,17 @@ jobs: - name: Install Dependencies run: npm ci working-directory: firebase-functions/functions + - name: Create .env file + run: | + echo "FIREBASE_TOKEN=${{ secrets.FIREBASE_TOKEN }}" > .env + echo "GMAIL_USER=${{ secrets.GMAIL_USER }}" >> .env + echo "GMAIL_PASS=${{ secrets.GMAIL_PASS }}" >> .env + echo "DATACITE_AUTH_HASH=${{ secrets.DATACITE_AUTH_HASH }}" >> .env + echo "AWS_REGION=${{ secrets.AWS_REGION }}" >> .env + echo "AWS_ACCESSKEYID=${{ secrets.AWS_ACCESSKEYID }}" >> .env + echo "AWS_SECRETACCESSKEY=${{ secrets.AWS_SECRETACCESSKEY }}" >> .env + echo "GITHUB_AUTH=${{ secrets.ISSUE_CREATOR_PAT }}" >> .env + working-directory: firebase-functions/functions - name: Deploy to Firebase uses: w9jds/firebase-action@master with: From 424dd1a15031e650c8cf8bc5bc54f4fd4c10f0dd Mon Sep 17 00:00:00 2001 From: Austen Sorochak Date: Fri, 2 Feb 2024 11:08:37 -0800 Subject: [PATCH 11/15] remove FIREBASE_TOKEN --- .github/workflows/firebase-deploy.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/firebase-deploy.yaml b/.github/workflows/firebase-deploy.yaml index 51b32786..1138206f 100644 --- a/.github/workflows/firebase-deploy.yaml +++ b/.github/workflows/firebase-deploy.yaml @@ -22,7 +22,6 @@ jobs: working-directory: firebase-functions/functions - name: Create .env file run: | - echo "FIREBASE_TOKEN=${{ secrets.FIREBASE_TOKEN }}" > .env echo "GMAIL_USER=${{ secrets.GMAIL_USER }}" >> .env echo "GMAIL_PASS=${{ secrets.GMAIL_PASS }}" >> .env echo "DATACITE_AUTH_HASH=${{ secrets.DATACITE_AUTH_HASH }}" >> .env From f1241669263a5942ea87c5d8cbf5ffe6609c25a2 Mon Sep 17 00:00:00 2001 From: Austen Sorochak Date: Fri, 2 Feb 2024 11:30:32 -0800 Subject: [PATCH 12/15] update for both env vars and params config --- firebase-functions/functions/issue.js | 4 +++- firebase-functions/functions/notify.js | 5 ++++- firebase-functions/functions/translate.js | 10 +++++++--- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/firebase-functions/functions/issue.js b/firebase-functions/functions/issue.js index b2634c5b..0c271eb0 100644 --- a/firebase-functions/functions/issue.js +++ b/firebase-functions/functions/issue.js @@ -3,6 +3,8 @@ const fs = require("fs"); const { defineString } = require('firebase-functions/params'); const githubAuth = defineString('GITHUB_AUTH'); +const githubAuthCred = process.env.GITHUB_AUTH || githubAuth.value() + function readIssueText(filename) { try { return fs.readFileSync(filename, "utf8"); @@ -14,7 +16,7 @@ function readIssueText(filename) { async function createIssue(title, url) { const octokit = new Octokit({ - auth: githubAuth.value(), + auth: githubAuthCred, }); const issueText = readIssueText("dataset-name.md"); const input = { diff --git a/firebase-functions/functions/notify.js b/firebase-functions/functions/notify.js index a5a3a841..16812d8a 100644 --- a/firebase-functions/functions/notify.js +++ b/firebase-functions/functions/notify.js @@ -11,9 +11,12 @@ const createIssue = require("./issue"); const gmailUser = defineString('GMAIL_USER'); const gmailPass = defineString('GMAIL_PASS'); +const gmailUserCred = process.env.GMAIL_USER || gmailUser.value() +const gmailPassCred = process.env.GMAIL_PASS || gmailPass.value() + const transporter = nodemailer.createTransport({ service: "gmail", - auth: { user: gmailUser.value(), pass: gmailPass.value() }, + auth: { user: gmailUserCred, pass: gmailPassCred }, }); /* Email the reviewers for the region when a form is submitted for review diff --git a/firebase-functions/functions/translate.js b/firebase-functions/functions/translate.js index 71067f89..7d98e716 100644 --- a/firebase-functions/functions/translate.js +++ b/firebase-functions/functions/translate.js @@ -6,10 +6,14 @@ const awsRegion = defineString('AWS_REGION'); const awsAccessKeyId = defineString('AWS_ACCESSKEYID'); const awsSecretAccessKey = defineString('AWS_SECRETACCESSKEY'); +const awsRegionCred = process.env.AWS_REGION || awsRegion.value() +const awsAccessKeyIdCred = process.env.AWS_ACCESSKEYID || awsAccessKeyId.value() +const awsSecretAccessKeyCred = process.env.AWS_SECRETACCESSKEY || awsSecretAccessKey.value() + const awsAuth = { - region: awsRegion.value(), - accessKeyId: awsAccessKeyId.value(), - secretAccessKey: awsSecretAccessKey.value(), + region: awsRegionCred, + accessKeyId: awsAccessKeyIdCred, + secretAccessKey: awsSecretAccessKeyCred, }; AWS.config = new AWS.Config(awsAuth); From 9271b20b1c14884020489a17fed6cec58fa9cdc6 Mon Sep 17 00:00:00 2001 From: Austen Sorochak Date: Fri, 2 Feb 2024 11:37:27 -0800 Subject: [PATCH 13/15] test --- firebase-functions/functions/datacite.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firebase-functions/functions/datacite.js b/firebase-functions/functions/datacite.js index 9bd935b8..23b37b5d 100644 --- a/firebase-functions/functions/datacite.js +++ b/firebase-functions/functions/datacite.js @@ -7,13 +7,13 @@ const dataciteAuthHash = defineString('DATACITE_AUTH_HASH'); exports.createDraftDoi = functions.https.onCall(async (record) => { - const dataciteCred = process.env.DATACITE_AUTH_HASH || dataciteAuthHash.value() + // const dataciteCred = process.env.DATACITE_AUTH_HASH || dataciteAuthHash.value() try{ const url = `${baseUrl}`; const response = await axios.post(url, record, { headers: { - 'Authorization': `Basic ${dataciteCred}`, + 'Authorization': `Basic ${dataciteAuthHash}`, 'Content-Type': 'application/json', }, }); From acbe9ebfc5bf59b71d9dca129f69cc9f80d80b8c Mon Sep 17 00:00:00 2001 From: Austen Sorochak Date: Fri, 2 Feb 2024 11:54:44 -0800 Subject: [PATCH 14/15] update datacite --- firebase-functions/functions/datacite.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/firebase-functions/functions/datacite.js b/firebase-functions/functions/datacite.js index 23b37b5d..d1d0cdf6 100644 --- a/firebase-functions/functions/datacite.js +++ b/firebase-functions/functions/datacite.js @@ -6,14 +6,15 @@ const axios = require("axios"); const dataciteAuthHash = defineString('DATACITE_AUTH_HASH'); exports.createDraftDoi = functions.https.onCall(async (record) => { - - // const dataciteCred = process.env.DATACITE_AUTH_HASH || dataciteAuthHash.value() + // Fallback to process.env.DATACITE_AUTH_HASH for local dev or deployment-specific configurations, + // otherwise use Firebase's parameterized configuration at runtime. + const dataciteCred = process.env.DATACITE_AUTH_HASH || dataciteAuthHash.value() try{ const url = `${baseUrl}`; const response = await axios.post(url, record, { headers: { - 'Authorization': `Basic ${dataciteAuthHash}`, + 'Authorization': `Basic ${dataciteCred}`, 'Content-Type': 'application/json', }, }); From a7b0d9e5be4b8eec1272855b4add1fe6515b8374 Mon Sep 17 00:00:00 2001 From: Austen Sorochak Date: Fri, 2 Feb 2024 15:34:28 -0800 Subject: [PATCH 15/15] update Readme for Deployment and Configuration of Firebase Functions --- README.md | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/README.md b/README.md index c4224315..5a67792e 100644 --- a/README.md +++ b/README.md @@ -31,3 +31,54 @@ Pushes to master automatically deploy to