Skip to content
Merged
Show file tree
Hide file tree
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
9 changes: 4 additions & 5 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
DB_URL = file:database/local.db # location of local database
DB_AUTH_TOKEN = # you can leave this empty for local development
DB_HTTP_URL = # you can leave this empty for local development
DB_AUTH_TOKEN_HTTP = # you can leave this empty for local development
INTERNAL_API_KEY = # you can leave this empty for local development
DB_URL = file:database/local.db # location of local database
DB_AUTH_TOKEN = # you can leave this empty for local development
DB_VISITS_AUTH_TOKEN = # you can leave this empty for local development
DB_VISITS_URL = file:database/visits.db # location of local database with site visits
15 changes: 6 additions & 9 deletions .github/workflows/_deploy-reusable.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,14 @@ on:
required: true
DB_AUTH_TOKEN:
required: true
DB_HTTP_URL:
required: true
DB_AUTH_TOKEN_HTTP:
required: true
INTERNAL_API_KEY:
required: true
NETLIFY_SITE_ID:
required: true
NETLIFY_ACCESS_TOKEN:
required: true
DB_VISITS_URL:
required: true
DB_VISITS_AUTH_TOKEN:
required: true

jobs:
build-and-deploy:
Expand Down Expand Up @@ -64,9 +62,8 @@ jobs:
env:
DB_URL: ${{ secrets.DB_URL }}
DB_AUTH_TOKEN: ${{ secrets.DB_AUTH_TOKEN }}
DB_HTTP_URL: ${{ secrets.DB_HTTP_URL }}
DB_AUTH_TOKEN_HTTP: ${{ secrets.DB_AUTH_TOKEN_HTTP }}
INTERNAL_API_KEY: ${{ secrets.INTERNAL_API_KEY }}
DB_VISITS_URL: ${{ secrets.DB_VISITS_URL }}
DB_VISITS_AUTH_TOKEN: ${{ secrets.DB_VISITS_AUTH_TOKEN }}
run: pnpm build

