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
···
///
/// deprecated: use `did`, which can be repeated multiple times
from_dids: Option<String>, // comma separated: gross
-
limit: Option<u64>,
+
#[serde(default = "get_default_limit")]
+
limit: u64,
// TODO: allow reverse (er, forward) order as well
+
}
+
fn get_default_limit() -> u64 {
+
DEFAULT_CURSOR_LIMIT
}
#[derive(Template, Serialize)]
#[template(path = "links.html.j2")]
···
.transpose()?
.map(|c| c.next);
-
let limit = query.limit.unwrap_or(DEFAULT_CURSOR_LIMIT);
+
let limit = query.limit;
if limit > DEFAULT_CURSOR_LIMIT_MAX {
return Err(http::StatusCode::BAD_REQUEST);
}
-
let mut filter_dids: HashSet<Did> = HashSet::from_iter(query.did.iter().map(|d| Did(d.to_string())));
+
let mut filter_dids: HashSet<Did> = HashSet::from_iter(
+
query
+
.did
+
.iter()
+
.map(|d| d.trim())
+
.filter(|d| !d.is_empty())
+
.map(|d| Did(d.to_string())),
+
);
if let Some(comma_joined) = &query.from_dids {
if !filter_dids.is_empty() {
+9 -6
constellation/templates/hello.html.j2
···
<p>
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/>
-
<small>(indexing new records in real time, backfill still TODO)</small>
+
<small>(indexing new records in real time, backfill coming soon!)</small>
</p>
-
<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>
+
<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>
<h2>API Endpoints</h2>
···
<h4>Query parameters:</h4>
<ul>
-
<li><code>target</code>: required, must url-encode. Example: <code>at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lgwdn7vd722r</code></li>
-
<li><code>collection</code>: required. Example: <code>app.bsky.feed.like</code></li>
-
<li><code>path</code>: required, must url-encode. Example: <code>.subject.uri</code></li>
+
<li><p><code>target</code>: required, must url-encode. Example: <code>at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lgwdn7vd722r</code></p></li>
+
<li><p><code>collection</code>: required. Example: <code>app.bsky.feed.like</code></p></li>
+
<li><p><code>path</code>: required, must url-encode. Example: <code>.subject.uri</code></p></li>
+
<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>
+
<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>
+
<li><p><code>limit</code>: optional. Default: <code>16</code>. Maximum: <code>100</code></p></li>
</ul>
<p style="margin-bottom: 0"><strong>Try it:</strong></p>
-
{% call try_it::links("at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lgwdn7vd722r", "app.bsky.feed.like", ".subject.uri") %}
+
{% call try_it::links("at://did:plc:a4pqq234yw7fqbddawjo7y35/app.bsky.feed.post/3m237ilwc372e", "app.bsky.feed.like", ".subject.uri", [""], 16) %}
<h3 class="route"><code>GET /links/distinct-dids</code></h3>
+1 -1
constellation/templates/links.html.j2
···
{% block content %}
-
{% call try_it::links(query.target, query.collection, query.path) %}
+
{% call try_it::links(query.target, query.collection, query.path, query.did, query.limit) %}
<h2>
Links to <code>{{ query.target }}</code>
+20 -2
constellation/templates/try-it-macros.html.j2
···
-
{% macro links(target, collection, path) %}
+
{% macro links(target, collection, path, dids, limit) %}
<form method="get" action="/links">
<pre class="code"><strong>GET</strong> /links
?target= <input type="text" name="target" value="{{ target }}" placeholder="target" />
&collection= <input type="text" name="collection" value="{{ collection }}" placeholder="collection" />
-
&path= <input type="text" name="path" value="{{ path }}" placeholder="path" /> <button type="submit">get links</button></pre>
+
&path= <input type="text" name="path" value="{{ path }}" placeholder="path" />
+
{%- for did in dids %}{% if !did.is_empty() %}
+
&did= <input type="text" name="did" value="{{ did }}" placeholder="did:plc:..." />{% endif %}{% endfor %}
+
<span id="did-placeholder"></span> <button id="add-did">+ did filter</button>
+
&limit= <input type="number" name="limit" value="{{ limit }}" max="100" placeholder="100" /> <button type="submit">get links</button></pre>
</form>
+
<script>
+
const addDidButton = document.getElementById('add-did');
+
const didPlaceholder = document.getElementById('did-placeholder');
+
addDidButton.addEventListener('click', e => {
+
e.preventDefault();
+
const i = document.createElement('input');
+
i.placeholder = 'did:plc:...';
+
i.name = "did"
+
const p = addDidButton.parentNode;
+
p.insertBefore(document.createTextNode('&did= '), didPlaceholder);
+
p.insertBefore(i, didPlaceholder);
+
p.insertBefore(document.createTextNode('\n '), didPlaceholder);
+
});
+
</script>
{% endmacro %}