diff --git a/migrations/archive/2022/20220915_transactions_user_name.js b/migrations/archive/2022/20220915_transactions_user_name.js new file mode 100644 index 0000000000..d652126ea2 --- /dev/null +++ b/migrations/archive/2022/20220915_transactions_user_name.js @@ -0,0 +1,97 @@ +/* eslint-disable no-console */ +import { model as UserModel } from '../../../website/server/models/user'; +import { TransactionModel } from '../../../website/server/models/transaction'; + +const MIGRATION_NAME = '20220915_transactions_user_name'; + +/* transaction config */ +const transactionPerRun = 500; +const progressCount = 1000; +const transactionQuery = { + migration: { $ne: MIGRATION_NAME }, // skip already migrated entries + 'transactionType': { $in: ['gift_send', 'gift_receive'] }, +}; + +let count = 0; +async function updateTransaction (transaction, userNameMap) { + count++; + + const set = { + migration: MIGRATION_NAME, + }; + + if (userNameMap.has(transaction.reference)) { + set['referenceText'] = userNameMap.get(transaction.reference); + } else { + set['referenceText'] = 'Account not found'; + } + + if (count % progressCount === 0) { + console.warn(`${count} ${transaction._id}`); + } + + return TransactionModel.updateOne({ + _id: transaction._id + }, { $set: set }).exec(); +} + +export default async function processTransactions () { + const fields = { + _id: 1, + reference: 1, + referenceText: 1, + }; + + const userNameMap = new Map(); + + while (true) { // eslint-disable-line no-constant-condition + const foundTransactions = await TransactionModel // eslint-disable-line no-await-in-loop + .find(transactionQuery) + .limit(transactionPerRun) + .sort({reference: 1}) + .select(fields) + .lean() + .exec(); + + if (foundTransactions.length === 0) { + console.warn('All appropriate transactions found and modified.'); + console.warn(`\n${count} transactions processed\n`); + break; + } + + // check for unknown users and load the names + const userIdsToLoad = []; + for (const foundTransaction of foundTransactions) { + const userId = foundTransaction.reference; + if (userNameMap.has(userId)) { + continue; + } + + userIdsToLoad.push(userId); + } + + const users = await UserModel // eslint-disable-line no-await-in-loop + .find({ + _id: { $in: userIdsToLoad } + }) + .select({ + _id: 1, + 'auth.local.username': 1, + }) + .lean() + .exec(); + + for (const user of users) { + const localUserName = user.auth?.local?.username; + + if (!localUserName) { + console.warn(`\nNo Username found for ID: ${user._id}\n`); + continue; + } + + userNameMap.set(user._id, localUserName) + } + + await Promise.all(foundTransactions.map(t => updateTransaction(t, userNameMap))); // eslint-disable-line no-await-in-loop + } +}; diff --git a/website/server/controllers/api-v4/members.js b/website/server/controllers/api-v4/members.js index c4a49c09d1..360f0e948e 100644 --- a/website/server/controllers/api-v4/members.js +++ b/website/server/controllers/api-v4/members.js @@ -1,7 +1,7 @@ import { authWithHeaders } from '../../middlewares/auth'; import { chatReporterFactory } from '../../libs/chatReporting/chatReporterFactory'; import { ensurePermission } from '../../middlewares/ensureAccessRight'; -import { model as Transaction } from '../../models/transaction'; +import { TransactionModel as Transaction } from '../../models/transaction'; const api = {}; diff --git a/website/server/controllers/api-v4/user.js b/website/server/controllers/api-v4/user.js index 1bf32bd982..b0e6e59773 100644 --- a/website/server/controllers/api-v4/user.js +++ b/website/server/controllers/api-v4/user.js @@ -2,7 +2,7 @@ import { authWithHeaders } from '../../middlewares/auth'; import * as userLib from '../../libs/user'; import { verifyDisplayName } from '../../libs/user/validation'; import common from '../../../common'; -import { model as Transaction } from '../../models/transaction'; +import { TransactionModel as Transaction } from '../../models/transaction'; const api = {}; diff --git a/website/server/models/subscriptionPlan.js b/website/server/models/subscriptionPlan.js index 71d92feea2..dc04661142 100644 --- a/website/server/models/subscriptionPlan.js +++ b/website/server/models/subscriptionPlan.js @@ -1,7 +1,7 @@ import mongoose from 'mongoose'; import validator from 'validator'; import baseModel from '../libs/baseModel'; -import { model as Transaction } from './transaction'; +import { TransactionModel as Transaction } from './transaction'; export const schema = new mongoose.Schema({ planId: String, diff --git a/website/server/models/transaction.js b/website/server/models/transaction.js index 56687f86c9..1820234afd 100644 --- a/website/server/models/transaction.js +++ b/website/server/models/transaction.js @@ -17,6 +17,7 @@ export const schema = new Schema({ userId: { $type: String, ref: 'User', required: true, validate: [v => validator.isUUID(v), 'Invalid uuid for Transaction.'], }, + migration: String, }, { strict: true, minimize: false, // So empty objects are returned @@ -34,9 +35,10 @@ schema.plugin(baseModel, { 'referenceText', 'amount', 'currentAmount', + 'migration', ], // Nothing can be set from the client timestamps: true, _id: false, // using custom _id }); -export const model = mongoose.model('Transaction', schema); +export const TransactionModel = mongoose.model('Transaction', schema); diff --git a/website/server/models/user/methods.js b/website/server/models/user/methods.js index f339cff896..8ecd8c8455 100644 --- a/website/server/models/user/methods.js +++ b/website/server/models/user/methods.js @@ -23,7 +23,7 @@ import amazonPayments from '../../libs/payments/amazon'; // eslint-disable-line import stripePayments from '../../libs/payments/stripe'; // eslint-disable-line import/no-cycle import paypalPayments from '../../libs/payments/paypal'; // eslint-disable-line import/no-cycle import { model as NewsPost } from '../newsPost'; -import { model as Transaction } from '../transaction'; +import { TransactionModel as Transaction } from '../transaction'; const { daysSince } = common;