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) { 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, ) } else { /** * If both have NO grouping in common create a membership * for both to new group but set membership as inactive for target * */ /** 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) } }