Margin is an open annotation layer for the internet. Powered by the AT Protocol. margin.at
extension web atproto comments

fixes

+45 -26
+1 -1
.env.example
··· 11 11 STATIC_DIR=../web/dist 12 12 13 13 # OAuth private key for signing requests (auto-generated if missing) 14 - OAUTH_KEY_PATH=./oauth_private_key.pem 14 + OAUTH_KEY_PATH=/data/oauth_private_key.pem 15 15 16 16 17 17 # Optional: Override default ATProto network URLs (you probably don't need these)
+24
backend/internal/api/annotations.go
··· 64 64 return 65 65 } 66 66 67 + for i, t := range req.Tags { 68 + req.Tags[i] = strings.ToLower(t) 69 + } 70 + 67 71 urlHash := db.HashURL(req.URL) 68 72 69 73 motivation := "commenting" ··· 329 333 return 330 334 } 331 335 rkey := parts[2] 336 + 337 + for i, t := range req.Tags { 338 + req.Tags[i] = strings.ToLower(t) 339 + } 332 340 333 341 tagsJSON := "" 334 342 if len(req.Tags) > 0 { ··· 692 700 if req.URL == "" || req.Selector == nil { 693 701 http.Error(w, "URL and selector are required", http.StatusBadRequest) 694 702 return 703 + } 704 + 705 + for i, t := range req.Tags { 706 + req.Tags[i] = strings.ToLower(t) 695 707 } 696 708 697 709 urlHash := db.HashURL(req.URL) ··· 806 818 return 807 819 } 808 820 821 + for i, t := range req.Tags { 822 + req.Tags[i] = strings.ToLower(t) 823 + } 824 + 809 825 urlHash := db.HashURL(req.URL) 810 826 record := xrpc.NewBookmarkRecord(req.URL, urlHash, req.Title, req.Description) 811 827 if len(req.Tags) > 0 { ··· 960 976 } 961 977 rkey := parts[2] 962 978 979 + for i, t := range req.Tags { 980 + req.Tags[i] = strings.ToLower(t) 981 + } 982 + 963 983 var result *xrpc.PutRecordOutput 964 984 err = s.refresher.ExecuteWithAutoRefresh(r, session, func(client *xrpc.Client, did string) error { 965 985 existing, getErr := client.GetRecord(r.Context(), did, xrpc.CollectionHighlight, rkey) ··· 1066 1086 rkey := parts[2] 1067 1087 1068 1088 var result *xrpc.PutRecordOutput 1089 + for i, t := range req.Tags { 1090 + req.Tags[i] = strings.ToLower(t) 1091 + } 1092 + 1069 1093 err = s.refresher.ExecuteWithAutoRefresh(r, session, func(client *xrpc.Client, did string) error { 1070 1094 existing, getErr := client.GetRecord(r.Context(), did, xrpc.CollectionBookmark, rkey) 1071 1095 if getErr != nil {
+1 -1
backend/internal/api/handler.go
··· 232 232 func (h *Handler) GetFeed(w http.ResponseWriter, r *http.Request) { 233 233 limit := parseIntParam(r, "limit", 50) 234 234 offset := parseIntParam(r, "offset", 0) 235 - tag := r.URL.Query().Get("tag") 235 + tag := strings.ToLower(r.URL.Query().Get("tag")) 236 236 creator := r.URL.Query().Get("creator") 237 237 feedType := r.URL.Query().Get("type") 238 238
+6 -6
backend/internal/db/queries_annotations.go
··· 217 217 rows, err := db.Query(` 218 218 SELECT uri, author_did, motivation, body_value, body_format, body_uri, target_source, target_hash, target_title, selector_json, tags_json, created_at, indexed_at, cid 219 219 FROM annotations 220 - WHERE tags_json::jsonb ? $1 220 + WHERE EXISTS(SELECT 1 FROM jsonb_array_elements_text(tags_json::jsonb) elem WHERE lower(elem) = $1) 221 221 ORDER BY created_at DESC 222 222 LIMIT $2 OFFSET $3 223 223 `, tag, limit, offset) ··· 233 233 rows, err := db.Query(` 234 234 SELECT uri, author_did, motivation, body_value, body_format, body_uri, target_source, target_hash, target_title, selector_json, tags_json, created_at, indexed_at, cid 235 235 FROM annotations 236 - WHERE tags_json::jsonb ? $1 AND uri NOT LIKE '%network.cosmik%' 236 + WHERE EXISTS(SELECT 1 FROM jsonb_array_elements_text(tags_json::jsonb) elem WHERE lower(elem) = $1) AND uri NOT LIKE '%network.cosmik%' 237 237 ORDER BY created_at DESC 238 238 LIMIT $2 OFFSET $3 239 239 `, tag, limit, offset) ··· 249 249 rows, err := db.Query(` 250 250 SELECT uri, author_did, motivation, body_value, body_format, body_uri, target_source, target_hash, target_title, selector_json, tags_json, created_at, indexed_at, cid 251 251 FROM annotations 252 - WHERE tags_json::jsonb ? $1 AND uri LIKE '%network.cosmik%' 252 + WHERE EXISTS(SELECT 1 FROM jsonb_array_elements_text(tags_json::jsonb) elem WHERE lower(elem) = $1) AND uri LIKE '%network.cosmik%' 253 253 ORDER BY created_at DESC 254 254 LIMIT $2 OFFSET $3 255 255 `, tag, limit, offset) ··· 279 279 rows, err := db.Query(` 280 280 SELECT uri, author_did, motivation, body_value, body_format, body_uri, target_source, target_hash, target_title, selector_json, tags_json, created_at, indexed_at, cid 281 281 FROM annotations 282 - WHERE author_did = $1 AND tags_json::jsonb ? $2 282 + WHERE author_did = $1 AND EXISTS(SELECT 1 FROM jsonb_array_elements_text(tags_json::jsonb) elem WHERE lower(elem) = $2) 283 283 ORDER BY created_at DESC 284 284 LIMIT $3 OFFSET $4 285 285 `, authorDID, tag, limit, offset) ··· 295 295 rows, err := db.Query(` 296 296 SELECT uri, author_did, motivation, body_value, body_format, body_uri, target_source, target_hash, target_title, selector_json, tags_json, created_at, indexed_at, cid 297 297 FROM annotations 298 - WHERE author_did = $1 AND tags_json::jsonb ? $2 AND uri NOT LIKE '%network.cosmik%' 298 + WHERE author_did = $1 AND EXISTS(SELECT 1 FROM jsonb_array_elements_text(tags_json::jsonb) elem WHERE lower(elem) = $2) AND uri NOT LIKE '%network.cosmik%' 299 299 ORDER BY created_at DESC 300 300 LIMIT $3 OFFSET $4 301 301 `, authorDID, tag, limit, offset) ··· 311 311 rows, err := db.Query(` 312 312 SELECT uri, author_did, motivation, body_value, body_format, body_uri, target_source, target_hash, target_title, selector_json, tags_json, created_at, indexed_at, cid 313 313 FROM annotations 314 - WHERE author_did = $1 AND tags_json::jsonb ? $2 AND uri LIKE '%network.cosmik%' 314 + WHERE author_did = $1 AND EXISTS(SELECT 1 FROM jsonb_array_elements_text(tags_json::jsonb) elem WHERE lower(elem) = $2) AND uri LIKE '%network.cosmik%' 315 315 ORDER BY created_at DESC 316 316 LIMIT $3 OFFSET $4 317 317 `, authorDID, tag, limit, offset)
+6 -6
backend/internal/db/queries_bookmarks.go
··· 131 131 rows, err := db.Query(` 132 132 SELECT uri, author_did, source, source_hash, title, description, tags_json, created_at, indexed_at, cid 133 133 FROM bookmarks 134 - WHERE tags_json::jsonb ? $1 134 + WHERE EXISTS(SELECT 1 FROM jsonb_array_elements_text(tags_json::jsonb) elem WHERE lower(elem) = $1) 135 135 ORDER BY created_at DESC 136 136 LIMIT $2 OFFSET $3 137 137 `, tag, limit, offset) ··· 147 147 rows, err := db.Query(` 148 148 SELECT uri, author_did, source, source_hash, title, description, tags_json, created_at, indexed_at, cid 149 149 FROM bookmarks 150 - WHERE tags_json::jsonb ? $1 AND uri NOT LIKE '%network.cosmik%' 150 + WHERE EXISTS(SELECT 1 FROM jsonb_array_elements_text(tags_json::jsonb) elem WHERE lower(elem) = $1) AND uri NOT LIKE '%network.cosmik%' 151 151 ORDER BY created_at DESC 152 152 LIMIT $2 OFFSET $3 153 153 `, tag, limit, offset) ··· 163 163 rows, err := db.Query(` 164 164 SELECT uri, author_did, source, source_hash, title, description, tags_json, created_at, indexed_at, cid 165 165 FROM bookmarks 166 - WHERE tags_json::jsonb ? $1 AND uri LIKE '%network.cosmik%' 166 + WHERE EXISTS(SELECT 1 FROM jsonb_array_elements_text(tags_json::jsonb) elem WHERE lower(elem) = $1) AND uri LIKE '%network.cosmik%' 167 167 ORDER BY created_at DESC 168 168 LIMIT $2 OFFSET $3 169 169 `, tag, limit, offset) ··· 179 179 rows, err := db.Query(` 180 180 SELECT uri, author_did, source, source_hash, title, description, tags_json, created_at, indexed_at, cid 181 181 FROM bookmarks 182 - WHERE author_did = $1 AND tags_json::jsonb ? $2 182 + WHERE author_did = $1 AND EXISTS(SELECT 1 FROM jsonb_array_elements_text(tags_json::jsonb) elem WHERE lower(elem) = $2) 183 183 ORDER BY created_at DESC 184 184 LIMIT $3 OFFSET $4 185 185 `, authorDID, tag, limit, offset) ··· 195 195 rows, err := db.Query(` 196 196 SELECT uri, author_did, source, source_hash, title, description, tags_json, created_at, indexed_at, cid 197 197 FROM bookmarks 198 - WHERE author_did = $1 AND tags_json::jsonb ? $2 AND uri NOT LIKE '%network.cosmik%' 198 + WHERE author_did = $1 AND EXISTS(SELECT 1 FROM jsonb_array_elements_text(tags_json::jsonb) elem WHERE lower(elem) = $2) AND uri NOT LIKE '%network.cosmik%' 199 199 ORDER BY created_at DESC 200 200 LIMIT $3 OFFSET $4 201 201 `, authorDID, tag, limit, offset) ··· 211 211 rows, err := db.Query(` 212 212 SELECT uri, author_did, source, source_hash, title, description, tags_json, created_at, indexed_at, cid 213 213 FROM bookmarks 214 - WHERE author_did = $1 AND tags_json::jsonb ? $2 AND uri LIKE '%network.cosmik%' 214 + WHERE author_did = $1 AND EXISTS(SELECT 1 FROM jsonb_array_elements_text(tags_json::jsonb) elem WHERE lower(elem) = $2) AND uri LIKE '%network.cosmik%' 215 215 ORDER BY created_at DESC 216 216 LIMIT $3 OFFSET $4 217 217 `, authorDID, tag, limit, offset)
+6 -6
backend/internal/db/queries_highlights.go
··· 132 132 rows, err := db.Query(` 133 133 SELECT uri, author_did, target_source, target_hash, target_title, selector_json, color, tags_json, created_at, indexed_at, cid 134 134 FROM highlights 135 - WHERE tags_json::jsonb ? $1 135 + WHERE EXISTS(SELECT 1 FROM jsonb_array_elements_text(tags_json::jsonb) elem WHERE lower(elem) = $1) 136 136 ORDER BY created_at DESC 137 137 LIMIT $2 OFFSET $3 138 138 `, tag, limit, offset) ··· 148 148 rows, err := db.Query(` 149 149 SELECT uri, author_did, target_source, target_hash, target_title, selector_json, color, tags_json, created_at, indexed_at, cid 150 150 FROM highlights 151 - WHERE tags_json::jsonb ? $1 AND uri NOT LIKE '%network.cosmik%' 151 + WHERE EXISTS(SELECT 1 FROM jsonb_array_elements_text(tags_json::jsonb) elem WHERE lower(elem) = $1) AND uri NOT LIKE '%network.cosmik%' 152 152 ORDER BY created_at DESC 153 153 LIMIT $2 OFFSET $3 154 154 `, tag, limit, offset) ··· 164 164 rows, err := db.Query(` 165 165 SELECT uri, author_did, target_source, target_hash, target_title, selector_json, color, tags_json, created_at, indexed_at, cid 166 166 FROM highlights 167 - WHERE tags_json::jsonb ? $1 AND uri LIKE '%network.cosmik%' 167 + WHERE EXISTS(SELECT 1 FROM jsonb_array_elements_text(tags_json::jsonb) elem WHERE lower(elem) = $1) AND uri LIKE '%network.cosmik%' 168 168 ORDER BY created_at DESC 169 169 LIMIT $2 OFFSET $3 170 170 `, tag, limit, offset) ··· 180 180 rows, err := db.Query(` 181 181 SELECT uri, author_did, target_source, target_hash, target_title, selector_json, color, tags_json, created_at, indexed_at, cid 182 182 FROM highlights 183 - WHERE author_did = $1 AND tags_json::jsonb ? $2 183 + WHERE author_did = $1 AND EXISTS(SELECT 1 FROM jsonb_array_elements_text(tags_json::jsonb) elem WHERE lower(elem) = $2) 184 184 ORDER BY created_at DESC 185 185 LIMIT $3 OFFSET $4 186 186 `, authorDID, tag, limit, offset) ··· 196 196 rows, err := db.Query(` 197 197 SELECT uri, author_did, target_source, target_hash, target_title, selector_json, color, tags_json, created_at, indexed_at, cid 198 198 FROM highlights 199 - WHERE author_did = $1 AND tags_json::jsonb ? $2 AND uri NOT LIKE '%network.cosmik%' 199 + WHERE author_did = $1 AND EXISTS(SELECT 1 FROM jsonb_array_elements_text(tags_json::jsonb) elem WHERE lower(elem) = $2) AND uri NOT LIKE '%network.cosmik%' 200 200 ORDER BY created_at DESC 201 201 LIMIT $3 OFFSET $4 202 202 `, authorDID, tag, limit, offset) ··· 212 212 rows, err := db.Query(` 213 213 SELECT uri, author_did, target_source, target_hash, target_title, selector_json, color, tags_json, created_at, indexed_at, cid 214 214 FROM highlights 215 - WHERE author_did = $1 AND tags_json::jsonb ? $2 AND uri LIKE '%network.cosmik%' 215 + WHERE author_did = $1 AND EXISTS(SELECT 1 FROM jsonb_array_elements_text(tags_json::jsonb) elem WHERE lower(elem) = $2) AND uri LIKE '%network.cosmik%' 216 216 ORDER BY created_at DESC 217 217 LIMIT $3 OFFSET $4 218 218 `, authorDID, tag, limit, offset)
+1 -6
web/src/views/core/Feed.tsx
··· 162 162 motivation={activeFilter} 163 163 emptyMessage={emptyMessage} 164 164 layout={layout} 165 - tag={ 166 - activeTab === "atmosphereconf" || 167 - tag?.toLowerCase() === "atmosphereconf" 168 - ? "ATmosphereConf" 169 - : tag 170 - } 165 + tag={activeTab === "atmosphereconf" ? "atmosphereconf" : tag?.toLowerCase()} 171 166 /> 172 167 </div> 173 168 );