EXPERIMENTAL: chatsByWorkspace returns a mapping of workspace ID to the latest non-archived chat ID for each requested workspace. The query returns all matching chats and RBAC post-filters them; the handler then picks the latest per workspace in Go. This avoids the DISTINCT ON + post-filter bug wher
(rw http.ResponseWriter, r *http.Request)
| 245 | // @Success 200 |
| 246 | // @x-apidocgen {"skip": true} |
| 247 | func (api *API) chatsByWorkspace(rw http.ResponseWriter, r *http.Request) { |
| 248 | ctx := r.Context() |
| 249 | |
| 250 | idsParam := r.URL.Query().Get("workspace_ids") |
| 251 | if idsParam == "" { |
| 252 | httpapi.Write(ctx, rw, http.StatusOK, map[uuid.UUID]uuid.UUID{}) |
| 253 | return |
| 254 | } |
| 255 | |
| 256 | raw := strings.Split(idsParam, ",") |
| 257 | |
| 258 | // maxWorkspaceIDs is coupled to DEFAULT_RECORDS_PER_PAGE (25) in |
| 259 | // site/src/components/PaginationWidget/utils.ts. |
| 260 | // If the page size changes, this limit should too. |
| 261 | const maxWorkspaceIDs = 25 |
| 262 | if len(raw) > maxWorkspaceIDs { |
| 263 | httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ |
| 264 | Message: fmt.Sprintf("Too many workspace IDs, maximum is %d.", maxWorkspaceIDs), |
| 265 | }) |
| 266 | return |
| 267 | } |
| 268 | |
| 269 | workspaceIDs := make([]uuid.UUID, 0, len(raw)) |
| 270 | for _, s := range raw { |
| 271 | id, err := uuid.Parse(strings.TrimSpace(s)) |
| 272 | if err != nil { |
| 273 | httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ |
| 274 | Message: fmt.Sprintf("Invalid workspace ID %q: %s", s, err), |
| 275 | }) |
| 276 | return |
| 277 | } |
| 278 | workspaceIDs = append(workspaceIDs, id) |
| 279 | } |
| 280 | |
| 281 | chats, err := api.Database.GetChatsByWorkspaceIDs(ctx, workspaceIDs) |
| 282 | if httpapi.Is404Error(err) { |
| 283 | httpapi.ResourceNotFound(rw) |
| 284 | return |
| 285 | } else if err != nil { |
| 286 | httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ |
| 287 | Message: "Failed to get chats by workspace.", |
| 288 | Detail: err.Error(), |
| 289 | }) |
| 290 | return |
| 291 | } |
| 292 | |
| 293 | // The SQL orders by (workspace_id, updated_at DESC), so the first |
| 294 | // chat seen per workspace after RBAC filtering is the latest |
| 295 | // readable one. |
| 296 | result := make(map[uuid.UUID]uuid.UUID, len(chats)) |
| 297 | for _, chat := range chats { |
| 298 | if chat.WorkspaceID.Valid { |
| 299 | if _, exists := result[chat.WorkspaceID.UUID]; !exists { |
| 300 | result[chat.WorkspaceID.UUID] = chat.ID |
| 301 | } |
| 302 | } |
| 303 | } |
| 304 |
nothing calls this directly
no test coverage detected