diff --git a/src/actions/points-system/calculate-user-points.ts b/src/actions/points-system/calculate-user-points.ts new file mode 100644 index 00000000..20eef08a --- /dev/null +++ b/src/actions/points-system/calculate-user-points.ts @@ -0,0 +1,63 @@ +import { Op } from "sequelize"; +import db, { sequelizeConnection } from "src/db"; +import logger from "src/utils/logger-handler"; + +export const name = "CalculatePointsDaily"; +export const schedule = "0 0 * * *"; +export const description = "Calculate total points and update users' total points"; +export const author = "Vitor Hugo"; + +export async function action() { + logger.info(`${name} start`); + + const events = await db.points_events.findAll({ + where: { + pointsCounted: false, + }, + order: ["userId"], + raw: true + }); + + if (!events?.length) { + logger.info(`${name} no uncounted events found`); + return; + } + + const pointsByUser = {} as { [userId: string]: { total: number, eventsIds: number[] } }; + + for (const event of events) { + if (!pointsByUser[event.userId]) + pointsByUser[event.userId] = { total: 0, eventsIds: [] }; + + pointsByUser[event.userId].total += event.pointsWon; + pointsByUser[event.userId].eventsIds.push(event.id); + } + + const updateUserPoints = Object.entries(pointsByUser).map(([id, { total }]) => ({ id, total })); + const parsedEventsIds = Object.values(pointsByUser).map(({ eventsIds }) => eventsIds).flat(); + + try { + await Promise.all(updateUserPoints.map(item => db.users.update({ + totalPoints: item.total + }, { + where: { + id: item.id + } + }))); + + await db.points_events.update({ + pointsCounted: true, + }, { + where: { + id: { + [Op.in]: parsedEventsIds + } + } + }); + + + logger.info(`${name} updated user points`, updateUserPoints); + } catch(error) { + logger.error(`${name} failed to update user points`, updateUserPoints, error); + } +} \ No newline at end of file diff --git a/src/db/index.ts b/src/db/index.ts index cae961fa..d4a4e004 100644 --- a/src/db/index.ts +++ b/src/db/index.ts @@ -34,13 +34,13 @@ if (NEXT_DB_SSL === "true") }, }; -const con = new Sequelize( +export const sequelizeConnection = new Sequelize( options.database!, options.username!, options.password!, options ); -const modules = initModels(con); +const modules = initModels(sequelizeConnection); export default modules; diff --git a/src/modules/chain-events.ts b/src/modules/chain-events.ts index f96133e2..1bac338f 100644 --- a/src/modules/chain-events.ts +++ b/src/modules/chain-events.ts @@ -23,6 +23,7 @@ import {action as UpdateHeaders} from "../actions/get-prices-header-information" import {action as GenerateNftImage} from "../actions/generate-nft-images"; import {action as UserLockedAmountChanged} from "../actions/get-user-locked-amount-changed-event"; import {action as ChangedFee} from "../actions/get-changed-fee"; +import {action as CalculateUserPoints} from "../actions/points-system/calculate-user-points"; /** * These events rely on parsed-logs to function and can/will rely on Database information, as well as update it @@ -55,6 +56,7 @@ export const MIDNIGHT_ACTIONS = { DeletePendingNetworks, DeletePendingBounties, UpdateNetworkParams, + CalculateUserPoints, } export const MINUTE_ACTIONS = {