'use strict'; const Schmervice = require('@hapipal/schmervice'); module.exports = class MembershipService extends Schmervice.Service { constructor(...args) { super(...args) } /** * Internal method to get list of grouping_ids for this user * @param {number} userId * @returns {Array} List of all grouping_ids for user */ async _getGroupIdsForUserId(userId) { const { Membership } = this.server.models() /** Grab every Membership associated with this id */ const allMemberships = await Membership.query() .where('user_id', userId) /** Copy a list of the just the Groupings */ const groupingIdsToGrab = allMemberships.map(membership => membership.grouping_id) /** Uncomment to dedupe the list just in case */ return [...new Set(groupingIdsToGrab)] } /** * Internal method to create a new grouping * @param {*} groupingToTry * @param {*} txn * @returns */ async _createGrouping(groupingToTry, txn) { const { Grouping } = this.server.models() const groupingInfo = { grouping_name: groupingToTry.grouping_name, grouping_type: groupingToTry.grouping_type, } return await Grouping.query(txn) .insert(groupingInfo) } async findOrCreateGrouping(groupingToTry) { let idToReturn = groupingToTry.grouping_id if(!idToReturn) { /** ?: For some reason this returns the key id */ const grouping = await this._createGrouping(groupingToTry) idToReturn = grouping.id } return idToReturn } /** * Get a list of groupings for user * @param {number} userId * @returns {Array} */ async findGroupingsById(userId) { const { Grouping } = this.server.models() const dedupedGroupings = await this._getGroupIdsForUserId(userId) /** Grab just the Groupings this id has a Membership for */ return await Grouping.query() .throwIfNotFound() .whereIn('grouping_id', dedupedGroupings) } async _groupingIdsInCommon(userId, targetId) { const dedupedUserGroupingIds = await this._getGroupIdsForUserId(userId) const dedupedTargetGroupingIds = await this._getGroupIdsForUserId(targetId) /** Return true if both people have a group in common */ return dedupedUserGroupingIds.filter(groupingId => dedupedTargetGroupingIds.includes(groupingId)) } async _patchMembership(memberships, userId, patch) { const { Membership } = this.server.models() /** Set membership as active only if the user initiates it */ for(let membershipInfo of memberships) { await Membership.query() .where('membership_id', membershipInfo.membership_id) .where('user_id', userId) .patch(patch) } } async attemptMatch(userId, targetId, txn) { const { Membership } = this.server.models() /** If both people have groups in common */ const matchingGroupingIds = await this._groupingIdsInCommon(userId, targetId) if(matchingGroupingIds.length) { /** Grab all memberships associated with groupingIds */ const memberships = await Membership.query().whereIn('grouping_id', matchingGroupingIds) /** Set membership as active only if the user initiates it */ await this._patchMembership(memberships, userId, { is_active: true }) /** Make a new query to get updated information */ return await Membership.query().whereIn('grouping_id', matchingGroupingIds) } } /** * Check for grouping membership then add membership record and set to active * or create a new grouping and add membership record for user and membership record for target * @param {number} userId * @param {number} targetId * @param {object} groupingToWrite * @param {string} role * @returns */ async joinGrouping(userId, targetId, groupingToWrite, role, txn) { const { Membership } = this.server.models() /** If both people have groups in common */ const matchingGroupingIds = await this._groupingIdsInCommon(userId, targetId) if(matchingGroupingIds.length) { /** Grab all memberships associated with groupingIds */ const memberships = await Membership.query().whereIn('grouping_id', matchingGroupingIds) /** Set membership as active only if the user initiates it */ await this._patchMembership(memberships, userId, { is_active: true }) /** Make a new query to get updated information */ return await Membership.query().whereIn('grouping_id', matchingGroupingIds) } /** * If both have NO grouping in common create a membership * for both to new group but set membership as inactive for target * */ else { /** Check if the grouping exists and if NOT creat it */ const groupingId = await this.findOrCreateGrouping(groupingToWrite) const userMembership = await Membership.query(txn).insert({ user_id: userId, grouping_id: groupingId, membership_type: role, can_edit: false, is_active: true }) const targetMembership = await Membership.query(txn).insert({ user_id: targetId, grouping_id: groupingId, membership_type: role, can_edit: false, is_active: false }) return [userMembership, targetMembership] } } /** * Remove membership record based on grouping_id * @param {number} userId * @param {number} groupingId * @returns */ async leaveGrouping(userId, groupingId) { const { Membership } = this.server.models() const dedupedGroupings = await this._getGroupIdsForUserId(userId) /** Do NOTHING if NOT in Grouping */ if(!dedupedGroupings.includes(groupingId)) return return await Membership.query() .delete() .where('grouping_id', groupingId) } }