mirror of
https://github.com/sudoxnym/habitica-self-host.git
synced 2026-04-14 11:36:45 +00:00
Better group plan member counts (#10449)
* fix(group-plans): improved member count accuracy * fix(migration): don't leave server running after completion * fix(migration): don't update Stripe for non-Stripe methods Also fixes a linting issue. * fix(lint): no comma dangle here * fix(async): put async token in relevant spot * fix(lint): still more linting * fix(async): better handling for async and promises Also adds additional logging where discrepancies are found. * feat(migration): provide CSV output * fix(promises): better pause/resume * fix(migration): don't update already canceled subs * fix(groups): also address quantity/memberCount discrepancies * fix(migration): also log quantity issues * fix(migration): equation was reversed * refactor(migration): condense logic, add error catch * fix(migration): fix root cause of failed quantity update?? * fix(lint): gratuitous parens * fix(test): expect group to be updated db-side * fix(migration): actually update quantities? * fix(groups): roll back unneeded Stripe lib change, refactor migration
This commit is contained in:
parent
6a767ed70b
commit
7ea6c911cb
4 changed files with 111 additions and 2 deletions
|
|
@ -112,5 +112,6 @@
|
|||
"CLOUDKARAFKA_USERNAME": "",
|
||||
"CLOUDKARAFKA_PASSWORD": "",
|
||||
"CLOUDKARAFKA_TOPIC_PREFIX": ""
|
||||
}
|
||||
},
|
||||
"MIGRATION_CONNECT_STRING": "mongodb://localhost:27017/habitrpg?auto_reconnect=true"
|
||||
}
|
||||
|
|
|
|||
107
migrations/groups/reconcile-group-plan-members.js
Normal file
107
migrations/groups/reconcile-group-plan-members.js
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
import monk from 'monk';
|
||||
import nconf from 'nconf';
|
||||
import stripePayments from '../../website/server/libs/payments/stripe';
|
||||
|
||||
/*
|
||||
* Ensure that group plan billing is accurate by doing the following:
|
||||
* 1. Correct the memberCount in all paid groups whose counts are wrong
|
||||
* 2. Where the above uses Stripe, update their subscription counts in Stripe
|
||||
*
|
||||
* Provides output on what groups were fixed, which can be piped to CSV.
|
||||
*/
|
||||
|
||||
const CONNECTION_STRING = nconf.get('MIGRATION_CONNECT_STRING');
|
||||
|
||||
let dbGroups = monk(CONNECTION_STRING).get('groups', { castIds: false });
|
||||
let dbUsers = monk(CONNECTION_STRING).get('users', { castIds: false });
|
||||
|
||||
async function fixGroupPlanMembers () {
|
||||
console.info('Group ID, Customer ID, Plan ID, Quantity, Recorded Member Count, Actual Member Count');
|
||||
let groupPlanCount = 0;
|
||||
let fixedGroupCount = 0;
|
||||
|
||||
dbGroups.find(
|
||||
{
|
||||
$and:
|
||||
[
|
||||
{'purchased.plan.planId': {$ne: null}},
|
||||
{'purchased.plan.planId': {$ne: ''}},
|
||||
{'purchased.plan.customerId': {$ne: 'cus_9f0DV4g7WHRzpM'}}, // Demo groups
|
||||
{'purchased.plan.customerId': {$ne: 'cus_9maalqDOFTrvqx'}},
|
||||
],
|
||||
$or:
|
||||
[
|
||||
{'purchased.plan.dateTerminated': null},
|
||||
{'purchased.plan.dateTerminated': ''},
|
||||
],
|
||||
},
|
||||
{
|
||||
fields: {
|
||||
memberCount: 1,
|
||||
'purchased.plan': 1,
|
||||
},
|
||||
}
|
||||
).each(async (group, {close, pause, resume}) => { // eslint-disable-line no-unused-vars
|
||||
pause();
|
||||
groupPlanCount++;
|
||||
|
||||
const canonicalMemberCount = await dbUsers.count(
|
||||
{
|
||||
$or:
|
||||
[
|
||||
{'party._id': group._id},
|
||||
{guilds: group._id},
|
||||
],
|
||||
}
|
||||
);
|
||||
const incorrectMemberCount = group.memberCount !== canonicalMemberCount;
|
||||
|
||||
const isMonthlyPlan = group.purchased.plan.planId === 'group_monthly';
|
||||
const quantityMismatch = group.purchased.plan.quantity !== group.memberCount + 2;
|
||||
const incorrectQuantity = isMonthlyPlan && quantityMismatch;
|
||||
|
||||
if (!incorrectMemberCount && !incorrectQuantity) {
|
||||
resume();
|
||||
return;
|
||||
}
|
||||
|
||||
console.info(`${group._id}, ${group.purchased.plan.customerId}, ${group.purchased.plan.planId}, ${group.purchased.plan.quantity}, ${group.memberCount}, ${canonicalMemberCount}`);
|
||||
|
||||
const groupUpdate = await dbGroups.update(
|
||||
{ _id: group._id },
|
||||
{
|
||||
$set: {
|
||||
memberCount: canonicalMemberCount,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!groupUpdate) return;
|
||||
|
||||
fixedGroupCount++;
|
||||
if (group.purchased.plan.paymentMethod === 'Stripe') {
|
||||
await stripePayments.chargeForAdditionalGroupMember(group);
|
||||
await dbGroups.update(
|
||||
{_id: group._id},
|
||||
{$set: {'purchased.plan.quantity': canonicalMemberCount + 2}}
|
||||
);
|
||||
}
|
||||
|
||||
if (incorrectQuantity) {
|
||||
await dbGroups.update(
|
||||
{_id: group._id},
|
||||
{$set: {'purchased.plan.quantity': canonicalMemberCount + 2}}
|
||||
);
|
||||
}
|
||||
|
||||
resume();
|
||||
}).then(() => {
|
||||
console.info(`Fixed ${fixedGroupCount} out of ${groupPlanCount} active Group Plans`);
|
||||
return process.exit(0);
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
return process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = fixGroupPlanMembers;
|
||||
|
|
@ -7,7 +7,7 @@ let authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done
|
|||
*/
|
||||
|
||||
let monk = require('monk');
|
||||
let connectionString = 'mongodb://sabrecat:z8e8jyRA8CTofMQ@ds013393-a0.mlab.com:13393/habitica?auto_reconnect=true';
|
||||
let connectionString = 'mongodb://localhost:27017/habitrpg?auto_reconnect=true';
|
||||
let dbTasks = monk(connectionString).get('tasks', { castIds: false });
|
||||
|
||||
function processTasks (lastId) {
|
||||
|
|
|
|||
|
|
@ -196,6 +196,7 @@ api.createGroupPlan = {
|
|||
|
||||
// @TODO: Change message
|
||||
if (group.privacy !== 'private') throw new NotAuthorized(res.t('partyMustbePrivate'));
|
||||
group.memberCount = await User.count({ $or: [{ 'party._id': group._id }, { guilds: group._id }] }).exec();
|
||||
group.leader = user._id;
|
||||
user.guilds.push(group._id);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue