mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #7806 from overleaf/ab-group-memberships-bigquery
[web] [analytics] Send group memberships information to analytics & import baseline data GitOrigin-RevId: a15c3131f7b55225ae3949933578475668a195a0
This commit is contained in:
parent
fe18fbe157
commit
5c00fe09e4
2 changed files with 179 additions and 12 deletions
|
@ -64,6 +64,11 @@ async function addUserToGroup(subscriptionId, userId) {
|
|||
).exec()
|
||||
await FeaturesUpdater.promises.refreshFeatures(userId, 'add-to-group')
|
||||
await _sendUserGroupPlanCodeUserProperty(userId)
|
||||
await _sendSubscriptionEvent(
|
||||
userId,
|
||||
subscriptionId,
|
||||
'group-subscription-joined'
|
||||
)
|
||||
}
|
||||
|
||||
async function removeUserFromGroup(subscriptionId, userId) {
|
||||
|
@ -76,6 +81,11 @@ async function removeUserFromGroup(subscriptionId, userId) {
|
|||
'remove-user-from-group'
|
||||
)
|
||||
await _sendUserGroupPlanCodeUserProperty(userId)
|
||||
await _sendSubscriptionEvent(
|
||||
userId,
|
||||
subscriptionId,
|
||||
'group-subscription-left'
|
||||
)
|
||||
}
|
||||
|
||||
async function removeUserFromAllGroups(userId) {
|
||||
|
@ -94,6 +104,13 @@ async function removeUserFromAllGroups(userId) {
|
|||
userId,
|
||||
'remove-user-from-groups'
|
||||
)
|
||||
for (const subscriptionId of subscriptionIds) {
|
||||
await _sendSubscriptionEvent(
|
||||
userId,
|
||||
subscriptionId,
|
||||
'group-subscription-left'
|
||||
)
|
||||
}
|
||||
await _sendUserGroupPlanCodeUserProperty(userId)
|
||||
}
|
||||
|
||||
|
@ -105,10 +122,16 @@ async function deleteSubscription(subscription, deleterData) {
|
|||
// 1. create deletedSubscription
|
||||
await createDeletedSubscription(subscription, deleterData)
|
||||
|
||||
// 2. remove subscription
|
||||
// 2. notify analytics that members left the subscription
|
||||
await _sendSubscriptionEventForAllMembers(
|
||||
subscription._id,
|
||||
'group-subscription-left'
|
||||
)
|
||||
|
||||
// 3. remove subscription
|
||||
await Subscription.deleteOne({ _id: subscription._id }).exec()
|
||||
|
||||
// 3. refresh users features
|
||||
// 4. refresh users features
|
||||
await _scheduleRefreshFeatures(subscription)
|
||||
}
|
||||
|
||||
|
@ -132,6 +155,12 @@ async function restoreSubscription(subscriptionId) {
|
|||
await DeletedSubscription.deleteOne({
|
||||
'subscription._id': subscription._id,
|
||||
}).exec()
|
||||
|
||||
// 4. notify analytics that members rejoined the subscription
|
||||
await _sendSubscriptionEventForAllMembers(
|
||||
subscriptionId,
|
||||
'group-subscription-left'
|
||||
)
|
||||
}
|
||||
|
||||
async function refreshUsersFeatures(subscription) {
|
||||
|
@ -276,6 +305,43 @@ async function _sendUserGroupPlanCodeUserProperty(userId) {
|
|||
}
|
||||
}
|
||||
|
||||
async function _sendSubscriptionEvent(userId, subscriptionId, event) {
|
||||
const subscription = await Subscription.findOne(
|
||||
{ _id: subscriptionId },
|
||||
{ recurlySubscription_id: 1, groupPlan: 1 }
|
||||
)
|
||||
if (!subscription || !subscription.groupPlan) {
|
||||
return
|
||||
}
|
||||
AnalyticsManager.recordEventForUser(userId, event, {
|
||||
groupId: subscription._id.toString(),
|
||||
subscriptionId: subscription.recurlySubscription_id,
|
||||
})
|
||||
}
|
||||
|
||||
async function _sendSubscriptionEventForAllMembers(subscriptionId, event) {
|
||||
const subscription = await Subscription.findOne(
|
||||
{ _id: subscriptionId },
|
||||
{
|
||||
recurlySubscription_id: 1,
|
||||
member_ids: 1,
|
||||
groupPlan: 1,
|
||||
}
|
||||
)
|
||||
if (!subscription) {
|
||||
return
|
||||
}
|
||||
const userIds = (subscription.member_ids || []).filter(Boolean)
|
||||
for (const userId of userIds) {
|
||||
if (userId) {
|
||||
AnalyticsManager.recordEventForUser(userId, event, {
|
||||
groupId: subscription._id.toString(),
|
||||
subscriptionId: subscription.recurlySubscription_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
updateAdmin: callbackify(updateAdmin),
|
||||
syncSubscription: callbackify(syncSubscription),
|
||||
|
|
|
@ -25,6 +25,7 @@ describe('SubscriptionUpdater', function () {
|
|||
member_ids: [],
|
||||
save: sinon.stub().resolves(),
|
||||
planCode: 'student_or_something',
|
||||
recurlySubscription_id: 'abc123def456fab789',
|
||||
}
|
||||
this.user_id = this.adminuser_id
|
||||
|
||||
|
@ -36,6 +37,7 @@ describe('SubscriptionUpdater', function () {
|
|||
save: sinon.stub().resolves(),
|
||||
groupPlan: true,
|
||||
planCode: 'group_subscription',
|
||||
recurlySubscription_id: '456fab789abc123def',
|
||||
}
|
||||
this.betterGroupSubscription = {
|
||||
_id: '999999999999999999999999',
|
||||
|
@ -45,6 +47,7 @@ describe('SubscriptionUpdater', function () {
|
|||
save: sinon.stub().resolves(),
|
||||
groupPlan: true,
|
||||
planCode: 'better_group_subscription',
|
||||
recurlySubscription_id: '123def456fab789abc',
|
||||
}
|
||||
|
||||
const subscription = this.subscription
|
||||
|
@ -66,6 +69,7 @@ describe('SubscriptionUpdater', function () {
|
|||
this.SubscriptionModel.updateOne = sinon
|
||||
.stub()
|
||||
.returns({ exec: sinon.stub().resolves() })
|
||||
this.SubscriptionModel.findOne = sinon.stub().resolves()
|
||||
this.SubscriptionModel.updateMany = sinon
|
||||
.stub()
|
||||
.returns({ exec: sinon.stub().resolves() })
|
||||
|
@ -135,6 +139,7 @@ describe('SubscriptionUpdater', function () {
|
|||
}
|
||||
|
||||
this.AnalyticsManager = {
|
||||
recordEventForUser: sinon.stub().resolves(),
|
||||
setUserPropertyForUser: sinon.stub(),
|
||||
}
|
||||
|
||||
|
@ -378,17 +383,30 @@ describe('SubscriptionUpdater', function () {
|
|||
|
||||
describe('addUserToGroup', function () {
|
||||
it('should add the user ids to the group as a set', async function () {
|
||||
this.SubscriptionModel.findOne = sinon
|
||||
.stub()
|
||||
.resolves(this.groupSubscription)
|
||||
|
||||
await this.SubscriptionUpdater.promises.addUserToGroup(
|
||||
this.subscription._id,
|
||||
this.groupSubscription._id,
|
||||
this.otherUserId
|
||||
)
|
||||
const searchOps = { _id: this.subscription._id }
|
||||
const searchOps = { _id: this.groupSubscription._id }
|
||||
const insertOperation = {
|
||||
$addToSet: { member_ids: this.otherUserId },
|
||||
}
|
||||
this.SubscriptionModel.updateOne
|
||||
.calledWith(searchOps, insertOperation)
|
||||
.should.equal(true)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.recordEventForUser,
|
||||
this.otherUserId,
|
||||
'group-subscription-joined',
|
||||
{
|
||||
groupId: this.groupSubscription._id,
|
||||
subscriptionId: this.groupSubscription.recurlySubscription_id,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('should update the users features', async function () {
|
||||
|
@ -450,9 +468,17 @@ describe('SubscriptionUpdater', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('removeUserFromGroups', function () {
|
||||
describe('removeUserFromGroup', function () {
|
||||
beforeEach(function () {
|
||||
this.fakeSubscriptions = [{ _id: 'fake-id-1' }, { _id: 'fake-id-2' }]
|
||||
this.fakeSubscriptions = [
|
||||
{
|
||||
_id: 'fake-id-1',
|
||||
},
|
||||
{
|
||||
_id: 'fake-id-2',
|
||||
},
|
||||
]
|
||||
this.SubscriptionModel.findOne.resolves(this.groupSubscription)
|
||||
this.SubscriptionLocator.promises.getMemberSubscriptions.resolves(
|
||||
this.fakeSubscriptions
|
||||
)
|
||||
|
@ -469,6 +495,22 @@ describe('SubscriptionUpdater', function () {
|
|||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should send a group-subscription-left event', async function () {
|
||||
await this.SubscriptionUpdater.promises.removeUserFromGroup(
|
||||
this.groupSubscription._id,
|
||||
this.otherUserId
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.recordEventForUser,
|
||||
this.otherUserId,
|
||||
'group-subscription-left',
|
||||
{
|
||||
groupId: this.groupSubscription._id,
|
||||
subscriptionId: this.groupSubscription.recurlySubscription_id,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('should set the group plan code user property when removing user from group', async function () {
|
||||
await this.SubscriptionUpdater.promises.removeUserFromGroup(
|
||||
this.subscription._id,
|
||||
|
@ -482,6 +524,29 @@ describe('SubscriptionUpdater', function () {
|
|||
)
|
||||
})
|
||||
|
||||
it('should update the users features', async function () {
|
||||
await this.SubscriptionUpdater.promises.removeUserFromGroup(
|
||||
this.subscription._id,
|
||||
this.otherUserId
|
||||
)
|
||||
this.FeaturesUpdater.promises.refreshFeatures
|
||||
.calledWith(this.otherUserId)
|
||||
.should.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('removeUserFromAllGroups', function () {
|
||||
beforeEach(function () {
|
||||
this.SubscriptionLocator.promises.getMemberSubscriptions.resolves([
|
||||
{
|
||||
_id: 'fake-id-1',
|
||||
},
|
||||
{
|
||||
_id: 'fake-id-2',
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it('should set the group plan code user property when removing user from all groups', async function () {
|
||||
await this.SubscriptionUpdater.promises.removeUserFromAllGroups(
|
||||
this.otherUserId
|
||||
|
@ -507,14 +572,50 @@ describe('SubscriptionUpdater', function () {
|
|||
)
|
||||
})
|
||||
|
||||
it('should update the users features', async function () {
|
||||
await this.SubscriptionUpdater.promises.removeUserFromGroup(
|
||||
this.subscription._id,
|
||||
it('should send a group-subscription-left event for each group', async function () {
|
||||
this.fakeSub1 = {
|
||||
_id: 'fake-id-1',
|
||||
groupPlan: true,
|
||||
recurlySubscription_id: 'fake-sub-1',
|
||||
}
|
||||
this.fakeSub2 = {
|
||||
_id: 'fake-id-2',
|
||||
groupPlan: true,
|
||||
recurlySubscription_id: 'fake-sub-2',
|
||||
}
|
||||
this.SubscriptionModel.findOne
|
||||
.withArgs(
|
||||
{ _id: 'fake-id-1' },
|
||||
{ recurlySubscription_id: 1, groupPlan: 1 }
|
||||
)
|
||||
.resolves(this.fakeSub1)
|
||||
.withArgs(
|
||||
{ _id: 'fake-id-2' },
|
||||
{ recurlySubscription_id: 1, groupPlan: 1 }
|
||||
)
|
||||
.resolves(this.fakeSub2)
|
||||
|
||||
await this.SubscriptionUpdater.promises.removeUserFromAllGroups(
|
||||
this.otherUserId
|
||||
)
|
||||
this.FeaturesUpdater.promises.refreshFeatures
|
||||
.calledWith(this.otherUserId)
|
||||
.should.equal(true)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.recordEventForUser,
|
||||
this.otherUserId,
|
||||
'group-subscription-left',
|
||||
{
|
||||
groupId: 'fake-id-1',
|
||||
subscriptionId: 'fake-sub-1',
|
||||
}
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.recordEventForUser,
|
||||
this.otherUserId,
|
||||
'group-subscription-left',
|
||||
{
|
||||
groupId: 'fake-id-2',
|
||||
subscriptionId: 'fake-sub-2',
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
|
|
Loading…
Reference in a new issue