Skip to content

Commit 7380498

Browse files
committed
feat: update clientTimezone regex to support additional characters and add tests for heatmap and views endpoints
1 parent e7d7e1d commit 7380498

3 files changed

Lines changed: 34 additions & 2 deletions

File tree

server/api/stats/heatmap.get.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const { select } = SqlBricks
66

77
const HeatmapQuerySchema = QuerySchema.extend({
88
clientTimezone: z.string()
9-
.regex(/^[A-Z_]+(?:\/[A-Z_-]+)*$/i)
9+
.regex(/^[\w+-]+(?:\/[\w+-]+)*$/)
1010
.max(64)
1111
.default('Etc/UTC'),
1212
})

server/api/stats/views.get.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const unitMap: { [x: string]: string } = {
1313
const ViewsQuerySchema = QuerySchema.extend({
1414
unit: z.enum(['minute', 'hour', 'day']),
1515
clientTimezone: z.string()
16-
.regex(/^[A-Z_]+(?:\/[A-Z_-]+)*$/i)
16+
.regex(/^[\w+-]+(?:\/[\w+-]+)*$/)
1717
.max(64)
1818
.default('Etc/UTC'),
1919
})

tests/api/stats.spec.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,12 @@ describe('/api/stats/views', () => {
100100
expect(response.status).toBe(200)
101101
})
102102

103+
it('supports offset-style clientTimezone values', async () => {
104+
const response = await fetchWithAuth('/api/stats/views?slug=0&unit=day&clientTimezone=Etc/GMT-8')
105+
106+
expect(response.status).toBe(200)
107+
})
108+
103109
it('returns 400 for invalid clientTimezone format', async () => {
104110
const response = await fetchWithAuth('/api/stats/views?slug=0&unit=day&clientTimezone=invalid<>timezone')
105111

@@ -124,3 +130,29 @@ describe('/api/stats/views', () => {
124130
expect(response.status).toBe(401)
125131
})
126132
})
133+
134+
describe('/api/stats/heatmap', () => {
135+
it('supports clientTimezone parameter', async () => {
136+
const response = await fetchWithAuth('/api/stats/heatmap?clientTimezone=Asia/Shanghai')
137+
138+
expect(response.status).toBe(200)
139+
})
140+
141+
it('supports offset-style clientTimezone values', async () => {
142+
const response = await fetchWithAuth('/api/stats/heatmap?clientTimezone=Etc/GMT-8')
143+
144+
expect(response.status).toBe(200)
145+
})
146+
147+
it('returns 400 for invalid clientTimezone format', async () => {
148+
const response = await fetchWithAuth('/api/stats/heatmap?clientTimezone=invalid<>timezone')
149+
150+
expect(response.status).toBe(400)
151+
})
152+
153+
it('returns 401 when accessing without auth', async () => {
154+
const response = await fetch('/api/stats/heatmap?clientTimezone=Asia/Shanghai')
155+
156+
expect(response.status).toBe(401)
157+
})
158+
})

0 commit comments

Comments
 (0)