• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

knowledgepixels / nanopub-registry / 20413250445

21 Dec 2025 05:19PM UTC coverage: 0.924% (-0.03%) from 0.954%
20413250445

push

github

ashleycaselli
chore: minor code cleanup

6 of 592 branches covered (1.01%)

Branch coverage included in aggregate %.

16 of 1789 relevant lines covered (0.89%)

0.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
src/main/java/com/knowledgepixels/registry/ListPage.java
1
package com.knowledgepixels.registry;
2

3
import com.google.gson.Gson;
4
import com.mongodb.client.ClientSession;
5
import com.mongodb.client.MongoCursor;
6
import io.vertx.ext.web.RoutingContext;
7
import org.bson.Document;
8
import org.bson.conversions.Bson;
9
import org.nanopub.jelly.NanopubStream;
10

11
import java.io.IOException;
12
import java.net.URLEncoder;
13
import java.util.List;
14

15
import static com.knowledgepixels.registry.RegistryDB.collection;
16
import static com.knowledgepixels.registry.RegistryDB.unhash;
17
import static com.knowledgepixels.registry.Utils.*;
18
import static com.mongodb.client.model.Aggregates.*;
19
import static com.mongodb.client.model.Filters.gt;
20
import static com.mongodb.client.model.Indexes.ascending;
21
import static com.mongodb.client.model.Indexes.descending;
22
import static com.mongodb.client.model.Projections.exclude;
23
import static com.mongodb.client.model.Projections.include;
24

