Constellation, Spacedust, Slingshot, UFOs: atproto crates and services for microcosm

document did filtering

and add to try-it

also not the limit param!!!

Changed files
+44 -12
constellation
+14 -3
constellation/src/server/mod.rs
··· 251 251 /// 252 252 /// deprecated: use `did`, which can be repeated multiple times 253 253 from_dids: Option<String>, // comma separated: gross 254 - limit: Option<u64>, 254 + #[serde(default = "get_default_limit")] 255 + limit: u64, 255 256 // TODO: allow reverse (er, forward) order as well 257 + } 258 + fn get_default_limit() -> u64 { 259 + DEFAULT_CURSOR_LIMIT 256 260 } 257 261 #[derive(Template, Serialize)] 258 262 #[template(path = "links.html.j2")] ··· 278 282 .transpose()? 279 283 .map(|c| c.next); 280 284 281 - let limit = query.limit.unwrap_or(DEFAULT_CURSOR_LIMIT); 285 + let limit = query.limit; 282 286 if limit > DEFAULT_CURSOR_LIMIT_MAX { 283 287 return Err(http::StatusCode::BAD_REQUEST); 284 288 } 285 289 286 - let mut filter_dids: HashSet<Did> = HashSet::from_iter(query.did.iter().map(|d| Did(d.to_string()))); 290 + let mut filter_dids: HashSet<Did> = HashSet::from_iter( 291 + query 292 + .did 293 + .iter() 294 + .map(|d| d.trim()) 295 + .filter(|d| !d.is_empty()) 296 + .map(|d| Did(d.to_string())), 297 + ); 287 298 288 299 if let Some(comma_joined) = &query.from_dids { 289 300 if !filter_dids.is_empty() {
+9 -6
constellation/templates/hello.html.j2
··· 20 20 21 21 <p> 22 22 This server has indexed <span class="stat">{{ stats.linking_records|human_number }}</span> links between <span class="stat">{{ stats.targetables|human_number }}</span> targets and sources from <span class="stat">{{ stats.dids|human_number }}</span> identities over <span class="stat">{{ days_indexed|human_number }}</span> days.<br/> 23 - <small>(indexing new records in real time, backfill still TODO)</small> 23 + <small>(indexing new records in real time, backfill coming soon!)</small> 24 24 </p> 25 25 26 - <p>The API is currently <strong>unstable</strong>. But feel free to use it! If you want to be nice, put your project name and bsky username (or email) in your user-agent header for api requests.</p> 26 + <p>But feel free to use it! If you want to be nice, put your project name and bsky username (or email) in your user-agent header for api requests.</p> 27 27 28 28 29 29 <h2>API Endpoints</h2> ··· 35 35 <h4>Query parameters:</h4> 36 36 37 37 <ul> 38 - <li><code>target</code>: required, must url-encode. Example: <code>at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lgwdn7vd722r</code></li> 39 - <li><code>collection</code>: required. Example: <code>app.bsky.feed.like</code></li> 40 - <li><code>path</code>: required, must url-encode. Example: <code>.subject.uri</code></li> 38 + <li><p><code>target</code>: required, must url-encode. Example: <code>at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lgwdn7vd722r</code></p></li> 39 + <li><p><code>collection</code>: required. Example: <code>app.bsky.feed.like</code></p></li> 40 + <li><p><code>path</code>: required, must url-encode. Example: <code>.subject.uri</code></p></li> 41 + <li><p><code>did</code>: optional, filter links to those from specific users. Include multiple times to filter by multiple users. Example: <code>did=did:plc:vc7f4oafdgxsihk4cry2xpze&did=did:plc:vc7f4oafdgxsihk4cry2xpze</code></p></li> 42 + <li><p><code>from_dids</code> [deprecated]: optional. Use <code>did</code> instead. Example: <code>from_dids=did:plc:vc7f4oafdgxsihk4cry2xpze,did:plc:vc7f4oafdgxsihk4cry2xpze</code></p></li> 43 + <li><p><code>limit</code>: optional. Default: <code>16</code>. Maximum: <code>100</code></p></li> 41 44 </ul> 42 45 43 46 <p style="margin-bottom: 0"><strong>Try it:</strong></p> 44 - {% call try_it::links("at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lgwdn7vd722r", "app.bsky.feed.like", ".subject.uri") %} 47 + {% call try_it::links("at://did:plc:a4pqq234yw7fqbddawjo7y35/app.bsky.feed.post/3m237ilwc372e", "app.bsky.feed.like", ".subject.uri", [""], 16) %} 45 48 46 49 47 50 <h3 class="route"><code>GET /links/distinct-dids</code></h3>
+1 -1
constellation/templates/links.html.j2
··· 6 6 7 7 {% block content %} 8 8 9 - {% call try_it::links(query.target, query.collection, query.path) %} 9 + {% call try_it::links(query.target, query.collection, query.path, query.did, query.limit) %} 10 10 11 11 <h2> 12 12 Links to <code>{{ query.target }}</code>
+20 -2
constellation/templates/try-it-macros.html.j2
··· 1 - {% macro links(target, collection, path) %} 1 + {% macro links(target, collection, path, dids, limit) %} 2 2 <form method="get" action="/links"> 3 3 <pre class="code"><strong>GET</strong> /links 4 4 ?target= <input type="text" name="target" value="{{ target }}" placeholder="target" /> 5 5 &collection= <input type="text" name="collection" value="{{ collection }}" placeholder="collection" /> 6 - &path= <input type="text" name="path" value="{{ path }}" placeholder="path" /> <button type="submit">get links</button></pre> 6 + &path= <input type="text" name="path" value="{{ path }}" placeholder="path" /> 7 + {%- for did in dids %}{% if !did.is_empty() %} 8 + &did= <input type="text" name="did" value="{{ did }}" placeholder="did:plc:..." />{% endif %}{% endfor %} 9 + <span id="did-placeholder"></span> <button id="add-did">+ did filter</button> 10 + &limit= <input type="number" name="limit" value="{{ limit }}" max="100" placeholder="100" /> <button type="submit">get links</button></pre> 7 11 </form> 12 + <script> 13 + const addDidButton = document.getElementById('add-did'); 14 + const didPlaceholder = document.getElementById('did-placeholder'); 15 + addDidButton.addEventListener('click', e => { 16 + e.preventDefault(); 17 + const i = document.createElement('input'); 18 + i.placeholder = 'did:plc:...'; 19 + i.name = "did" 20 + const p = addDidButton.parentNode; 21 + p.insertBefore(document.createTextNode('&did= '), didPlaceholder); 22 + p.insertBefore(i, didPlaceholder); 23 + p.insertBefore(document.createTextNode('\n '), didPlaceholder); 24 + }); 25 + </script> 8 26 {% endmacro %} 9 27 10 28