Write on the margins of the internet. Powered by the AT Protocol. margin.at
extension web atproto comments

add highlight quick API handler

+79
+78
backend/internal/api/apikey.go
··· 267 267 }) 268 268 } 269 269 270 + type QuickHighlightRequest struct { 271 + URL string `json:"url"` 272 + Selector interface{} `json:"selector"` 273 + Color string `json:"color,omitempty"` 274 + } 275 + 276 + func (h *APIKeyHandler) QuickHighlight(w http.ResponseWriter, r *http.Request) { 277 + apiKey, err := h.authenticateAPIKey(r) 278 + if err != nil { 279 + http.Error(w, err.Error(), http.StatusUnauthorized) 280 + return 281 + } 282 + 283 + var req QuickHighlightRequest 284 + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { 285 + http.Error(w, "Invalid request body", http.StatusBadRequest) 286 + return 287 + } 288 + 289 + if req.URL == "" || req.Selector == nil { 290 + http.Error(w, "URL and selector are required", http.StatusBadRequest) 291 + return 292 + } 293 + 294 + session, err := h.getSessionByDID(apiKey.OwnerDID) 295 + if err != nil { 296 + http.Error(w, "User session not found. Please log in to margin.at first.", http.StatusUnauthorized) 297 + return 298 + } 299 + 300 + urlHash := db.HashURL(req.URL) 301 + color := req.Color 302 + if color == "" { 303 + color = "yellow" 304 + } 305 + 306 + record := xrpc.NewHighlightRecord(req.URL, urlHash, req.Selector, color, nil) 307 + 308 + var result *xrpc.CreateRecordOutput 309 + err = h.refresher.ExecuteWithAutoRefresh(r, session, func(client *xrpc.Client, did string) error { 310 + var createErr error 311 + result, createErr = client.CreateRecord(r.Context(), did, xrpc.CollectionHighlight, record) 312 + return createErr 313 + }) 314 + if err != nil { 315 + http.Error(w, "Failed to create highlight: "+err.Error(), http.StatusInternalServerError) 316 + return 317 + } 318 + 319 + h.db.UpdateAPIKeyLastUsed(apiKey.ID) 320 + 321 + selectorJSON, _ := json.Marshal(req.Selector) 322 + selectorStr := string(selectorJSON) 323 + colorPtr := &color 324 + 325 + highlight := &db.Highlight{ 326 + URI: result.URI, 327 + AuthorDID: apiKey.OwnerDID, 328 + TargetSource: req.URL, 329 + TargetHash: urlHash, 330 + SelectorJSON: &selectorStr, 331 + Color: colorPtr, 332 + CreatedAt: time.Now(), 333 + IndexedAt: time.Now(), 334 + CID: &result.CID, 335 + } 336 + if err := h.db.CreateHighlight(highlight); err != nil { 337 + fmt.Printf("Warning: failed to index highlight in local DB: %v\n", err) 338 + } 339 + 340 + w.Header().Set("Content-Type", "application/json") 341 + json.NewEncoder(w).Encode(map[string]string{ 342 + "uri": result.URI, 343 + "cid": result.CID, 344 + "message": "Highlight created successfully", 345 + }) 346 + } 347 + 270 348 func (h *APIKeyHandler) authenticateAPIKey(r *http.Request) (*db.APIKey, error) { 271 349 auth := r.Header.Get("Authorization") 272 350 if auth == "" {
+1
backend/internal/api/handler.go
··· 78 78 79 79 r.Post("/quick/bookmark", h.apiKeys.QuickBookmark) 80 80 r.Post("/quick/annotation", h.apiKeys.QuickAnnotation) 81 + r.Post("/quick/highlight", h.apiKeys.QuickHighlight) 81 82 }) 82 83 } 83 84