Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: don't return data after today in stats API #963

Merged
merged 5 commits into from
Jan 7, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 23 additions & 7 deletions supabase/functions/_backend/public/statistics/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Context, MiddlewareHandler } from '@hono/hono'
import * as d3 from 'd3'
import dayjs from 'dayjs'
import utc from 'dayjs/plugin/utc'
import { Hono } from 'hono/tiny'
import { JSDOM } from 'jsdom'
import { svgPathProperties } from 'svg-path-properties'
Expand All @@ -9,6 +10,8 @@ import { useCors } from '../../utils/hono.ts'
import { hasAppRight, hasOrgRight, supabaseAdmin, supabaseClient as useSupabaseClient } from '../../utils/supabase.ts'
import { checkKey } from '../../utils/utils.ts'

dayjs.extend(utc)

interface AuthInfo {
userId: string
authType: 'apikey' | 'jwt'
Expand Down Expand Up @@ -99,7 +102,7 @@ app.get('/app/:app_id', async (c: Context) => {
return c.json({ status: 'You can\'t access this app' }, 400)

const supabase = supabaseAdmin(c)
const { data: finalStats, error } = (body.graph === undefined) ? await getNormalStats(appId, null, body.from, body.to, supabase) : await drawGraphForNormalStats(appId, null, body.from, body.to, body.graph, supabase)
const { data: finalStats, error } = (body.graph === undefined) ? await getNormalStats(appId, null, body.from, body.to, supabase, c.get('auth').authType === 'jwt') : await drawGraphForNormalStats(appId, null, body.from, body.to, body.graph, supabase)
if (error)
return c.json({ status: 'Cannot get app statistics', error: JSON.stringify(error) }, 500)

Expand Down Expand Up @@ -135,7 +138,7 @@ app.get('/org/:org_id', async (c: Context) => {
return c.json({ status: 'You can\'t access this organization' }, 400)

const { data: finalStats, error } = (body.graph === undefined)
? await getNormalStats(null, orgId, body.from, body.to, supabase)
? await getNormalStats(null, orgId, body.from, body.to, supabase, c.get('auth').authType === 'jwt')
: await drawGraphForNormalStats(null, orgId, body.from, body.to, body.graph, supabase)

if (error)
Expand Down Expand Up @@ -207,7 +210,7 @@ app.get('/user', async (c: Context) => {
const uniqueOrgs = Array.from(
new Map(orgs.data.map(org => [org.org_id, org])).values(),
)
const stats = await Promise.all(uniqueOrgs.map(org => getNormalStats(null, org.org_id, body.from, body.to, supabase)))
const stats = await Promise.all(uniqueOrgs.map(org => getNormalStats(null, org.org_id, body.from, body.to, supabase, auth.authType === 'jwt')))
const errors = stats.filter(stat => stat.error).map(stat => stat.error)
if (errors.length > 0)
return c.json({ status: 'Cannot get user statistics', error: JSON.stringify(errors) }, 500)
Expand All @@ -228,7 +231,7 @@ app.get('/user', async (c: Context) => {
return c.json({ status: 'ok', statistics: finalStats })
})

async function getNormalStats(appId: string | null, ownerOrg: string | null, from: Date, to: Date, supabase: ReturnType<typeof supabaseAdmin>) {
async function getNormalStats(appId: string | null, ownerOrg: string | null, from: Date, to: Date, supabase: ReturnType<typeof supabaseAdmin>, isDashboard: boolean = false) {
if (!appId && !ownerOrg)
return { data: null, error: 'Invalid appId or ownerOrg' }

Expand All @@ -255,6 +258,7 @@ async function getNormalStats(appId: string | null, ownerOrg: string | null, fro
let mau = createUndefinedArray(graphDays) as number[]
let storage = createUndefinedArray(graphDays) as number[]
let bandwidth = createUndefinedArray(graphDays) as number[]
let gets = isDashboard ? createUndefinedArray(graphDays) as number[] : []

// Group metrics by app_id
let metricsByApp = metrics.reduce((acc, metric) => {
Expand Down Expand Up @@ -294,6 +298,10 @@ async function getNormalStats(appId: string | null, ownerOrg: string | null, fro
bandwidth[dayNumber] += bandwidthVal
else
bandwidth[dayNumber] = bandwidthVal

if (isDashboard) {
gets[dayNumber] = item.get
}
}
})
})
Expand All @@ -317,19 +325,27 @@ async function getNormalStats(appId: string | null, ownerOrg: string | null, fro
mau = (mau as number[]).reduce((p, c) => { if (p.length > 0) { c += p[p.length - 1] } p.push(c); return p }, [] as number[])
// eslint-disable-next-line style/max-statements-per-line
bandwidth = (bandwidth as number[]).reduce((p, c) => { if (p.length > 0) { c += p[p.length - 1] } p.push(c); return p }, [] as number[])
const baseDay = dayjs(from)
if (isDashboard) {
// eslint-disable-next-line style/max-statements-per-line
gets = (gets as number[]).reduce((p, c) => { if (p.length > 0) { c += p[p.length - 1] } p.push(c); return p }, [] as number[])
}
const baseDay = dayjs(from).utc()

const finalStats = createUndefinedArray(graphDays) as { date: string, mau: number, storage: number, bandwidth: number }[]
const finalStats = createUndefinedArray(graphDays) as { date: string, mau: number, storage: number, bandwidth: number, get: number | undefined }[]
const today = dayjs().utc()
for (let i = 0; i < graphDays; i++) {
const day = baseDay.add(i, 'day')
if (day.utc().startOf('day').isAfter(today.utc().endOf('day')))
continue
finalStats[i] = {
mau: mau[i],
storage: storage[i],
bandwidth: bandwidth[i],
get: isDashboard ? gets[i] : undefined,
date: day.toISOString(),
}
}
return { data: finalStats, error: null }
return { data: finalStats.filter(x => !!x), error: null }
}

async function getBundleUsage(appId: string, from: Date, to: Date, shouldGetLatestVersion: boolean, supabase: ReturnType<typeof supabaseAdmin>) {
Expand Down
Loading