- name: Get latest commit message
Expand Down
5 changes: 2 additions & 3 deletions .github/workflows/deploy-preview-skip-db.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ jobs:
secrets:
DB_URL: ${{ secrets.DB_PREVIEW_URL }}
DB_AUTH_TOKEN: ${{ secrets.DB_PREVIEW_AUTH_TOKEN }}
DB_HTTP_URL: ${{ secrets.DB_PREVIEW_HTTP_URL }}
DB_AUTH_TOKEN_HTTP: ${{ secrets.DB_PREVIEW_AUTH_TOKEN_HTTP }}
INTERNAL_API_KEY: ${{ secrets.INTERNAL_API_KEY }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
NETLIFY_ACCESS_TOKEN: ${{ secrets.NETLIFY_ACCESS_TOKEN }}
DB_VISITS_URL: ${{ secrets.DB_VISITS_URL }}
DB_VISITS_AUTH_TOKEN: ${{ secrets.DB_VISITS_AUTH_TOKEN }}
5 changes: 2 additions & 3 deletions .github/workflows/deploy-preview.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ jobs:
secrets:
DB_URL: ${{ secrets.DB_PREVIEW_URL }}
DB_AUTH_TOKEN: ${{ secrets.DB_PREVIEW_AUTH_TOKEN }}
DB_HTTP_URL: ${{ secrets.DB_PREVIEW_HTTP_URL }}
DB_AUTH_TOKEN_HTTP: ${{ secrets.DB_PREVIEW_AUTH_TOKEN_HTTP }}
INTERNAL_API_KEY: ${{ secrets.INTERNAL_API_KEY }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
NETLIFY_ACCESS_TOKEN: ${{ secrets.NETLIFY_ACCESS_TOKEN }}
DB_VISITS_URL: ${{ secrets.DB_VISITS_URL }}
DB_VISITS_AUTH_TOKEN: ${{ secrets.DB_VISITS_AUTH_TOKEN }}
5 changes: 2 additions & 3 deletions .github/workflows/deploy-prod-skip-db.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ jobs:
secrets:
DB_URL: ${{ secrets.DB_URL }}
DB_AUTH_TOKEN: ${{ secrets.DB_AUTH_TOKEN }}
DB_HTTP_URL: ${{ secrets.DB_HTTP_URL }}
DB_AUTH_TOKEN_HTTP: ${{ secrets.DB_AUTH_TOKEN_HTTP }}
INTERNAL_API_KEY: ${{ secrets.INTERNAL_API_KEY }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
NETLIFY_ACCESS_TOKEN: ${{ secrets.NETLIFY_ACCESS_TOKEN }}
DB_VISITS_URL: ${{ secrets.DB_VISITS_URL }}
DB_VISITS_AUTH_TOKEN: ${{ secrets.DB_VISITS_AUTH_TOKEN }}
5 changes: 2 additions & 3 deletions .github/workflows/deploy-prod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ jobs:
secrets:
DB_URL: ${{ secrets.DB_URL }}
DB_AUTH_TOKEN: ${{ secrets.DB_AUTH_TOKEN }}
DB_HTTP_URL: ${{ secrets.DB_HTTP_URL }}
DB_AUTH_TOKEN_HTTP: ${{ secrets.DB_AUTH_TOKEN_HTTP }}
INTERNAL_API_KEY: ${{ secrets.INTERNAL_API_KEY }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
NETLIFY_ACCESS_TOKEN: ${{ secrets.NETLIFY_ACCESS_TOKEN }}
DB_VISITS_URL: ${{ secrets.DB_VISITS_URL }}
DB_VISITS_AUTH_TOKEN: ${{ secrets.DB_VISITS_AUTH_TOKEN }}
1 change: 1 addition & 0 deletions database/migrations/014_drop-visits.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DROP TABLE visits; -- will record these in a separate db
12 changes: 11 additions & 1 deletion src/lib/server/db.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { DB_AUTH_TOKEN, DB_URL } from '$env/static/private'
import {
DB_AUTH_TOKEN,
DB_URL,
DB_VISITS_AUTH_TOKEN,
DB_VISITS_URL,
} from '$env/static/private'
import { createClient, type LibsqlError } from '@libsql/client'
import type { Arrayed } from '$lib/commons/types'

Expand Down Expand Up @@ -41,3 +46,8 @@ export async function batch<T extends any[]>(queries: { sql: string; values: any
return { results: null, err: err as LibsqlError }
}
}

export const db_visits = createClient({
url: DB_VISITS_URL,
authToken: DB_VISITS_AUTH_TOKEN,
})
25 changes: 0 additions & 25 deletions src/routes/api/db-dump/+server.ts

This file was deleted.

18 changes: 10 additions & 8 deletions src/routes/api/track/+server.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { query } from '$lib/server/db'
import { is_object } from '$lib/server/utils'
import { json } from '@sveltejs/kit'
import sql from 'sql-template-tag'
import { get_geo_data, is_allowed } from './track.utils'
import { db_visits } from '$lib/server/db'

type ValidBody = { device_type: string; theme: string }

Expand Down Expand Up @@ -30,12 +29,15 @@ export const POST = async (event) => {

const { country } = get_geo_data(event.request)

const { err } = await query(sql`
INSERT INTO visits (theme, device_type, country)
VALUES (${theme}, ${device_type}, ${country})
`)

if (err) return json({ error: 'Database error' }, { status: 500 })
try {
await db_visits.execute(
`INSERT INTO visits (theme, device_type, country) VALUES (?, ?, ?)`,
[theme, device_type, country],
)
} catch (err) {
console.error(err)
return json({ error: 'Database error' }, { status: 500 })
}

return json({ message: 'Visit has been tracked' })
}
127 changes: 64 additions & 63 deletions src/routes/stats/+page.server.ts
Original file line number Diff line number Diff line change
@@ -1,99 +1,100 @@
import { batch } from '$lib/server/db'
import { db_visits } from '$lib/server/db'
import { error } from '@sveltejs/kit'
import sql from 'sql-template-tag'

export const prerender = false

const COUNTRY_COUNT_THRESHOLD = 10

export const load = async () => {
const { results, err } = await batch<
[
{
start: string
total: number
total_last_day: number
total_last_week: number
total_last_month: number
},
{ day: string; count: number },
{ country: string; count: number },
{ theme: string; count: number },
{ device_type: string; count: number },
]
>([
sql`
SELECT
try {
const results = await db_visits.batch([
`SELECT
COALESCE(MIN(created_at), '') AS start,
COUNT(*) AS total,
COUNT(CASE WHEN created_at >= datetime('now', '-1 day') THEN 1 END) AS total_last_day,
COUNT(CASE WHEN created_at >= datetime('now', '-7 days') THEN 1 END) AS total_last_week,
COUNT(CASE WHEN created_at >= datetime('now', '-1 month') THEN 1 END) AS total_last_month
FROM visits;
`,
sql`
SELECT
FROM visits`,
`SELECT
date(created_at) AS day,
COUNT(*) AS count
FROM visits
GROUP BY day
ORDER BY day;
`,
sql`
SELECT
ORDER BY day`,
`SELECT
country,
COUNT(*) as count
FROM visits
GROUP BY country
ORDER BY count DESC;
`,
sql`
SELECT
ORDER BY count DESC`,
`SELECT
theme,
COUNT(*) as count
FROM visits
GROUP BY theme
ORDER BY theme;
`,
sql`
SELECT
ORDER BY theme`,
`SELECT
device_type,
COUNT(*) as count
FROM visits
GROUP BY device_type
ORDER BY count DESC;
`,
])
ORDER BY count DESC`,
])

if (err) error(500, 'Failed to load data')
const summary = results[0].rows[0] as unknown as {
start: string
total: number
total_last_day: number
total_last_week: number
total_last_month: number
}

const [
[{ total, start, total_last_day, total_last_week, total_last_month }],
daily_visits,
detailed_country_stats,
theme_stats,
device_stats,
] = results
const { start, total, total_last_day, total_last_week, total_last_month } =
summary

const country_stats: typeof detailed_country_stats = []
let other_count = 0
const daily_visits = results[1].rows as unknown as {
day: string
count: number
}[]

for (const { country, count } of detailed_country_stats) {
if (count <= COUNTRY_COUNT_THRESHOLD) other_count += count
else country_stats.push({ country, count })
}
const detailed_country_stats = results[2].rows as unknown as {
country: string
count: number
}[]

const theme_stats = results[3].rows as unknown as {
theme: string
count: number
}[]

const device_stats = results[4].rows as unknown as {
device_type: string
count: number
}[]

const country_stats: typeof detailed_country_stats = []
let other_count = 0

for (const { country, count } of detailed_country_stats) {
if (count <= COUNTRY_COUNT_THRESHOLD) other_count += count
else country_stats.push({ country, count })
}

country_stats.push({ country: 'Others', count: other_count })
country_stats.push({ country: 'Others', count: other_count })

return {
start,
total,
total_last_day,
total_last_week,
total_last_month,
daily_visits,
country_stats,
theme_stats,
device_stats,
return {
start,
total,
total_last_day,
total_last_week,
total_last_month,
daily_visits,
country_stats,
theme_stats,
device_stats,
}
} catch (err) {
console.error(err)
error(500, 'Failed to load data')
}
}