You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

membership.js 6.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. const Schmervice = require('@hapipal/schmervice')
  2. module.exports = class MembershipService extends Schmervice.Service {
  3. constructor(...args) {
  4. super(...args)
  5. }
  6. /**
  7. * Internal method to get list of grouping_ids for this user
  8. * @param {number} profileId
  9. * @returns {Array} List of all grouping_ids for user
  10. */
  11. async _getGroupingIdsForProfileId(profileId, type, active) {
  12. const { Membership } = this.server.models()
  13. /** Grab every Membership associated with this id */
  14. let allMemberships
  15. if(type && active == 'any') {
  16. allMemberships = await Membership.query()
  17. .where({ profile_id: profileId })
  18. .where({ membership_type: type })
  19. } else if (type) {
  20. allMemberships = await Membership.query()
  21. .where({ profile_id: profileId })
  22. .where({ membership_type: type })
  23. .where({ is_active: true })
  24. } else if(active == 'any') {
  25. allMemberships = await Membership.query()
  26. .where({ profile_id: profileId })
  27. } else {
  28. allMemberships = await Membership.query()
  29. .where({ profile_id: profileId })
  30. .where({ is_active: true })
  31. }
  32. /** Copy a list of the just the Groupings */
  33. const groupingIdsToGrab = allMemberships.map(
  34. membership => membership.grouping_id,
  35. )
  36. /** Uncomment to dedupe the list just in case */
  37. return [...new Set(groupingIdsToGrab)]
  38. }
  39. /**
  40. * Internal method to create a new grouping
  41. * @param {object} groupingToTry from payload data
  42. * @param {*} txn
  43. * @returns {Grouping} created db record
  44. */
  45. async _createGrouping(groupingToTry, txn) {
  46. const { Grouping } = this.server.models()
  47. const groupingInfo = {
  48. grouping_name: groupingToTry.grouping_name,
  49. grouping_type: groupingToTry.grouping_type,
  50. }
  51. return await Grouping.query(txn).insert(groupingInfo)
  52. }
  53. /**
  54. * Tries to grab a grouping_id from payload data
  55. * or returns grouping_id from a newly created record
  56. * @param {object} groupingToTry from payload data
  57. * @returns {number} grouping_id from payload or created record
  58. */
  59. async findOrCreateGroupingFromPayload(groupingToTry) {
  60. let idToReturn = groupingToTry.grouping_id
  61. if (!idToReturn) {
  62. /** ?: For some reason this returns the key id */
  63. const grouping = await this._createGrouping(groupingToTry)
  64. idToReturn = grouping.id
  65. }
  66. return idToReturn
  67. }
  68. /**
  69. * Get a list of groupings for user
  70. * @param {number} profileId
  71. * @returns {Array}
  72. */
  73. async findGroupingsByProfileId(profileId, type) {
  74. const { Grouping } = this.server.models()
  75. const dedupedGroupings = await this._getGroupingIdsForProfileId(profileId, type, 'any')
  76. /** Grab just the Groupings this id has a Membership for */
  77. return await Grouping.query()
  78. .whereIn('grouping_id', dedupedGroupings)
  79. .withGraphFetched('profiles')
  80. }
  81. async _groupingIdsInCommon(profileId, targetId) {
  82. const dedupedUserGroupingIds = await this._getGroupingIdsForProfileId(
  83. profileId,
  84. )
  85. const dedupedTargetGroupingIds = await this._getGroupingIdsForProfileId(
  86. targetId,
  87. )
  88. /** Return true if both people have a group in common */
  89. return dedupedUserGroupingIds.filter(groupingId =>
  90. dedupedTargetGroupingIds.includes(groupingId),
  91. )
  92. }
  93. async _patchMembership(memberships, profileId, patch) {
  94. const { Membership } = this.server.models()
  95. /** Set membership as active only if the user initiates it */
  96. for (let membershipInfo of memberships) {
  97. await Membership.query()
  98. .where('membership_id', membershipInfo.membership_id)
  99. .where('user_id', profileId)
  100. .patch(patch)
  101. }
  102. }
  103. /**
  104. * Check for grouping membership then add membership record and set to active
  105. * or create a new grouping and add membership record for user and membership record for target
  106. * @param {number} profileId
  107. * @param {number} targetId
  108. * @param {object} groupingToWrite
  109. * @param {string} role
  110. * @returns
  111. */
  112. async joinGrouping(profileId, targetId, groupingToWrite, role, txn) {
  113. const { Membership } = this.server.models()
  114. /** If both people have groups in common */
  115. const matchingGroupingIds = await this._groupingIdsInCommon(
  116. profileId,
  117. targetId,
  118. )
  119. if (matchingGroupingIds.length) {
  120. /** Grab all memberships associated with groupingIds */
  121. const memberships = await Membership.query().whereIn(
  122. 'grouping_id',
  123. matchingGroupingIds,
  124. )
  125. /** Set membership as active only if the user initiates it */
  126. await this._patchMembership(memberships, profileId, {
  127. is_active: true,
  128. })
  129. /** Make a new query to get updated information */
  130. return await Membership.query().whereIn(
  131. 'grouping_id',
  132. matchingGroupingIds,
  133. )
  134. } else {
  135. /**
  136. * If both have NO grouping in common, create a membership
  137. * for both and add to a new grouping but
  138. * set membership as inactive for target
  139. * */
  140. /** Check if the grouping exists and if NOT create it */
  141. const groupingId = await this.findOrCreateGroupingFromPayload(groupingToWrite)
  142. const membershipDetailsInCommon = {
  143. grouping_id: groupingId,
  144. membership_type: role,
  145. can_edit: false,
  146. }
  147. const userMembership = await Membership.query(txn).insert({
  148. profile_id: profileId,
  149. ...membershipDetailsInCommon,
  150. is_active: true,
  151. })
  152. const targetMembership = await Membership.query(txn).insert({
  153. profile_id: targetId,
  154. ...membershipDetailsInCommon,
  155. is_active: false,
  156. })
  157. return [userMembership, targetMembership]
  158. }
  159. }
  160. /**
  161. * Remove membership record based on grouping_id
  162. * @param {number} profileId
  163. * @param {number} groupingId
  164. * @returns
  165. */
  166. async leaveGrouping(profileId, groupingId) {
  167. const { Membership } = this.server.models()
  168. const dedupedGroupings = await this._getGroupingIdsForProfileId(profileId)
  169. /** Do NOTHING if NOT in Grouping */
  170. if (!dedupedGroupings.includes(groupingId)) return
  171. return await Membership.query()
  172. .delete()
  173. .where('grouping_id', groupingId)
  174. }
  175. }