Update cloud functions with new functionality
This commit is contained in:
@@ -2,9 +2,12 @@
|
|||||||
/* eslint-disable no-tabs */
|
/* eslint-disable no-tabs */
|
||||||
const functions = require("firebase-functions");
|
const functions = require("firebase-functions");
|
||||||
const admin = require("firebase-admin");
|
const admin = require("firebase-admin");
|
||||||
|
const { ChatSharp } = require("@material-ui/icons");
|
||||||
admin.initializeApp();
|
admin.initializeApp();
|
||||||
const db = admin.firestore();
|
const db = admin.firestore();
|
||||||
|
|
||||||
|
// TODO: set up App Check https://firebase.google.com/docs/app-check/cloud-functions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Randomises the items in an array.
|
* Randomises the items in an array.
|
||||||
* @param {object} array The array to randomise.
|
* @param {object} array The array to randomise.
|
||||||
@@ -20,6 +23,7 @@ function shuffleArray(array) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds extra user info when new user created.
|
* Adds extra user info when new user created.
|
||||||
|
* NOTE: Can't be unit tested.
|
||||||
* @return {promise} Promise from database write.
|
* @return {promise} Promise from database write.
|
||||||
*/
|
*/
|
||||||
exports.userCreated = functions.auth.user().onCreate(async (user) => {
|
exports.userCreated = functions.auth.user().onCreate(async (user) => {
|
||||||
@@ -35,6 +39,7 @@ exports.userCreated = functions.auth.user().onCreate(async (user) => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Cleans up database when user deleted. Progress documents are kept as they may provide useful metrics.
|
* Cleans up database when user deleted. Progress documents are kept as they may provide useful metrics.
|
||||||
|
* NOTE: Can't be unit tested.
|
||||||
* @return {promise} Promise from database delete.
|
* @return {promise} Promise from database delete.
|
||||||
*/
|
*/
|
||||||
exports.userDeleted = functions.auth.user().onDelete(async (user) => {
|
exports.userDeleted = functions.auth.user().onDelete(async (user) => {
|
||||||
@@ -46,40 +51,60 @@ exports.userDeleted = functions.auth.user().onDelete(async (user) => {
|
|||||||
* @param {object} data The data passed to the function.
|
* @param {object} data The data passed to the function.
|
||||||
* @param {string} data.set_id The ID of the desired set.
|
* @param {string} data.set_id The ID of the desired set.
|
||||||
* @param {boolean} data.switch_language Whether or not the languages should be reversed.
|
* @param {boolean} data.switch_language Whether or not the languages should be reversed.
|
||||||
* @return {string} progressId The ID of the created progress document.
|
* @param {boolean} data.mode The mode to be tested in. Valid options are "questions" and "lives".
|
||||||
|
* @param {boolean} data.limit The maximum number of lives/questions for the test.
|
||||||
|
* @return {string} The ID of the created progress document.
|
||||||
*/
|
*/
|
||||||
exports.createProgress = functions.https.onCall((data, context) => {
|
exports.createProgress = functions.https.onCall((data, context) => {
|
||||||
// const uid = context.auth.uid;
|
// const uid = context.auth.uid;
|
||||||
const uid = "W3eFM5CcDqtocwQ37QGOQSCaWFFj";
|
const uid = "user_01";
|
||||||
|
|
||||||
const switchLanguage = data.switch_language;
|
|
||||||
const setId = data.set_id;
|
const setId = data.set_id;
|
||||||
|
|
||||||
|
const setDocId = db.collection("sets").doc(setId);
|
||||||
|
|
||||||
|
return db.runTransaction((transaction) => {
|
||||||
|
return transaction.get(setDocId).then((setDoc) => {
|
||||||
|
if (!setDoc.exists) {
|
||||||
|
throw new functions.https.HttpsError("not-found", "Set doesn't exist");
|
||||||
|
} else if (!setDoc.data().public && setDoc.data().owner !== uid) {
|
||||||
|
throw new functions.https.HttpsError("permission-denied", "Insufficient permissions to access set");
|
||||||
|
} else {
|
||||||
|
const switchLanguage = data.switch_language;
|
||||||
|
const mode = data.mode;
|
||||||
|
const limit = data.limit;
|
||||||
|
|
||||||
|
const setTitle = setDoc.data().title;
|
||||||
|
const setOwner = setDoc.data().owner;
|
||||||
|
|
||||||
const correct = [];
|
const correct = [];
|
||||||
const incorrect = [];
|
const incorrect = [];
|
||||||
const mark = 0;
|
const currentCorrect = [];
|
||||||
const progress = 0;
|
const progress = 0;
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
|
||||||
const setDocId = db.collection("sets").doc(setId);
|
|
||||||
const setVocabCollectionId = db
|
const setVocabCollectionId = db
|
||||||
.collection("sets").doc(setId)
|
.collection("sets").doc(setId)
|
||||||
.collection("vocab");
|
.collection("vocab");
|
||||||
const progressDocId = db
|
const progressDocId = db
|
||||||
.collection("progress").doc();
|
.collection("progress").doc();
|
||||||
|
|
||||||
|
|
||||||
return db.runTransaction((transaction) => {
|
|
||||||
return transaction.get(setDocId).then((setDoc) => {
|
|
||||||
if (!setDoc.exists) {
|
|
||||||
throw new functions.https.HttpsError("not-found", "Set doesn't exist");
|
|
||||||
} else {
|
|
||||||
const setTitle = setDoc.data().title;
|
|
||||||
|
|
||||||
return transaction.get(setVocabCollectionId).then((setVocab) => {
|
return transaction.get(setVocabCollectionId).then((setVocab) => {
|
||||||
let questions = [];
|
let dataToSet = {
|
||||||
|
questions: [],
|
||||||
|
correct: correct,
|
||||||
|
current_correct: currentCorrect,
|
||||||
|
incorrect: incorrect,
|
||||||
|
progress: progress,
|
||||||
|
start_time: startTime,
|
||||||
|
set_title: setTitle,
|
||||||
|
uid: uid,
|
||||||
|
switch_language: switchLanguage,
|
||||||
|
duration: null,
|
||||||
|
set_owner: setOwner,
|
||||||
|
mode: mode,
|
||||||
|
}
|
||||||
|
|
||||||
setVocab.forEach((doc) => {
|
shuffleArray(setVocab).forEach((doc, index, array) => {
|
||||||
const vocabId = doc.id;
|
const vocabId = doc.id;
|
||||||
|
|
||||||
const terms = {
|
const terms = {
|
||||||
@@ -90,7 +115,7 @@ exports.createProgress = functions.https.onCall((data, context) => {
|
|||||||
"item": doc.data().definition,
|
"item": doc.data().definition,
|
||||||
};
|
};
|
||||||
|
|
||||||
questions.push(vocabId);
|
dataToSet.questions.push(vocabId);
|
||||||
|
|
||||||
transaction.set(
|
transaction.set(
|
||||||
progressDocId.collection("terms").doc(vocabId),
|
progressDocId.collection("terms").doc(vocabId),
|
||||||
@@ -100,31 +125,27 @@ exports.createProgress = functions.https.onCall((data, context) => {
|
|||||||
progressDocId.collection("definitions").doc(vocabId),
|
progressDocId.collection("definitions").doc(vocabId),
|
||||||
definitions
|
definitions
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (mode == "questions" && index >= limit - 1) {
|
||||||
|
array.length = index + 1;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
if (mode === "lives") dataToSet.lives = limit;
|
||||||
|
|
||||||
transaction.set(
|
transaction.set(
|
||||||
progressDocId,
|
progressDocId,
|
||||||
{
|
dataToSet
|
||||||
questions: shuffleArray(questions),
|
|
||||||
correct: correct,
|
|
||||||
incorrect: incorrect,
|
|
||||||
mark: mark,
|
|
||||||
progress: progress,
|
|
||||||
start_time: startTime,
|
|
||||||
set_title: setTitle,
|
|
||||||
uid: uid,
|
|
||||||
switch_language: switchLanguage,
|
|
||||||
duration: null,
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return progressDocId.id;
|
||||||
progressId: progressDocId.id,
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -180,13 +201,47 @@ exports.getPrompt = functions.https.onCall((data, context) => {
|
|||||||
});
|
});
|
||||||
});*/
|
});*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether two arrays have the same members.
|
||||||
|
* @param {array} arr1 The first array to compare.
|
||||||
|
* @param {array} arr2 The second array to compare.
|
||||||
|
* @return {boolean} Whether or not the two arrays have the same members.
|
||||||
|
*/
|
||||||
|
function arraysHaveSameMembers(arr1, arr2) {
|
||||||
|
const set1 = new Set(arr1);
|
||||||
|
const set2 = new Set(arr2);
|
||||||
|
return arr1.every(item => set2.has(item)) &&
|
||||||
|
arr2.every(item => set1.has(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes characters from terms & definitions that should be ignored.
|
||||||
|
* @param {string} item The term/definition to remove the characters that should be ignored from.
|
||||||
|
* @return {string} The original string with the unwanted characters removed.
|
||||||
|
*/
|
||||||
|
function cleanseVocabString(item) {
|
||||||
|
const chars = " .,()-_'\"";
|
||||||
|
|
||||||
|
let newString = item;
|
||||||
|
|
||||||
|
chars.split("").forEach((char) => {
|
||||||
|
newString = newString.replace(char, "");
|
||||||
|
});
|
||||||
|
|
||||||
|
return newString;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processes a response to a question in a vocab set.
|
* Processes a response to a question in a vocab set.
|
||||||
* @param {object} data The data passed to the function.
|
* @param {object} data The data passed to the function.
|
||||||
* @param {string} data.progressId The ID of the progress document to update.
|
* @param {string} data.progressId The ID of the progress document to update.
|
||||||
* @param {string} data.answer The answer given by the user to the current prompt.
|
* @param {string} data.answer The answer given by the user to the current prompt.
|
||||||
* @return {boolean} correct Whether the provided answer was correct.
|
* @return {boolean} correct Whether the provided answer was correct.
|
||||||
* @return {array} correctAnswers An array of correct answers for the question just answered.
|
* @return {array} correctAnswers An array of correct answers for the question just answered. If not all correct
|
||||||
|
* answers have yet been given, and the current answer is correct, this only contains the correct
|
||||||
|
* answers given so far.
|
||||||
|
* @return {integer} lives Total number of lives available in this test. Only returned if mode is "lives".
|
||||||
|
* @return {boolean} moreAnswers Whether or not there are more answers required for the current prompt.
|
||||||
* @return {object} nextPrompt Details of the next prompt, if relevant. Null if last question has been answered.
|
* @return {object} nextPrompt Details of the next prompt, if relevant. Null if last question has been answered.
|
||||||
* @return {string} nextPrompt.item The term/definition prompt for the next question.
|
* @return {string} nextPrompt.item The term/definition prompt for the next question.
|
||||||
* @return {string} nextPrompt.sound The file ID for the next question's sound file. Null if language is switched.
|
* @return {string} nextPrompt.sound The file ID for the next question's sound file. Null if language is switched.
|
||||||
@@ -197,7 +252,7 @@ exports.getPrompt = functions.https.onCall((data, context) => {
|
|||||||
*/
|
*/
|
||||||
exports.processAnswer = functions.https.onCall((data, context) => {
|
exports.processAnswer = functions.https.onCall((data, context) => {
|
||||||
// const uid = context.auth.uid;
|
// const uid = context.auth.uid;
|
||||||
const uid = "W3eFM5CcDqtocwQ37QGOQSCaWFFj";
|
const uid = "user_01";
|
||||||
|
|
||||||
const progressId = data.progressId;
|
const progressId = data.progressId;
|
||||||
const inputAnswer = data.answer;
|
const inputAnswer = data.answer;
|
||||||
@@ -207,9 +262,11 @@ exports.processAnswer = functions.https.onCall((data, context) => {
|
|||||||
|
|
||||||
return db.runTransaction((transaction) => {
|
return db.runTransaction((transaction) => {
|
||||||
return transaction.get(progressDocId).then((progressDoc) => {
|
return transaction.get(progressDocId).then((progressDoc) => {
|
||||||
if (uid !== progressDoc.data().uid) {
|
if (!progressDoc.exists) {
|
||||||
|
throw new functions.https.HttpsError("not-found", "Progress record " + progressId + " doesn't exist")
|
||||||
|
} else if (uid !== progressDoc.data().uid) {
|
||||||
throw new functions.https.HttpsError("permission-denied", "Wrong user's progress");
|
throw new functions.https.HttpsError("permission-denied", "Wrong user's progress");
|
||||||
} else if (progressDoc.data().progress >= progressDoc.data().questions.length) {
|
} else if (progressDoc.data().progress >= progressDoc.data().questions.length || (progressDoc.data().mode === "lives" && progressDoc.data().incorrect.length >= progressDoc.data().lives)) {
|
||||||
throw new functions.https.HttpsError("permission-denied", "Progress already completed")
|
throw new functions.https.HttpsError("permission-denied", "Progress already completed")
|
||||||
} else {
|
} else {
|
||||||
currentIndex = progressDoc.data().progress;
|
currentIndex = progressDoc.data().progress;
|
||||||
@@ -226,45 +283,82 @@ exports.processAnswer = functions.https.onCall((data, context) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return transaction.get(answerDocId).then((answerDoc) => {
|
return transaction.get(answerDocId).then((answerDoc) => {
|
||||||
// TODO: rename due to conflict with var passed to cloud fn
|
const docData = progressDoc.data();
|
||||||
const data = progressDoc.data();
|
const mode = docData.mode;
|
||||||
const correctAnswers = answerDoc.data().item;
|
const correctAnswers = answerDoc.data().item;
|
||||||
const splitCorrectAnswers = correctAnswers.replace(" ", "").split("/");
|
const splitCorrectAnswers = correctAnswers.split("/");
|
||||||
const isCorrectAnswer = splitCorrectAnswers.includes(inputAnswer.replace(" ", ""));
|
const cleansedSplitCorrectAnswers = cleanseVocabString(correctAnswers).split("/");
|
||||||
|
const cleansedInputAnswer = cleanseVocabString(inputAnswer);
|
||||||
|
|
||||||
data.progress++;
|
let isCorrectAnswer = false;
|
||||||
|
let correctAnswerIndex;
|
||||||
|
|
||||||
if (isCorrectAnswer) {
|
cleansedSplitCorrectAnswers.forEach((answer, index, array) => {
|
||||||
data.correct.push(currentVocab);
|
if (answer === cleansedInputAnswer) {
|
||||||
} else {
|
isCorrectAnswer = true;
|
||||||
data.incorrect.push(currentVocab);
|
correctAnswerIndex = index;
|
||||||
data.questions.push(currentVocab);
|
array.length = index + 1;
|
||||||
const doneQuestions = data.questions.slice(0,data.progress);
|
|
||||||
const notDoneQuestions = data.questions.slice(data.progress);
|
|
||||||
data.questions = doneQuestions.concat(shuffleArray(notDoneQuestions));
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let prevCorrect = progressDoc.data().current_correct;
|
||||||
|
|
||||||
var returnData = {
|
var returnData = {
|
||||||
|
mode: mode,
|
||||||
correct: isCorrectAnswer,
|
correct: isCorrectAnswer,
|
||||||
correctAnswers: splitCorrectAnswers,
|
correctAnswers: splitCorrectAnswers,
|
||||||
|
moreAnswers: false,
|
||||||
nextPrompt: null,
|
nextPrompt: null,
|
||||||
progress: data.progress,
|
progress: docData.progress,
|
||||||
totalQuestions: data.questions.length,
|
totalQuestions: docData.questions.length,
|
||||||
totalCorrect: data.correct.length,
|
totalCorrect: docData.correct.length,
|
||||||
totalIncorrect: data.incorrect.length,
|
totalIncorrect: docData.incorrect.length,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.progress >= data.questions.length) {
|
if (isCorrectAnswer) {
|
||||||
const duration = Date.now() - data.start_time;
|
if (!prevCorrect) {
|
||||||
data.duration = duration;
|
docData.current_correct = [splitCorrectAnswers[correctAnswerIndex]];
|
||||||
|
} else if (!prevCorrect.includes(splitCorrectAnswers[correctAnswerIndex])) {
|
||||||
|
docData.current_correct.push(splitCorrectAnswers[correctAnswerIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (docData.current_correct.length === splitCorrectAnswers.length) {
|
||||||
|
docData.progress++;
|
||||||
|
returnData.progress = docData.progress;
|
||||||
|
docData.current_correct = [];
|
||||||
|
docData.correct.push(currentVocab);
|
||||||
|
returnData.totalCorrect = docData.correct.length;
|
||||||
|
} else {
|
||||||
|
returnData.moreAnswers = true;
|
||||||
|
returnData.correctAnswers = docData.current_correct;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
docData.progress++;
|
||||||
|
returnData.progress = docData.progress;
|
||||||
|
docData.incorrect.push(currentVocab);
|
||||||
|
docData.questions.push(currentVocab);
|
||||||
|
const doneQuestions = docData.questions.slice(0, docData.progress);
|
||||||
|
const notDoneQuestions = docData.questions.slice(docData.progress);
|
||||||
|
docData.current_correct = [];
|
||||||
|
docData.questions = doneQuestions.concat(shuffleArray(notDoneQuestions));
|
||||||
|
returnData.totalQuestions = docData.questions.length;
|
||||||
|
returnData.totalIncorrect = docData.incorrect.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode === "lives") returnData.lives = docData.lives;
|
||||||
|
|
||||||
|
if (!returnData.moreAnswers) {
|
||||||
|
if (docData.progress >= docData.questions.length || (mode === "lives" && docData.incorrect.length >= docData.lives)) {
|
||||||
|
const duration = Date.now() - docData.start_time;
|
||||||
|
docData.duration = duration;
|
||||||
returnData.duration = duration;
|
returnData.duration = duration;
|
||||||
console.log("duration: " + data.duration + " // start time: " + data.start_time);
|
|
||||||
transaction.set(progressDocId, data);
|
transaction.set(progressDocId, docData);
|
||||||
return returnData;
|
return returnData;
|
||||||
} else {
|
} else {
|
||||||
const nextVocabId = data.questions[data.progress];
|
const nextVocabId = docData.questions[docData.progress];
|
||||||
|
|
||||||
if (data.switch_language) {
|
if (docData.switch_language) {
|
||||||
const promptDocId = progressDocId
|
const promptDocId = progressDocId
|
||||||
.collection("definitions").doc(nextVocabId);
|
.collection("definitions").doc(nextVocabId);
|
||||||
const sound = null;
|
const sound = null;
|
||||||
@@ -274,7 +368,7 @@ exports.processAnswer = functions.https.onCall((data, context) => {
|
|||||||
item: promptDoc.data().item,
|
item: promptDoc.data().item,
|
||||||
sound: sound,
|
sound: sound,
|
||||||
}
|
}
|
||||||
transaction.set(progressDocId, data);
|
transaction.set(progressDocId, docData);
|
||||||
return returnData;
|
return returnData;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -287,12 +381,15 @@ exports.processAnswer = functions.https.onCall((data, context) => {
|
|||||||
item: promptDoc.data().item,
|
item: promptDoc.data().item,
|
||||||
sound: sound,
|
sound: sound,
|
||||||
}
|
}
|
||||||
transaction.set(progressDocId, data);
|
transaction.set(progressDocId, docData);
|
||||||
return returnData;
|
return returnData;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
transaction.set(progressDocId, docData);
|
||||||
|
return returnData;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -309,9 +406,9 @@ exports.processAnswer = functions.https.onCall((data, context) => {
|
|||||||
*/
|
*/
|
||||||
exports.setAdmin = functions.https.onCall(async (data, context) => {
|
exports.setAdmin = functions.https.onCall(async (data, context) => {
|
||||||
// const uid = context.auth.uid;
|
// const uid = context.auth.uid;
|
||||||
// const admin = context.auth.tokens.admin;
|
// const isAdmin = context.auth.tokens.admin;
|
||||||
const uid = "W3eFM5CcDqtocwQ37QGOQSCaWFFj";
|
const uid = "M3JPrFRH6Fdo8XMUbF0l2zVZUCH3";
|
||||||
const isAdmin = false;
|
const isAdmin = true;
|
||||||
|
|
||||||
const targetUser = data.targetUser;
|
const targetUser = data.targetUser;
|
||||||
const adminState = data.adminState;
|
const adminState = data.adminState;
|
||||||
@@ -340,8 +437,8 @@ exports.addSetToGroup = functions.https.onCall((data, context) => {
|
|||||||
// const uid = context.auth.uid;
|
// const uid = context.auth.uid;
|
||||||
// const isAdmin = context.auth.token.admin;
|
// const isAdmin = context.auth.token.admin;
|
||||||
// const auth = context.auth;
|
// const auth = context.auth;
|
||||||
const uid = "W3eFM5CcDqtocwQ37QGOQSCaWFFj";
|
const uid = "user_01";
|
||||||
const isAdmin = true;
|
const isAdmin = false;
|
||||||
const auth = { uid: uid };
|
const auth = { uid: uid };
|
||||||
|
|
||||||
const groupId = data.groupId;
|
const groupId = data.groupId;
|
||||||
@@ -399,7 +496,7 @@ exports.removeSetFromGroup = functions.https.onCall((data, context) => {
|
|||||||
// const uid = context.auth.uid;
|
// const uid = context.auth.uid;
|
||||||
// const isAdmin = context.auth.token.admin;
|
// const isAdmin = context.auth.token.admin;
|
||||||
// const auth = context.auth;
|
// const auth = context.auth;
|
||||||
const uid = "W3eFM5CcDqtocwQ37QGOQSCaWFFj";
|
const uid = "user_01";
|
||||||
const isAdmin = false;
|
const isAdmin = false;
|
||||||
const auth = { uid: uid };
|
const auth = { uid: uid };
|
||||||
|
|
||||||
@@ -413,7 +510,6 @@ exports.removeSetFromGroup = functions.https.onCall((data, context) => {
|
|||||||
return transaction.get(setDocId).then((setDoc) => {
|
return transaction.get(setDocId).then((setDoc) => {
|
||||||
return transaction.get(userGroupDocId).then((userGroupDoc) => {
|
return transaction.get(userGroupDocId).then((userGroupDoc) => {
|
||||||
const userRole = userGroupDoc.data().role;
|
const userRole = userGroupDoc.data().role;
|
||||||
console.log(context.auth);
|
|
||||||
if (auth && (userRole == "owner" || isAdmin)) {
|
if (auth && (userRole == "owner" || isAdmin)) {
|
||||||
let setDocData = setDoc.data();
|
let setDocData = setDoc.data();
|
||||||
if (setDocData.groups == null || !setDocData.groups.includes(groupId)) {
|
if (setDocData.groups == null || !setDocData.groups.includes(groupId)) {
|
||||||
@@ -445,6 +541,7 @@ exports.removeSetFromGroup = functions.https.onCall((data, context) => {
|
|||||||
/**
|
/**
|
||||||
* Changes an existing user's membership status of a group in the groups collection
|
* Changes an existing user's membership status of a group in the groups collection
|
||||||
* in Firestore, after it has been changed in the users collection.
|
* in Firestore, after it has been changed in the users collection.
|
||||||
|
* NOTE: Can't be unit tested.
|
||||||
* @return {promise} The promise from setting the group's updated data.
|
* @return {promise} The promise from setting the group's updated data.
|
||||||
*/
|
*/
|
||||||
exports.userGroupRoleChanged = functions.firestore.document("users/{userId}/groups/{groupId}")
|
exports.userGroupRoleChanged = functions.firestore.document("users/{userId}/groups/{groupId}")
|
||||||
@@ -484,7 +581,6 @@ async function generateJoinCode() {
|
|||||||
if (snapshot.exists) {
|
if (snapshot.exists) {
|
||||||
return generateJoinCode();
|
return generateJoinCode();
|
||||||
} else {
|
} else {
|
||||||
console.log("RETURNING");
|
|
||||||
return joinCode;
|
return joinCode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -496,7 +592,7 @@ async function generateJoinCode() {
|
|||||||
*/
|
*/
|
||||||
exports.createGroup = functions.https.onCall(async (data, context) => {
|
exports.createGroup = functions.https.onCall(async (data, context) => {
|
||||||
// const uid = context.auth.uid;
|
// const uid = context.auth.uid;
|
||||||
const uid = "W3eFM5CcDqtocwQ37QGOQSCaWFFj";
|
const uid = "user_01";
|
||||||
|
|
||||||
const joinCode = await generateJoinCode();
|
const joinCode = await generateJoinCode();
|
||||||
|
|
||||||
@@ -516,6 +612,7 @@ exports.createGroup = functions.https.onCall(async (data, context) => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Cleans up database after group is deleted - removes group references from user groups collections.
|
* Cleans up database after group is deleted - removes group references from user groups collections.
|
||||||
|
* NOTE: Can't be unit tested.
|
||||||
* @return {promise} The promise from deleting the user's group data.
|
* @return {promise} The promise from deleting the user's group data.
|
||||||
*/
|
*/
|
||||||
exports.groupDeleted = functions.firestore.document("groups/{groupId}")
|
exports.groupDeleted = functions.firestore.document("groups/{groupId}")
|
||||||
@@ -543,6 +640,7 @@ exports.groupDeleted = functions.firestore.document("groups/{groupId}")
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Cleans up database after group is deleted - removes group references from user groups collections.
|
* Cleans up database after group is deleted - removes group references from user groups collections.
|
||||||
|
* NOTE: Can't be unit tested.
|
||||||
* @return {boolean} Returns true on completion.
|
* @return {boolean} Returns true on completion.
|
||||||
*/
|
*/
|
||||||
exports.progressDeleted = functions.firestore.document("progress/{progressId}")
|
exports.progressDeleted = functions.firestore.document("progress/{progressId}")
|
||||||
@@ -576,6 +674,12 @@ async function deleteCollection(db, collectionPath, batchSize) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a batch of Firestore documents.
|
||||||
|
* @param {FirebaseFirestore.Firestore} db The database object from which the collection should be deleted.
|
||||||
|
* @param {string} query The delete query.
|
||||||
|
* @param {integer} resolve The resolve object from a generated promise.
|
||||||
|
*/
|
||||||
async function deleteQueryBatch(db, query, resolve) {
|
async function deleteQueryBatch(db, query, resolve) {
|
||||||
const snapshot = await query.get();
|
const snapshot = await query.get();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user