@Summary Get insights about user status counts @ID get-insights-about-user-status-counts @Security CoderSessionToken @Produce json @Tags Insights @Param timezone query string false "IANA timezone name (e.g. America/St_Johns)" @Param tz_offset query int false "Deprecated: Time-zone offset (e.g. -2).
(rw http.ResponseWriter, r *http.Request)
| 303 | // @Success 200 {object} codersdk.GetUserStatusCountsResponse |
| 304 | // @Router /api/v2/insights/user-status-counts [get] |
| 305 | func (api *API) insightsUserStatusCounts(rw http.ResponseWriter, r *http.Request) { |
| 306 | ctx := r.Context() |
| 307 | |
| 308 | p := httpapi.NewQueryParamParser() |
| 309 | vals := r.URL.Query() |
| 310 | timezone := p.String(vals, "", "timezone") |
| 311 | tzOffset := p.Int(vals, 0, "tz_offset") |
| 312 | _ = p.Int(vals, 0, "interval") // Deprecated: ignored, kept for backward compatibility. |
| 313 | p.ErrorExcessParams(vals) |
| 314 | |
| 315 | if len(p.Errors) > 0 { |
| 316 | httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ |
| 317 | Message: "Query parameters have invalid values.", |
| 318 | Validations: p.Errors, |
| 319 | }) |
| 320 | return |
| 321 | } |
| 322 | |
| 323 | if timezone != "" && tzOffset != 0 { |
| 324 | httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ |
| 325 | Message: "Provide either \"timezone\" or \"tz_offset\", not both.", |
| 326 | }) |
| 327 | return |
| 328 | } |
| 329 | |
| 330 | var loc *time.Location |
| 331 | if timezone == "" { |
| 332 | timezone = "UTC" |
| 333 | if tzOffset > 0 { |
| 334 | timezone = fmt.Sprintf("Etc/GMT-%d", tzOffset) |
| 335 | } else if tzOffset < 0 { |
| 336 | timezone = fmt.Sprintf("Etc/GMT+%d", -tzOffset) |
| 337 | } |
| 338 | } |
| 339 | |
| 340 | loc, err := time.LoadLocation(timezone) |
| 341 | if err != nil { |
| 342 | httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ |
| 343 | Message: "Invalid timezone.", |
| 344 | Detail: err.Error(), |
| 345 | }) |
| 346 | return |
| 347 | } |
| 348 | |
| 349 | nextHourInLoc := dbtime.Now().Truncate(time.Hour).Add(time.Hour).In(loc) |
| 350 | sixtyDaysAgo := dbtime.StartOfDay(nextHourInLoc).AddDate(0, 0, -60) |
| 351 | |
| 352 | queryParams := database.GetUserStatusCountsParams{ |
| 353 | StartTime: sixtyDaysAgo, |
| 354 | EndTime: nextHourInLoc, |
| 355 | // loc.String() returns an IANA timezone name (e.g. "America/New_York"). |
| 356 | // Both Go and PostgreSQL use the IANA Time Zone Database, so names are |
| 357 | // compatible. The Etc/GMT±N names used for offset fallback are also valid |
| 358 | // in both systems. |
| 359 | Tz: loc.String(), |
| 360 | } |
| 361 | rows, err := api.Database.GetUserStatusCounts(ctx, queryParams) |
| 362 | if err != nil { |
nothing calls this directly
no test coverage detected