From 746c087dc20d3a2a94ffe402c2be5bc5f9cd39f1 Mon Sep 17 00:00:00 2001 From: fegloff Date: Wed, 10 Jan 2024 12:18:51 -0400 Subject: [PATCH 1/5] add revenue report --- src/database/stats.service.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/database/stats.service.ts b/src/database/stats.service.ts index fa6dde73..cceb867d 100644 --- a/src/database/stats.service.ts +++ b/src/database/stats.service.ts @@ -113,6 +113,24 @@ export class StatsService { return rows } + public async getRevenue (daysPeriod = 7): Promise { + const currentTime = moment() + const dateStart = moment() + .tz('America/Los_Angeles') + .set({ hour: 0, minute: 0, second: 0 }) + .subtract(daysPeriod, 'days') + .unix() + + const dateEnd = currentTime.unix() + const result = await logRepository.createQueryBuilder('logs') + // const result = await invoiceRepository.createQueryBuilder('invoice') + .select('SUM(CAST(logs.amountCredits AS NUMERIC)) AS revenue') + .where('logs.isSupportedCommand=true') + .andWhere(`logs.createdAt BETWEEN TO_TIMESTAMP(${dateStart}) and TO_TIMESTAMP(${dateEnd})`) + .execute() + return result[0].revenue + } + public async addCommandStat ({ tgUserId, rawMessage, command }: { tgUserId: number, rawMessage: string, command: string }): Promise { const stat = new StatBotCommand() From b6d611a4e5adfe68dcdcde2a4fc1f6ef2d921b6b Mon Sep 17 00:00:00 2001 From: fegloff Date: Wed, 10 Jan 2024 23:03:54 -0400 Subject: [PATCH 2/5] add total and weekly reports + getNewUser (work in progress) --- src/database/stats.service.ts | 30 ++++++++++++++++++++++++++---- src/modules/schedule/index.ts | 29 +++++++++++++++++++++++------ 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/src/database/stats.service.ts b/src/database/stats.service.ts index cceb867d..19ac1229 100644 --- a/src/database/stats.service.ts +++ b/src/database/stats.service.ts @@ -70,6 +70,28 @@ export class StatsService { return rows.length ? +rows[0].count : 0 } + public async getNewUsers (daysPeriod = 0): Promise { + const currentTime = moment() + const dateStart = moment() + .tz('America/Los_Angeles') + .set({ hour: 0, minute: 0, second: 0 }) + .subtract(daysPeriod, 'days') + .unix() + + const dateEnd = currentTime.unix() + const query = logRepository + .createQueryBuilder('logs') + .select('tgUserId') + .where( + 'logs.createdAt = (SELECT MIN(createdAt) FROM logs WHERE tgUserId = logs.tgUserId)' + ) + .andWhere(`logs.createdAt BETWEEN TO_TIMESTAMP(${dateStart}) and TO_TIMESTAMP(${dateEnd})`) + + const result = await query.getMany() + console.log(`DAYS ${daysPeriod}`, result) + return 8 + } + public async getTotalMessages (daysPeriod = 0, onlySupportedCommands = false): Promise { const currentTime = moment() const dateStart = moment() @@ -83,8 +105,9 @@ export class StatsService { const query = logRepository .createQueryBuilder('logs') .select('count(*)') - .where(`logs.createdAt BETWEEN TO_TIMESTAMP(${dateStart}) and TO_TIMESTAMP(${dateEnd})`) - + if (daysPeriod > 0) { + query.where(`logs.createdAt BETWEEN TO_TIMESTAMP(${dateStart}) and TO_TIMESTAMP(${dateEnd})`) + } if (onlySupportedCommands) { query.andWhere('logs.isSupportedCommand=true') } @@ -113,7 +136,7 @@ export class StatsService { return rows } - public async getRevenue (daysPeriod = 7): Promise { + public async getRevenueFromLog (daysPeriod = 7): Promise { const currentTime = moment() const dateStart = moment() .tz('America/Los_Angeles') @@ -123,7 +146,6 @@ export class StatsService { const dateEnd = currentTime.unix() const result = await logRepository.createQueryBuilder('logs') - // const result = await invoiceRepository.createQueryBuilder('invoice') .select('SUM(CAST(logs.amountCredits AS NUMERIC)) AS revenue') .where('logs.isSupportedCommand=true') .andWhere(`logs.createdAt BETWEEN TO_TIMESTAMP(${dateStart}) and TO_TIMESTAMP(${dateEnd})`) diff --git a/src/modules/schedule/index.ts b/src/modules/schedule/index.ts index 0b50bddc..851fa194 100644 --- a/src/modules/schedule/index.ts +++ b/src/modules/schedule/index.ts @@ -92,8 +92,12 @@ export class BotSchedule { swapTradingVolume, balance, + uniqueUsersCount, + totalMessage, + weeklyUsers, - dailyMessages + dailyMessages, + weeklyRevenue ] = await Promise.all([ getDailyMetrics(MetricsDailyType.totalFee, 7), getDailyMetrics(MetricsDailyType.walletsCount, 7), @@ -104,9 +108,16 @@ export class BotSchedule { getTradingVolume(7), getAddressBalance(this.holderAddress), + statsService.getUniqueUsersCount(), + statsService.getTotalMessages(0, true), + statsService.getActiveUsers(7), - statsService.getTotalMessages(1, true) + statsService.getTotalMessages(7, true), + getBotFee(this.holderAddress, 7) // statsService.getRevenue(100) ]) + // await statsService.getNewUsers(100) + // await statsService.getNewUsers(400) + // await statsService.getNewUsers(600) const networkFeesSum = networkFeesWeekly.reduce((sum, item) => sum + +item.value, 0) const walletsCountSum = walletsCountWeekly.reduce((sum, item) => sum + +item.value, 0) @@ -123,13 +134,19 @@ export class BotSchedule { 'Total assets, monthly stakes, weekly swaps: ' + `*$${abbreviateNumber(bridgeTVL)}*, ${abbreviateNumber(totalStakeONE)}, $${abbreviateNumber(swapTradingVolumeSum)}` - const oneBotMetrics = - 'Bot total earns, weekly users, daily messages: ' + - `*${abbreviateNumber(balance / Math.pow(10, 18))}* ONE` + + const oneBotWeeklyMetrics = + 'Bot weekly earns, users, messages: ' + + `*${abbreviateNumber(+weeklyRevenue)}* ONE` + `, ${lessThan100(abbreviateNumber(weeklyUsers))}` + `, ${lessThan100(abbreviateNumber(dailyMessages))}` - return `${networkUsage}\n${assetsUpdate}\n${oneBotMetrics}` + const oneBotMetrics = + 'Bot total earns, users, messages: ' + + `*${abbreviateNumber(balance / Math.pow(10, 18))}* ONE` + + `, ${lessThan100(abbreviateNumber(uniqueUsersCount))}` + + `, ${lessThan100(abbreviateNumber(totalMessage))}` + + return `${networkUsage}\n${assetsUpdate}\n${oneBotWeeklyMetrics}\n${oneBotMetrics}` } public async generateReportEngagementByCommand (days: number): Promise { From 6b0ef48bec8466802dde118b1cb2d1ac701b38d8 Mon Sep 17 00:00:00 2001 From: fegloff Date: Thu, 11 Jan 2024 15:22:52 -0400 Subject: [PATCH 3/5] fix new users report --- src/database/stats.service.ts | 23 ++++++++++++++--------- src/modules/schedule/index.ts | 11 ++++------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/database/stats.service.ts b/src/database/stats.service.ts index 19ac1229..1ed98f1e 100644 --- a/src/database/stats.service.ts +++ b/src/database/stats.service.ts @@ -79,17 +79,22 @@ export class StatsService { .unix() const dateEnd = currentTime.unix() + const query = logRepository .createQueryBuilder('logs') - .select('tgUserId') - .where( - 'logs.createdAt = (SELECT MIN(createdAt) FROM logs WHERE tgUserId = logs.tgUserId)' - ) - .andWhere(`logs.createdAt BETWEEN TO_TIMESTAMP(${dateStart}) and TO_TIMESTAMP(${dateEnd})`) - - const result = await query.getMany() - console.log(`DAYS ${daysPeriod}`, result) - return 8 + .select('distinct("FirstInsertTime")') // distinct("FirstInsertTime")') // 'logs."tgUserId", MIN(logs."createdAt") AS "FirstTime"') + .from(subQuery => + subQuery + .select('"tgUserId", MIN("createdAt") AS "FirstInsertTime"') + .from(BotLog, 'logs') + .groupBy('"tgUserId"'), 'first_inserts') + if (daysPeriod > 0) { + query.where(`"FirstInsertTime" BETWEEN TO_TIMESTAMP(${dateStart}) and TO_TIMESTAMP(${dateEnd})`) + } + // query.groupBy('logs."tgUserId"') + const result = await query.execute() + // console.log(dateStart, dateEnd, result.length) + return result.length } public async getTotalMessages (daysPeriod = 0, onlySupportedCommands = false): Promise { diff --git a/src/modules/schedule/index.ts b/src/modules/schedule/index.ts index 851fa194..6b61be60 100644 --- a/src/modules/schedule/index.ts +++ b/src/modules/schedule/index.ts @@ -96,7 +96,7 @@ export class BotSchedule { totalMessage, weeklyUsers, - dailyMessages, + newUsers, weeklyRevenue ] = await Promise.all([ getDailyMetrics(MetricsDailyType.totalFee, 7), @@ -112,12 +112,9 @@ export class BotSchedule { statsService.getTotalMessages(0, true), statsService.getActiveUsers(7), - statsService.getTotalMessages(7, true), + statsService.getNewUsers(7), getBotFee(this.holderAddress, 7) // statsService.getRevenue(100) ]) - // await statsService.getNewUsers(100) - // await statsService.getNewUsers(400) - // await statsService.getNewUsers(600) const networkFeesSum = networkFeesWeekly.reduce((sum, item) => sum + +item.value, 0) const walletsCountSum = walletsCountWeekly.reduce((sum, item) => sum + +item.value, 0) @@ -135,10 +132,10 @@ export class BotSchedule { `*$${abbreviateNumber(bridgeTVL)}*, ${abbreviateNumber(totalStakeONE)}, $${abbreviateNumber(swapTradingVolumeSum)}` const oneBotWeeklyMetrics = - 'Bot weekly earns, users, messages: ' + + 'Bot weekly earns, active users, new users: ' + `*${abbreviateNumber(+weeklyRevenue)}* ONE` + `, ${lessThan100(abbreviateNumber(weeklyUsers))}` + - `, ${lessThan100(abbreviateNumber(dailyMessages))}` + `, ${lessThan100(abbreviateNumber(newUsers))}` const oneBotMetrics = 'Bot total earns, users, messages: ' + From fb2c3dc2fe3ddfeb4cf0dcb7c5aee58fb52ba4ef Mon Sep 17 00:00:00 2001 From: fegloff Date: Fri, 12 Jan 2024 13:16:01 -0400 Subject: [PATCH 4/5] add one-time user report --- src/database/stats.service.ts | 22 ++++++++++++++++++++-- src/modules/schedule/index.ts | 10 ++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/database/stats.service.ts b/src/database/stats.service.ts index 1ed98f1e..09e3d98e 100644 --- a/src/database/stats.service.ts +++ b/src/database/stats.service.ts @@ -82,7 +82,7 @@ export class StatsService { const query = logRepository .createQueryBuilder('logs') - .select('distinct("FirstInsertTime")') // distinct("FirstInsertTime")') // 'logs."tgUserId", MIN(logs."createdAt") AS "FirstTime"') + .select('distinct("FirstInsertTime")') .from(subQuery => subQuery .select('"tgUserId", MIN("createdAt") AS "FirstInsertTime"') @@ -91,12 +91,30 @@ export class StatsService { if (daysPeriod > 0) { query.where(`"FirstInsertTime" BETWEEN TO_TIMESTAMP(${dateStart}) and TO_TIMESTAMP(${dateEnd})`) } - // query.groupBy('logs."tgUserId"') const result = await query.execute() // console.log(dateStart, dateEnd, result.length) return result.length } + // Doesn't check last 7 days. + public async getOnetimeUsers (): Promise { + const bufferDays = 7 + const bufferDate = moment() + .tz('America/Los_Angeles') + .set({ hour: 0, minute: 0, second: 0 }) + .subtract(bufferDays, 'days') + .unix() + + const query = await logRepository + .createQueryBuilder('logs') + .select('count("tgUserId") AS row_count, "tgUserId", MAX("createdAt") AS max_created') + .where(`"createdAt" < TO_TIMESTAMP(${bufferDate})`) + .groupBy('"tgUserId"') + .getRawMany() + const result = query.filter(row => row.row_count === '1') + return result.length + } + public async getTotalMessages (daysPeriod = 0, onlySupportedCommands = false): Promise { const currentTime = moment() const dateStart = moment() diff --git a/src/modules/schedule/index.ts b/src/modules/schedule/index.ts index 6b61be60..9c6128de 100644 --- a/src/modules/schedule/index.ts +++ b/src/modules/schedule/index.ts @@ -177,7 +177,9 @@ export class BotSchedule { weeklyUsers, totalMessages, totalSupportedMessages, - engagementByCommand + engagementByCommand, + onetimeUsers, + newUsers ] = await Promise.all([ this.getBotFeeReport(this.holderAddress), getBotFee(this.holderAddress, 7), @@ -187,15 +189,19 @@ export class BotSchedule { statsService.getActiveUsers(7), statsService.getTotalMessages(7), statsService.getTotalMessages(7, true), - this.generateReportEngagementByCommand(7) + this.generateReportEngagementByCommand(7), + statsService.getOnetimeUsers(), + statsService.getNewUsers(7) ]) const report = `\nBot fees: *${botFeesReport}*` + `\nWeekly bot fees collected: *${abbreviateNumber(botFeesWeekly)}*` + `\nDaily Active Users: *${abbreviateNumber(dau)}*` + + `\nOne-time users: *${onetimeUsers}*` + `\nTotal fees users pay in ONE: *${abbreviateNumber(totalOne)}*` + `\nTotal fees users pay in free credits: *${abbreviateNumber(totalCredits)}*` + `\nWeekly active users: *${abbreviateNumber(weeklyUsers)}*` + + `\nWeekly new users: *${abbreviateNumber(newUsers)}*` + `\nWeekly user engagement (any commands): *${abbreviateNumber(totalMessages)}*` + `\nWeekly user engagement (commands supported by bot): *${abbreviateNumber(totalSupportedMessages)}*` + `\n\n${engagementByCommand}` From fdeb851112f3077b283157dcb4b192c61f72c92f Mon Sep 17 00:00:00 2001 From: fegloff Date: Fri, 12 Jan 2024 13:31:32 -0400 Subject: [PATCH 5/5] update allstats and stats reports --- src/modules/schedule/index.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/modules/schedule/index.ts b/src/modules/schedule/index.ts index 9c6128de..1ed95d75 100644 --- a/src/modules/schedule/index.ts +++ b/src/modules/schedule/index.ts @@ -179,7 +179,8 @@ export class BotSchedule { totalSupportedMessages, engagementByCommand, onetimeUsers, - newUsers + newUsers, + totalUsers ] = await Promise.all([ this.getBotFeeReport(this.holderAddress), getBotFee(this.holderAddress, 7), @@ -191,19 +192,21 @@ export class BotSchedule { statsService.getTotalMessages(7, true), this.generateReportEngagementByCommand(7), statsService.getOnetimeUsers(), - statsService.getNewUsers(7) + statsService.getNewUsers(7), + statsService.getUniqueUsersCount() ]) const report = `\nBot fees: *${botFeesReport}*` + `\nWeekly bot fees collected: *${abbreviateNumber(botFeesWeekly)}*` + `\nDaily Active Users: *${abbreviateNumber(dau)}*` + - `\nOne-time users: *${onetimeUsers}*` + `\nTotal fees users pay in ONE: *${abbreviateNumber(totalOne)}*` + `\nTotal fees users pay in free credits: *${abbreviateNumber(totalCredits)}*` + `\nWeekly active users: *${abbreviateNumber(weeklyUsers)}*` + `\nWeekly new users: *${abbreviateNumber(newUsers)}*` + `\nWeekly user engagement (any commands): *${abbreviateNumber(totalMessages)}*` + `\nWeekly user engagement (commands supported by bot): *${abbreviateNumber(totalSupportedMessages)}*` + + `\nTotal users: *${totalUsers}*` + + `\nOne-time users: *${onetimeUsers}*` + `\n\n${engagementByCommand}` return report }