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.

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