(READ ONLY) Margin is an open annotation layer for the internet. Powered by the AT Protocol. margin.at
extension web atproto comments
98
fork

Configure Feed

Select the types of activity you want to include in your feed.

add highlight quick API handler

scanash00 fb80a55b 2c84b534

+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