25
public class ListPage extends Page {
26

27
    private static final Gson gson = new Gson();
×
28

29
    public static void show(RoutingContext context) {
30
        ListPage page;
31
        try (ClientSession s = RegistryDB.getClient().startSession()) {
×
32
            s.startTransaction();
×
33
            page = new ListPage(s, context);
×
34
            page.show();
×
35
        } catch (IOException ex) {
×
36
            ex.printStackTrace();
×
37
        } finally {
38
            context.response().end();
×
39
            // TODO Clean-up here?
40
        }
41
    }
×
42

43
    private ListPage(ClientSession mongoSession, RoutingContext context) {
44
        super(mongoSession, context);
×
45
    }
×
46

47
    protected void show() throws IOException {
48
        RoutingContext context = getContext();
×
49
        String format;
50
        String ext = getExtension();
×
51
        final String req = getRequestString();
×
52
        if ("json".equals(ext)) {
×
53
            format = TYPE_JSON;
×
54
        } else if ("jelly".equals(ext)) {
×
55
            format = TYPE_JELLY;
×
56
        } else if (ext == null || "html".equals(ext)) {
×
57
            format = Utils.getMimeType(context, SUPPORTED_TYPES_LIST);
×
58
        } else {
59
            context.response().setStatusCode(400).setStatusMessage("Invalid request: " + getFullRequest());
×
60
            return;
×
61
        }
62

63
        if (getPresentationFormat() != null) {
×
64
            setRespContentType(getPresentationFormat());
×
65
        } else {
66
            setRespContentType(format);
×
67
        }
68

69
        if (req.matches("/list/[0-9a-f]{64}/([0-9a-f]{64}|\\$)")) {
×
70
            String pubkey = req.replaceFirst("/list/([0-9a-f]{64})/([0-9a-f]{64}|\\$)", "$1");
×
71
            String type = req.replaceFirst("/list/([0-9a-f]{64})/([0-9a-f]{64}|\\$)", "$2");
×
72

73
            if (TYPE_JELLY.equals(format)) {
×
74
                // Return all nanopubs in the list as a single Jelly stream
75
                List<Bson> pipeline = List.of(match(new Document("pubkey", pubkey).append("type", type)), sort(ascending("position")), // TODO: is this needed?
×
76
                        lookup("nanopubs", "np", "_id", "nanopub"), project(new Document("jelly", "$nanopub.jelly")), unwind("$jelly"));
×
77
                // TODO: try with resource should be used for all DB access, really, like here
78
                try (var result = collection("listEntries").aggregate(mongoSession, pipeline).cursor()) {
×
79
                    NanopubStream npStream = NanopubStream.fromMongoCursor(result);
×
80
                    BufferOutputStream outputStream = new BufferOutputStream();
×
81
                    npStream.writeToByteStream(outputStream);
×
82
                    context.response().write(outputStream.getBuffer());
×
83
                }
84
            } else {
×
85
                MongoCursor<Document> c = collection("listEntries").find(mongoSession, new Document("pubkey", pubkey).append("type", type)).projection(exclude("_id")).sort(ascending("position")).cursor();
×
86

87
                if (TYPE_JSON.equals(format)) {
×
88
                    println("[");
×
89
                    while (c.hasNext()) {
×
90
                        Document d = c.next();
×
91
                        // Transforming long to int, so the JSON output looks nice:
92
                        // TODO Make this scale beyond the int range
93
                        d.replace("position", d.getLong("position").intValue());
×
94
                        print(d.toJson());
×
95
                        println(c.hasNext() ? "," : "");
×
96
                    }
×
97
                    println("]");
×
98
                } else {
99
                    printHtmlHeader("List for pubkey " + getLabel(pubkey) + " / type " + getLabel(type) + " - Nanopub Registry");
×
100
                    println("<h1>List</h1>");
×
101
                    println("<p><a href=\"/list/" + pubkey + "\">&lt; Pubkey</a></p>");
×
102
                    println("<h3>Formats</h3>");
×
103
                    println("<p>");
×
104
                    println("<a href=\"/list/" + pubkey + "/" + type + ".json\">.json</a> |");
×
105
                    println("<a href=\"/list/" + pubkey + "/" + type + ".json.txt\">.json.txt</a>");
×
106
                    println("</p>");
×
107
                    println("<h3>Pubkey Hash</h3>");
×
108
                    println("<p><code>" + pubkey + "</code></p>");
×
109
                    println("<h3>Type Hash</h3>");
×
110
                    println("<p><code>" + type + "</code></p>");
×
111
                    println("<h3>Entries</h3>");
×
112
                    println("<ol>");
×
113
                    while (c.hasNext()) {
×
114
                        Document d = c.next();
×
115
                        println("<li><a href=\"/np/" + d.getString("np") + "\"><code>" + getLabel(d.getString("np")) + "</code></a></li>");
×
116
                    }
×
117
                    println("</ol>");
×
118
                    printHtmlFooter();
×
119
                }
120
            }
121
        } else if (req.matches("/list/[0-9a-f]{64}")) {
×
122
            String pubkey = req.replaceFirst("/list/([0-9a-f]{64})", "$1");
×
123
            MongoCursor<Document> c = collection("lists").find(mongoSession, new Document("pubkey", pubkey)).projection(exclude("_id")).cursor();
×
124
            if (TYPE_JSON.equals(format)) {
×
125
                println("[");
×
126
                while (c.hasNext()) {
×
127
                    print(c.next().toJson());
×
128
                    println(c.hasNext() ? "," : "");
×
129
                }
130
                println("]");
×
131
            } else {
132
                printHtmlHeader("Accounts for Pubkey " + getLabel(pubkey) + " - Nanopub Registry");
×
133
                println("<h1>Accounts for Pubkey " + getLabel(pubkey) + "</h1>");
×
134
                println("<p><a href=\"/list\">&lt; Account List</a></p>");
×
135
                println("<h3>Formats</h3>");
×
136
                println("<p>");
×
137
                println("<a href=\"/list/" + pubkey + ".json\">.json</a> |");
×
138
                println("<a href=\"/list/" + pubkey + ".json.txt\">.json.txt</a>");
×
139
                println("</p>");
×
140
                println("<h3>Pubkey Hash</h3>");
×
141
                println("<p><code>" + pubkey + "</code></p>");
×
142
                println("<h3>Entry Lists</h3>");
×
143
                println("<ol>");
×
144
                while (c.hasNext()) {
×
145
                    Document d = c.next();
×
146
                    String type = d.getString("type");
×
147
                    println("<li>");
×
148
                    println("<a href=\"/list/" + pubkey + "/" + type + "\"><code>" + getLabel(type) + "</code></a> ");
×
149
                    if (type.equals("$")) {
×
150
                        println("(all types)");
×
151
                    } else {
152
                        println("(type " + unhash(type) + ")");
×
153
                    }
154
                    println("</li>");
×
155
                }
×
156
                println("</ol>");
×
157
                printHtmlFooter();
×
158
            }
159
        } else if (req.equals("/list")) {
×
160
            try (var c = collection("accounts").find(mongoSession).sort(ascending("pubkey")).projection(exclude("_id")).cursor()) {
×
161
                if (TYPE_JSON.equals(format)) {
×
162
                    println("[");
×
163
                    while (c.hasNext()) {
×
164
                        print(c.next().toJson());
×
165
                        println(c.hasNext() ? "," : "");
×
166
                    }
167
                    println("]");
×
168
                } else {
169
                    printHtmlHeader("Account List - Nanopub Registry");
×
170
                    println("<h1>Account List</h1>");
×
171
                    println("<p><a href=\"/\">&lt; Home</a></p>");
×
172
                    println("<h3>Formats</h3>");
×
173
                    println("<p>");
×
174
                    println("<a href=\"list.json\">.json</a> |");
×
175
                    println("<a href=\"list.json.txt\">.json.txt</a>");
×
176
                    println("</p>");
×
177
                    println("<h3>Accounts</h3>");
×
178
                    println("<ol>");
×
179
                    while (c.hasNext()) {
×
180
                        Document d = c.next();
×
181
                        String pubkey = d.getString("pubkey");
×
182
                        if (!pubkey.equals("$")) {
×
183
                            println("<li>");
×
184
                            println("<a href=\"/list/" + pubkey + "\"><code>" + getLabel(pubkey) + "</code></a>");
×
185
                            String a = d.getString("agent");
×
186
                            print(" by <a href=\"/agent?id=" + URLEncoder.encode(a, "UTF-8") + "\">" + Utils.getAgentLabel(a) + "</a>");
×
187
                            print(", status: " + d.get("status"));
×
188
                            print(", depth: " + d.get("depth"));
×
189
                            if (d.get("pathCount") != null) {
×
190
                                print(", pathCount: " + d.get("pathCount"));
×
191
                            }
192
                            if (d.get("ratio") != null) {
×
193
                                print(", ratio: " + df8.format(d.get("ratio")));
×
194
                            }
195
                            if (d.get("quota") != null) {
×
196
                                print(", quota: " + d.get("quota"));
×
197
                            }
198
                            println("");
×
199
                            println("</li>");
×
200
                        }
201
                    }
×
202
                    println("</ol>");
×
203
                    printHtmlFooter();
×
204
                }
205
            }
206
        } else if (req.equals("/agent") && context.request().getParam("id") != null) {
×
207
            String agentId = context.request().getParam("id");
×
208
            if (TYPE_JSON.equals(format)) {
×
209
                print(AgentInfo.get(mongoSession, agentId).asJson());
×
210
            } else {
211
                Document agentDoc = RegistryDB.getOne(mongoSession, "agents", new Document("agent", agentId));
×
212
                printHtmlHeader("Agent " + Utils.getAgentLabel(agentId) + " - Nanopub Registry");
×
213
                println("<h1>Agent " + Utils.getAgentLabel(agentId) + "</h1>");
×
214
                println("<p><a href=\"/agents\">&lt; Agent List</a></p>");
×
215
                println("<h3>Formats</h3>");
×
216
                println("<p>");
×
217
                println("<a href=\"agent.json?id=" + URLEncoder.encode(agentId, "UTF-8") + "\">.json</a> |");
×
218
                println("<a href=\"agent.json.txt?id=" + URLEncoder.encode(agentId, "UTF-8") + "\">.json.txt</a>");
×
219
                println("</p>");
×
220
                println("<h3>ID</h3>");
×
221
                println("<p><a href=\"" + agentId + "\"><code>" + agentId + "</code></a></p>");
×
222
                println("<h3>Properties</h3>");
×
223
                println("<ul>");
×
224
                println("<li>Average path count: " + agentDoc.get("avgPathCount") + "</li>");
×
225
                println("<li>Total ratio: " + agentDoc.get("totalRatio") + "</li>");
×
226
                println("</ul>");
×
227
                println("<h3>Accounts</h3>");
×
228
                println("<p>Count: " + agentDoc.get("accountCount") + "</p>");
×
229
                println("<p><a href=\"agentAccounts?id=" + URLEncoder.encode(agentId, "UTF-8") + "\">&gt; agentAccounts</a></p>");
×
230
                printHtmlFooter();
×
231
            }
232
        } else if (req.equals("/agentAccounts") && context.request().getParam("id") != null) {
×
233
            String agentId = context.request().getParam("id");
×
234
            MongoCursor<Document> c = collection("accounts").find(mongoSession, new Document("agent", agentId)).projection(exclude("_id")).cursor();
×
235
            if (TYPE_JSON.equals(format)) {
×
236
                println("[");
×
237
                while (c.hasNext()) {
×
238
                    print(c.next().toJson());
×
239
                    println(c.hasNext() ? "," : "");
×
240
                }
241
                println("]");
×
242
            } else {
243
                printHtmlHeader("Accounts of Agent " + Utils.getAgentLabel(agentId) + " - Nanopub Registry");
×
244
                println("<h1>Accounts of Agent " + Utils.getAgentLabel(agentId) + "</h1>");
×
245
                println("<p><a href=\"/agent?id=" + URLEncoder.encode(agentId, "UTF-8") + "\">&lt; Agent</a></p>");
×
246
                println("<h3>Formats</h3>");
×
247
                println("<p>");
×
248
                println("<a href=\"agentAccounts.json?id=" + URLEncoder.encode(agentId, "UTF-8") + "\">.json</a> |");
×
249
                println("<a href=\"agentAccounts.json.txt?id=" + URLEncoder.encode(agentId, "UTF-8") + "\">.json.txt</a>");
×
250
                println("</p>");
×
251
                println("<h3>Account List</h3>");
×
252
                println("<ul>");
×
253
                while (c.hasNext()) {
×
254
                    Document d = c.next();
×
255
                    String pubkey = d.getString("pubkey");
×
256
                    //                                Object iCount = getMaxValue("listEntries", new Document("pubkey", pubkey).append("type", INTRO_TYPE_HASH), "position");
257
                    //                                Object eCount = getMaxValue("listEntries", new Document("pubkey", pubkey).append("type", ENDORSE_TYPE), "position");
258
                    //                                Object fCount = getMaxValue("listEntries", new Document("pubkey", pubkey).append("type", "$"), "position");
259
                    println("<li><a href=\"/list/" + pubkey + "\"><code>" + getLabel(pubkey) + "</code></a> (" + d.get("status") + "), " + "quota " + d.get("quota") + ", " + "ratio " + df8.format(d.get("ratio")) + ", " + "path count " + d.get("pathCount") + "</li>");
×
260
                }
×
261
                println("</ul>");
×
262
                printHtmlFooter();
×
263
            }
264
        } else if (req.equals("/agents")) {
×
265
            MongoCursor<Document> c = collection("agents").find(mongoSession).sort(descending("totalRatio")).projection(exclude("_id")).cursor();
×
266
            if (TYPE_JSON.equals(format)) {
×
267
                println("[");
×
268
                while (c.hasNext()) {
×
269
                    print(c.next().toJson());
×
270
                    println(c.hasNext() ? "," : "");
×
271
                }
272
                println("]");
×
273
            } else {
274
                printHtmlHeader("Agent List - Nanopub Registry");
×
275
                println("<h1>Agent List</h1>");
×
276
                println("<p><a href=\"/\">&lt; Home</a></p>");
×
277
                println("<h3>Formats</h3>");
×
278
                println("<p>");
×
279
                println("<a href=\"agents.json\">.json</a> |");
×
280
                println("<a href=\"agents.json.txt\">.json.txt</a>");
×
281
                println("</p>");
×
282
                println("<h3>Agents</h3>");
×
283
                println("<ol>");
×
284
                while (c.hasNext()) {
×
285
                    Document d = c.next();
×
286
                    if (d.get("agent").equals("$")) continue;
×
287
                    String a = d.getString("agent");
×
288
                    int accountCount = d.getInteger("accountCount");
×
289
                    println("<li><a href=\"/agent?id=" + URLEncoder.encode(a, "UTF-8") + "\">" + Utils.getAgentLabel(a) + "</a>, " + accountCount + " account" + (accountCount == 1 ? "" : "s") + ", " + "ratio " + df8.format(d.get("totalRatio")) + ", " + "avg. path count " + df1.format(d.get("avgPathCount")) + "</li>");
×
290
                }
×
291
                println("</ol>");
×
292
                printHtmlFooter();
×
293
            }
294
        } else if (req.equals("/nanopubs")) {
×
295
            if (TYPE_JELLY.equals(format)) {
×
296
                // Return all nanopubs from after counter X (-1 by default)
297
                long afterCounter;
298
                try {
299
                    afterCounter = Long.parseLong(getParam("afterCounter", "-1"));
×
300
                } catch (NumberFormatException ex) {
×
301
                    context.response().setStatusCode(400).setStatusMessage("Invalid afterCounter parameter.");
×
302
                    return;
×
303
                }
×
304
                // TODO: something is aborting the Mongo transaction here after a while,
305
                //  find out what exactly.
306
                var pipeline = collection("nanopubs").find(mongoSession).filter(gt("counter", afterCounter)).sort(ascending("counter"))
×
307
                        // Only include the needed fields to save bandwidth to the DB
308
                        .projection(include("jelly", "counter"));
×
309

310
                try (var result = pipeline.cursor()) {
×
311
                    NanopubStream npStream = NanopubStream.fromMongoCursorWithCounter(result);
×
312
                    BufferOutputStream outputStream = new BufferOutputStream();
×
313
                    npStream.writeToByteStream(outputStream);
×
314
                    context.response().write(outputStream.getBuffer());
×
315
                }
316
            } else {
×
317
                // Return latest nanopubs
318

319
                MongoCursor<Document> c = collection("nanopubs").find(mongoSession).sort(descending("counter")).limit(1000).cursor();
×
320
                if (TYPE_JSON.equals(format)) {
×
321
                    println("[");
×
322
                    while (c.hasNext()) {
×
323
                        print(gson.toJson(c.next().getString("_id")));
×
324
                        println(c.hasNext() ? "," : "");
×
325
                    }
326
                    println("]");
×
327
                } else {
328
                    printHtmlHeader("Latest nanopubs - Nanopub Registry");
×
329
                    println("<h1>Nanopubs</h1>");
×
330
                    println("<p><a href=\"/\">&lt; Home</a></p>");
×
331
                    println("<h3>Latest Nanopubs JSON (max. 1000)</h3>");
×
332
                    println("<p>");
×
333
                    println("<a href=\"nanopubs.json\">.json</a> |");
×
334
                    println("<a href=\"nanopubs.json.txt\">.json.txt</a>");
×
335
                    println("</p>");
×
336
                    println("<h3>All Nanopubs (Jelly)</h3>");
×
337
                    println("<p><a href=\"nanopubs.jelly\">.jelly</a></p>");
×
338
                    println("<h3>Latest Nanopubs List (max. 1000)</h3>");
×
339
                    println("<ol>");
×
340
                    while (c.hasNext()) {
×
341
                        String npId = c.next().getString("_id");
×
342
                        println("<li><a href=\"/np/" + npId + "\"><code>" + getLabel(npId) + "</code></a></li>");
×
343
                    }
×
344
                    println("</ol>");
×
345
                    printHtmlFooter();
×
346
                }
347
            }
×
348
        } else if (req.equals("/pubkeys")) {
×
349
            try (var c = collection("lists").distinct(mongoSession, "pubkey", String.class).cursor()) {
×
350
                if (TYPE_JSON.equals(format)) {
×
351
                    println("[");
×
352
                    while (c.hasNext()) {
×
353
                        print(gson.toJson(c.next()));
×
354
                        println(c.hasNext() ? "," : "");
×
355
                    }
356
                    println("]");
×
357
                } else {
358
                    printHtmlHeader("Pubkey List - Nanopub Registry");
×
359
                    println("<h1>Pubkey List</h1>");
×
360
                    println("<p><a href=\"/\">&lt; Home</a></p>");
×
361
                    println("<h3>Formats</h3>");
×
362
                    println("<p>");
×
363
                    println("<a href=\"pubkeys.json\">.json</a> |");
×
364
                    println("<a href=\"pubkeys.json.txt\">.json.txt</a>");
×
365
                    println("</p>");
×
366
                    println("<h3>Pubkeys</h3>");
×
367
                    println("<ol>");
×
368
                    while (c.hasNext()) {
×
369
                        String pubkey = c.next();
×
370
                        if (!pubkey.equals("$")) {
×
371
                            println("<li>");
×
372
                            println("<a href=\"/list/" + pubkey + "\"><code>" + getLabel(pubkey) + "</code></a>");
×
373
                            println("</li>");
×
374
                        }
375
                    }
×
376
                    println("</ol>");
×
377
                    printHtmlFooter();
×
378
                }
379
            }
380
        } else {
381
            context.response().setStatusCode(400).setStatusMessage("Invalid request: " + getFullRequest());
×
382
        }
383
    }
×
384

385
    private static String getLabel(Object obj) {
386
        if (obj == null) return null;
×
387
        if (obj.toString().length() < 10) return obj.toString();
×
388
        return obj.toString().substring(0, 10);
×
389
    }
390

391
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc