/* eslint-disable promise/always-return */
/**
* @module method/use
*/
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const FieldValue = admin.firestore.FieldValue;
const {has} = require('lodash');
const db = admin.firestore();
/**
* Consume an invite code
*
* @param {string} uid - Refereeās Firebase User ID, e.g. hk_wx5555556.
* @param {string} inviteCode - The invite code
*
* @return {object} An object containing data related to the invite code.
*/
const use = (uid, inviteCode) => {
return db.runTransaction((transaction) => {
// Assign references to Cloud Firestore
const userMetaRef = db.collection('appUserMeta').doc(uid);
const inviteCodeRef = db.collection('appGlobalSettings')
.doc('inviteCode')
.collection('codes')
.doc(inviteCode);
return transaction.getAll(userMetaRef, inviteCodeRef).then((docs) => {
// Reassign docs
const [userMetaDoc, inviteCodeDoc] = docs;
// Assign userMeta and inviteCodeData to null
let userMeta = null;
let inviteCodeData = null;
// Check if the userMeta exists
if (userMetaDoc.exists) {
userMeta = userMetaDoc.data();
} else {
throw new functions.https.HttpsError(
'not-found',
'Error while attempting to use invite code: '
+ 'Cannot find specified user in user meta'
);
}
// Check if user has already consumed an invite code previosuly
if (has(userMeta, 'inviteCode')) {
throw new functions.https.HttpsError(
'cancelled',
'Error while attempting to use invite code: '
+ 'User has previously consumed an invite code'
);
}
// Check if the invite code exists
if (inviteCodeDoc.exists) {
inviteCodeData = inviteCodeDoc.data();
} else {
throw new functions.https.HttpsError(
'not-found',
'Error while attempting to use invite code: '
+ 'Cannot find specified invite code'
);
}
// Assign expiration and current timestamps
const expiration = inviteCodeData['expiration'].toMillis();
const now = Date.now();
// Check if invite code is not expired
if (now < expiration) {
// Check if invite code still has quota
if (inviteCodeData['quota'] > 0) {
// Save invite code data to userMeta
transaction.update(userMetaRef, {
inviteCode: {
code: inviteCode,
description: inviteCodeData['description'],
},
});
// Decrease quota count of invite code
transaction.update(inviteCodeRef, {
quota: FieldValue.increment(-1),
});
} else {
throw new functions.https.HttpsError(
'resource-exhausted',
'Error while attempting to use invite code: '
+ 'Invite code has been used too many times'
);
}
} else {
throw new functions.https.HttpsError(
'cancelled',
'Error while attempting to use invite code: '
+ 'Invite code has already expired'
);
}
}).then(() => {
return true;
}).catch((error) => {
// throw new Error('Error while attempting to use invite code: ' + error);
throw error;
});
});
};
module.exports = use;