Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit6326643

Browse files
committed
allow endtime for today include the hour
1 parent4820c53 commit6326643

File tree

1 file changed

+73
-43
lines changed

1 file changed

+73
-43
lines changed

‎coderd/insights.go

Lines changed: 73 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -66,20 +66,16 @@ func (api *API) insightsUserLatency(rw http.ResponseWriter, r *http.Request) {
6666
return
6767
}
6868

69-
// TODO(mafredri): Client or deployment timezone?
70-
// Example:
71-
// - I want data from Monday - Friday
72-
// - I'm UTC+3 and the deployment is UTC+0
73-
// - Do we select Monday - Friday in UTC+0 or UTC+3?
74-
// - Considering users can be in different timezones, perhaps this should be per-user (but we don't keep track of user timezones).
7569
p:=httpapi.NewQueryParamParser().
7670
Required("start_time").
7771
Required("end_time")
7872
vals:=r.URL.Query()
7973
var (
80-
startTime=p.Time3339Nano(vals, time.Time{},"start_time")
81-
endTime=p.Time3339Nano(vals, time.Time{},"end_time")
82-
templateIDs=p.UUIDs(vals, []uuid.UUID{},"template_ids")
74+
// The QueryParamParser does not preserve timezone, so we need
75+
// to parse the time ourselves.
76+
startTimeString=p.String(vals,"","start_time")
77+
endTimeString=p.String(vals,"","end_time")
78+
templateIDs=p.UUIDs(vals, []uuid.UUID{},"template_ids")
8379
)
8480
p.ErrorExcessParams(vals)
8581
iflen(p.Errors)>0 {
@@ -90,15 +86,11 @@ func (api *API) insightsUserLatency(rw http.ResponseWriter, r *http.Request) {
9086
return
9187
}
9288

93-
if!verifyInsightsStartAndEndTime(ctx,rw,startTime,endTime) {
89+
startTime,endTime,ok:=parseInsightsStartAndEndTime(ctx,rw,startTimeString,endTimeString)
90+
if!ok {
9491
return
9592
}
9693

97-
// Should we verify all template IDs exist, or just return no rows?
98-
// _, err := api.Database.GetTemplatesWithFilter(ctx, database.GetTemplatesWithFilterParams{
99-
// IDs: templateIDs,
100-
// })
101-
10294
rows,err:=api.Database.GetUserLatencyInsights(ctx, database.GetUserLatencyInsightsParams{
10395
StartTime:startTime,
10496
EndTime:endTime,
@@ -192,10 +184,12 @@ func (api *API) insightsTemplates(rw http.ResponseWriter, r *http.Request) {
192184
Required("end_time")
193185
vals:=r.URL.Query()
194186
var (
195-
startTime=p.Time3339Nano(vals, time.Time{},"start_time")
196-
endTime=p.Time3339Nano(vals, time.Time{},"end_time")
197-
intervalString=p.String(vals,string(codersdk.InsightsReportIntervalNone),"interval")
198-
templateIDs=p.UUIDs(vals, []uuid.UUID{},"template_ids")
187+
// The QueryParamParser does not preserve timezone, so we need
188+
// to parse the time ourselves.
189+
startTimeString=p.String(vals,"","start_time")
190+
endTimeString=p.String(vals,"","end_time")
191+
intervalString=p.String(vals,string(codersdk.InsightsReportIntervalNone),"interval")
192+
templateIDs=p.UUIDs(vals, []uuid.UUID{},"template_ids")
199193
)
200194
p.ErrorExcessParams(vals)
201195
iflen(p.Errors)>0 {
@@ -206,19 +200,15 @@ func (api *API) insightsTemplates(rw http.ResponseWriter, r *http.Request) {
206200
return
207201
}
208202

209-
if!verifyInsightsStartAndEndTime(ctx,rw,startTime,endTime) {
203+
startTime,endTime,ok:=parseInsightsStartAndEndTime(ctx,rw,startTimeString,endTimeString)
204+
if!ok {
210205
return
211206
}
212207
interval,ok:=verifyInsightsInterval(ctx,rw,intervalString)
213208
if!ok {
214209
return
215210
}
216211

217-
// Should we verify all template IDs exist, or just return no rows?
218-
// _, err := api.Database.GetTemplatesWithFilter(ctx, database.GetTemplatesWithFilterParams{
219-
// IDs: templateIDs,
220-
// })
221-
222212
varusage database.GetTemplateInsightsRow
223213
vardailyUsage []database.GetTemplateDailyInsightsRow
224214
// Use a transaction to ensure that we get consistent data between
@@ -310,54 +300,94 @@ func (api *API) insightsTemplates(rw http.ResponseWriter, r *http.Request) {
310300
httpapi.Write(ctx,rw,http.StatusOK,resp)
311301
}
312302

313-
funcverifyInsightsStartAndEndTime(ctx context.Context,rw http.ResponseWriter,startTime,endTime time.Time)bool {
314-
for_,v:=range []struct {
315-
namestring
316-
t time.Time
303+
// parseInsightsStartAndEndTime parses the start and end time query parameters
304+
// and returns the parsed values. The client provided timezone must be preserved
305+
// when parsing the time. Verification is performed so that the start and end
306+
// time are not zero and that the end time is not before the start time. The
307+
// clock must be set to 00:00:00, except for "today", where end time is allowed
308+
// to provide the hour of the day (e.g. 14:00:00).
309+
funcparseInsightsStartAndEndTime(ctx context.Context,rw http.ResponseWriter,startTimeString,endTimeStringstring) (startTime,endTime time.Time,okbool) {
310+
constinsightsTimeLayout=time.RFC3339Nano
311+
312+
for_,qp:=range []struct {
313+
name,valuestring
314+
dest*time.Time
317315
}{
318-
{"start_time",startTime},
319-
{"end_time",endTime},
316+
{"start_time",startTimeString,&startTime},
317+
{"end_time",endTimeString,&endTime},
320318
} {
321-
ifv.t.IsZero() {
319+
t,err:=time.Parse(insightsTimeLayout,qp.value)
320+
iferr!=nil {
322321
httpapi.Write(ctx,rw,http.StatusBadRequest, codersdk.Response{
323322
Message:"Query parameter has invalid value.",
324323
Validations: []codersdk.ValidationError{
325324
{
326-
Field:v.name,
327-
Detail:"must benot be zero",
325+
Field:qp.name,
326+
Detail:fmt.Sprintf("Query param %qmust bea valid date format (%s): %s",qp.name,insightsTimeLayout,err.Error()),
328327
},
329328
},
330329
})
331-
returnfalse
330+
returntime.Time{}, time.Time{},false
332331
}
333-
h,m,s:=v.t.Clock()
334-
ifh!=0||m!=0||s!=0 {
332+
ift.IsZero() {
333+
httpapi.Write(ctx,rw,http.StatusBadRequest, codersdk.Response{
334+
Message:"Query parameter has invalid value.",
335+
Validations: []codersdk.ValidationError{
336+
{
337+
Field:qp.name,
338+
Detail:fmt.Sprintf("Query param %q must not be zero",qp.name),
339+
},
340+
},
341+
})
342+
return time.Time{}, time.Time{},false
343+
}
344+
ensureZeroHour:=true
345+
ifqp.name=="end_time" {
346+
ey,em,ed:=t.Date()
347+
ty,tm,td:=time.Now().Date()
348+
349+
ensureZeroHour=ey!=ty||em!=tm||ed!=td
350+
}
351+
h,m,s:=t.Clock()
352+
ifensureZeroHour&& (h!=0||m!=0||s!=0) {
353+
httpapi.Write(ctx,rw,http.StatusBadRequest, codersdk.Response{
354+
Message:"Query parameter has invalid value.",
355+
Validations: []codersdk.ValidationError{
356+
{
357+
Field:qp.name,
358+
Detail:fmt.Sprintf("Query param %q must have the clock set to 00:00:00",qp.name),
359+
},
360+
},
361+
})
362+
return time.Time{}, time.Time{},false
363+
}elseifm!=0||s!=0 {
335364
httpapi.Write(ctx,rw,http.StatusBadRequest, codersdk.Response{
336365
Message:"Query parameter has invalid value.",
337366
Validations: []codersdk.ValidationError{
338367
{
339-
Field:v.name,
340-
Detail:"clockmustbe 00:00:00",
368+
Field:qp.name,
369+
Detail:fmt.Sprintf("Query param %qmusthave the clock set to %02d:00:00",qp.name,h),
341370
},
342371
},
343372
})
344-
returnfalse
373+
returntime.Time{}, time.Time{},false
345374
}
375+
*qp.dest=t
346376
}
347377
ifendTime.Before(startTime) {
348378
httpapi.Write(ctx,rw,http.StatusBadRequest, codersdk.Response{
349379
Message:"Query parameter has invalid value.",
350380
Validations: []codersdk.ValidationError{
351381
{
352382
Field:"end_time",
353-
Detail:"must beafterstart_time",
383+
Detail:fmt.Sprintf("Query param %qmust begreater than %q","end_time","start_time"),
354384
},
355385
},
356386
})
357-
returnfalse
387+
returntime.Time{}, time.Time{},false
358388
}
359389

360-
returntrue
390+
returnstartTime,endTime,true
361391
}
362392

363393
funcverifyInsightsInterval(ctx context.Context,rw http.ResponseWriter,intervalStringstring) (codersdk.InsightsReportInterval,bool) {

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp