UNPKG

@levante-framework/firekit

Version:

A library to facilitate Firebase authentication and Firestore interaction for LEVANTE apps

135 lines (134 loc) 6.2 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.RoarAppUser = void 0; const firestore_1 = require("firebase/firestore"); const extend_1 = __importDefault(require("lodash/extend")); const interfaces_1 = require("../../interfaces"); const util_1 = require("../util"); /** Class representing a ROAR user */ class RoarAppUser { /** Create a ROAR user * @param {object} input * @param {Firestore} input.db - The assessment Firestore instance to which this user's data will be written * @param {string} input.roarUid - The ROAR ID of the user * @param {string} input.assessmentUid - The assessment firebase UID of the user * @param {string} input.assessmentPid - The assessment PID of the user * @param {string} input.userType - The user type. Must be either 'admin', 'educator', 'student', 'caregiver', 'guest', or 'researcher.' * @param {object} input.userMetadata - An object containing additional user metadata * @param {string} input.testData = Boolean flag indicating test data * @param {string} input.demoData = Boolean flag indicating demo data * @param {string} input.offlineEnabled = Boolean flag indicating whether user has enrolled in Offline ROAR * @param {string[]} input.offlineTasks = Array of task IDs that user will need access to offline * @param {string[]} input.offlineAdministrations = Array of administration IDs that user will need access to offline */ constructor({ db, roarUid, assessmentUid, assessmentPid, userType = interfaces_1.UserType.guest, userMetadata = {}, testData = false, demoData = false, offlineEnabled = false, offlineTasks = [], offlineAdministrations = [], }) { const allowedUserCategories = Object.values(interfaces_1.UserType); if (!allowedUserCategories.includes(userType)) { throw new Error(`User category must be one of ${allowedUserCategories.join(', ')}.`); } if (roarUid === undefined && userType !== interfaces_1.UserType.guest) { throw new Error('All non-guest LEVANTE users must be created with a LEVANTE UID.'); } if (userType === interfaces_1.UserType.guest && roarUid !== undefined) { throw new Error('Guest LEVANTE users cannot have a LEVANTE UID.'); } if (userType !== interfaces_1.UserType.guest && assessmentPid === undefined) { throw new Error('All non-guest LEVANTE users must have an assessment PID on instantiation.'); } this.db = db; this.roarUid = roarUid; this.assessmentPid = assessmentPid; this.assessmentUid = assessmentUid; this.userType = userType; this.userMetadata = userMetadata; this.testData = testData; this.demoData = demoData; this.offlineEnabled = offlineEnabled; this.offlineTasks = offlineTasks; this.offlineAdministrations = offlineAdministrations; if (userType === interfaces_1.UserType.guest) { this.userRef = (0, firestore_1.doc)(this.db, 'guests', this.assessmentUid); } else { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion this.userRef = (0, firestore_1.doc)(this.db, 'users', this.roarUid); } } async init() { const docSnap = await (0, firestore_1.getDoc)(this.userRef); this.onFirestore = docSnap.exists(); if (this.onFirestore) { // If so, retrieve their data. this.userData = docSnap.data(); } else { // Otherwise allow them to create their own data ONLY if they are a guest. await this._setUserData(); } } async _setUserData() { if (this.userType !== interfaces_1.UserType.guest) { throw new Error('Cannot set user data on a non-guest LEVANTE user.'); } this.userData = (0, util_1.removeUndefined)({ ...this.userMetadata, assessmentPid: this.assessmentPid, assessmentUid: this.assessmentUid, userType: this.userType, }); await (0, firestore_1.setDoc)(this.userRef, { ...this.userData, created: (0, firestore_1.serverTimestamp)(), createdAt: (0, firestore_1.serverTimestamp)(), updatedAt: (0, firestore_1.serverTimestamp)(), }); this.onFirestore = true; } async checkUserExists() { if (!this.onFirestore) { await this.init(); } if (!this.onFirestore) { throw new Error('This non-guest user is not in Firestore.'); } } /** * Update the user's data (both locally and in Firestore) * @param {object} input * @param {string[]} input.tasks - The tasks to be added to the user doc * @param {string[]} input.variants - The variants to be added to the user doc * @param {string} input.assessmentPid - The assessment PID of the user * @param {*} input.userMetadata - Any additional user metadata * @method * @async */ async updateUser({ tasks, variants, assessmentPid, ...userMetadata }) { this.checkUserExists(); let userData = { lastUpdated: (0, firestore_1.serverTimestamp)(), }; if (tasks) userData.tasks = (0, firestore_1.arrayUnion)(...tasks); if (variants) userData.variants = (0, firestore_1.arrayUnion)(...variants); if (this.userType === interfaces_1.UserType.guest) { if (assessmentPid) userData.assessmentPid = assessmentPid; userData = { ...userMetadata, ...userData, }; } this.userData = (0, extend_1.default)(this.userData, { ...userMetadata, tasks, variants, assessmentPid, }); return await (0, firestore_1.updateDoc)(this.userRef, (0, util_1.removeUndefined)(userData)); } } exports.RoarAppUser = RoarAppUser;