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} profileId * @returns {Array} List of all grouping_ids for user */ async _getGroupingIdsForProfileId(profileId) { const { Membership } = this.server.models() /** Grab every Membership associated with this id */ const allMemberships = await Membership.query().where({ profile_id: profileId, }) /** Copy a list of the just the Grouping ids */ 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 {object} groupingToTry from payload data * @param {*} txn * @returns {Grouping} created db record */ 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) } /** * Tries to grab a grouping_id from payload data * or returns grouping_id from a newly created record * @param {object} groupingToTry from payload data * @returns {number} grouping_id from payload or created record */ async findOrCreateGroupingFromPayload(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} profileId * @returns {Array} */ async findGroupingsByProfileId(profileId, type) { const { Grouping } = this.server.models() const dedupedGroupings = await this._getGroupingIdsForProfileId( profileId, type, ) /** Grab just the Groupings this id has a Membership for */ return await Grouping.query() .whereIn('grouping_id', dedupedGroupings) .withGraphFetched('profiles') } async _groupingIdsInCommon(profileId, targetId) { const uids = await this._getGroupingIdsForProfileId(profileId) const tids = await this._getGroupingIdsForProfileId(targetId) const common = [] for (let i in uids) { if (tids.indexOf(uids[i]) !== -1) common.push(uids[i]) } return common.sort((x, y) => x - y) } async _patchMembership(memberships, profileId, 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('profile_id', profileId) .patch(patch) } } /** * 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} profileId * @param {number} targetId * @param {object} groupingToWrite * @param {string} role * @returns */ async joinGrouping(profileId, targetId, groupingToWrite, role, txn) { const { Membership } = this.server.models() /** If both people have groups in common */ const matchingGroupingIds = await this._groupingIdsInCommon( profileId, 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, profileId, { 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 and add to a new grouping but * set membership as inactive for target * */ /** Check if the grouping exists and if NOT create it */ const groupingId = await this.findOrCreateGroupingFromPayload( groupingToWrite, ) const membershipDetailsInCommon = { grouping_id: groupingId, membership_type: role, can_edit: false, } const userMembership = await Membership.query(txn).insert({ profile_id: profileId, ...membershipDetailsInCommon, is_active: true, }) const targetMembership = await Membership.query(txn).insert({ profile_id: targetId, ...membershipDetailsInCommon, is_active: false, }) return [userMembership, targetMembership] } } /** * Remove membership record based on grouping_id * @param {number} profileId * @param {number} groupingId * @returns */ async leaveGrouping(profileId, groupingId) { const { Membership } = this.server.models() const dedupedGroupings = await this._getGroupingIdsForProfileId( profileId, ) /** Do NOTHING if NOT in Grouping */ if (!dedupedGroupings.includes(groupingId)) return return await Membership.query() .delete() .where('grouping_id', groupingId) } }