Skip to content

Commit

Permalink
Merge pull request #530 from brown-ccv/revert-516-add-commander
Browse files Browse the repository at this point in the history
Revert "add: commander to optionally provide delete or download along with st…"
  • Loading branch information
YUUU23 authored Aug 14, 2024
2 parents a7df3ac + 617f371 commit 1fb344c
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 107 deletions.
104 changes: 21 additions & 83 deletions cli.mjs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { checkbox, confirm, expand, input, select } from "@inquirer/prompts";
import fsExtra from "fs-extra";

// TODO @brown-ccv #183: Upgrade to modular SDK instead of compat
import { cert, initializeApp } from "firebase-admin/app";
import { getFirestore } from "firebase-admin/firestore";
import { Command } from "commander";
import { cert, initializeApp } from "firebase-admin/app"; // eslint-disable-line import/no-unresolved
import { getFirestore } from "firebase-admin/firestore"; // eslint-disable-line import/no-unresolved

/** -------------------- GLOBALS -------------------- */

Expand All @@ -19,73 +17,16 @@ let OUTPUT_ROOT; // The root in which data is saved
const INVALID_ACTION_ERROR = new Error("Invalid action: " + ACTION);
const INVALID_DEPLOYMENT_ERROR = new Error("Invalid deployment: " + DEPLOYMENT);

/** -------------------- COMMANDER -------------------- */
const commander = new Command();
// default: [download | delete ] not provided, run main() as usual continuing with prompting
commander.action(() => {});

// download: optional argument studyID and participantID skips relative prompts
commander
.command(`download`)
.argument(`[studyID]`)
.argument(`[participantID]`)
.description(`Download experiment data from Firebase provided study ID and participant ID`)
.action((studyID, participantID) => {
ACTION = "download";
STUDY_ID = studyID;
PARTICIPANT_ID = participantID;
});

// delete: optional argument studyID and participantID skips relative prompts
commander
.command(`delete`)
.argument(`[studyID]`)
.argument(`[participantID]`)
.description(`Delete experiment data from Firebase provided study ID and participant ID`)
.action((studyID, participantID) => {
ACTION = "delete";
STUDY_ID = studyID;
PARTICIPANT_ID = participantID;
});
commander.parse();

// print message if download or delete provided, along with optional args provided
if (ACTION !== undefined) {
console.log(
`${ACTION} data from Firebase given ${STUDY_ID === undefined ? "" : `study ID: ${STUDY_ID}`} ${PARTICIPANT_ID === undefined ? "" : `and participant ID: ${PARTICIPANT_ID}`}`
);
}

/** -------------------- MAIN -------------------- */

// TODO @brown-ccv #289: Pass CLI arguments with commander (especially for action)
async function main() {
if (ACTION === undefined) {
ACTION = await actionPrompt();
}
ACTION = await actionPrompt();
DEPLOYMENT = await deploymentPrompt();
// TODO @brown-ccv #291: Enable downloading all study data at once
if (STUDY_ID === undefined) {
STUDY_ID = await studyIDPrompt();
} else {
// when args directly passed in through CLI, check if study is valid
const studyCollection = await validateStudyFirebase(STUDY_ID);
if (!studyCollection) {
console.error("Please enter a valid study from your Firestore database");
process.exit(1);
}
}
STUDY_ID = await studyIDPrompt();
// TODO @brown-ccv #291: Enable downloading all participant data at once
if (PARTICIPANT_ID === undefined) {
PARTICIPANT_ID = await participantIDPrompt();
} else {
// when args directly passed in through CLI, check if participant is valid
const participantCollection = await validateParticipantFirebase(PARTICIPANT_ID);
if (!participantCollection) {
console.error(`Please enter a valid participant on the study "${STUDY_ID}"`);
process.exit(1);
}
}
PARTICIPANT_ID = await participantIDPrompt();
EXPERIMENT_IDS = await experimentIDPrompt();

switch (ACTION) {
Expand Down Expand Up @@ -113,6 +54,7 @@ async function main() {
}
}
main();

/** -------------------- DOWNLOAD ACTION -------------------- */

/** Download data that's stored in Firebase */
Expand Down Expand Up @@ -244,14 +186,20 @@ async function deploymentPrompt() {
/** Prompt the user to enter the ID of a study */
async function studyIDPrompt() {
const invalidMessage = "Please enter a valid study from your Firestore database";
const validateStudyFirebase = async (input) => {
// subcollection is programmatically generated, if it doesn't exist then input must not be a valid studyID
const studyIDCollections = await getStudyRef(input).listCollections();
return studyIDCollections.find((c) => c.id === PARTICIPANTS_COL) ? true : invalidMessage;
};

return await input({
message: "Select a study:",
validate: async (input) => {
if (!input) return invalidMessage;

switch (DEPLOYMENT) {
case "firebase":
const studyCollection = await validateStudyFirebase(input);
return studyCollection || invalidMessage;
return validateStudyFirebase(input);
default:
throw INVALID_DEPLOYMENT_ERROR;
}
Expand All @@ -262,6 +210,12 @@ async function studyIDPrompt() {
/** Prompt the user to enter the ID of a participant on the STUDY_ID study */
async function participantIDPrompt() {
const invalidMessage = `Please enter a valid participant on the study "${STUDY_ID}"`;
const validateParticipantFirebase = async (input) => {
// subcollection is programmatically generated, if it doesn't exist then input must not be a valid participantID
const studyIDCollections = await getParticipantRef(STUDY_ID, input).listCollections();
return studyIDCollections.find((c) => c.id === DATA_COL) ? true : invalidMessage;
};

return await input({
message: "Select a participant:",
validate: async (input) => {
Expand All @@ -271,8 +225,7 @@ async function participantIDPrompt() {

switch (DEPLOYMENT) {
case "firebase":
const participantCollection = await validateParticipantFirebase(input);
return participantCollection || invalidMessage;
return validateParticipantFirebase(input);
default:
throw INVALID_DEPLOYMENT_ERROR;
}
Expand Down Expand Up @@ -359,21 +312,6 @@ async function confirmOverwritePrompt(file, overwriteAll) {
return answer;
}

/** -------------------- FIRESTORE VALIDATIONS -------------------- */
/** helper to check if the given study (input) is in firestore */
async function validateStudyFirebase(input) {
// subcollection is programmatically generated, if it doesn't exist then input must not be a valid studyID
const studyIDCollections = await getStudyRef(input).listCollections();
return studyIDCollections.find((c) => c.id === PARTICIPANTS_COL);
}

/** helper to check if the given participant (input) is in firestore under study */
async function validateParticipantFirebase(input) {
// subcollection is programmatically generated, if it doesn't exist then input must not be a valid participantID
const studyIDCollections = await getParticipantRef(STUDY_ID, input).listCollections();
return studyIDCollections.find((c) => c.id === DATA_COL);
}

/** -------------------- FIRESTORE HELPERS -------------------- */

const RESPONSES_COL = "participant_responses";
Expand Down
39 changes: 16 additions & 23 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
"@jspsych/plugin-instructions": "^1.1.3",
"@jspsych/plugin-preload": "^1.1.2",
"@jspsych/plugin-survey": "^1.0.1",
"commander": "^12.1.0",
"electron-log": "^5.0.0",
"electron-squirrel-startup": "^1.0.0",
"firebase": "^10.11.0",
Expand Down

0 comments on commit 1fb344c

Please sign in to comment.