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

knowledgepixels / nanodash / 17852532121

19 Sep 2025 08:10AM UTC coverage: 13.568% (-0.3%) from 13.87%
17852532121

push

github

tkuhn
feat: Switch to QueryRef provided by nanopub, using multimap

428 of 4008 branches covered (10.68%)

Branch coverage included in aggregate %.

1104 of 7283 relevant lines covered (15.16%)

0.68 hits per line

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

0.0
src/main/java/com/knowledgepixels/nanodash/connector/GenOverviewPage.java
1
package com.knowledgepixels.nanodash.connector;
2

3
import java.util.ArrayList;
4
import java.util.List;
5

6
import org.apache.wicket.ajax.AjaxRequestTarget;
7
import org.apache.wicket.ajax.markup.html.AjaxLink;
8
import org.apache.wicket.markup.html.WebMarkupContainer;
9
import org.apache.wicket.markup.html.basic.Label;
10
import org.apache.wicket.markup.html.image.Image;
11
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
12
import org.apache.wicket.markup.html.link.ExternalLink;
13
import org.apache.wicket.markup.repeater.Item;
14
import org.apache.wicket.markup.repeater.data.DataView;
15
import org.apache.wicket.markup.repeater.data.ListDataProvider;
16
import org.apache.wicket.request.mapper.parameter.PageParameters;
17
import org.apache.wicket.request.resource.PackageResourceReference;
18
import org.eclipse.rdf4j.model.IRI;
19
import org.nanopub.Nanopub;
20
import org.nanopub.extra.services.ApiResponse;
21
import org.nanopub.extra.services.ApiResponseEntry;
22
import org.nanopub.extra.services.QueryRef;
23
import org.slf4j.Logger;
24
import org.slf4j.LoggerFactory;
25

26
import com.knowledgepixels.nanodash.ApiCache;
27
import com.knowledgepixels.nanodash.NanodashPreferences;
28
import com.knowledgepixels.nanodash.NanodashSession;
29
import com.knowledgepixels.nanodash.User;
30
import com.knowledgepixels.nanodash.Utils;
31
import com.knowledgepixels.nanodash.component.TitleBar;
32
import com.knowledgepixels.nanodash.page.OrcidLoginPage;
33
import com.knowledgepixels.nanodash.page.PublishPage;
34

35
/**
36
 * Overview page for a connector journal.
37
 */
38
public class GenOverviewPage extends ConnectorPage {
39

40
    private static final Logger logger = LoggerFactory.getLogger(GenOverviewPage.class);
×
41

42
    /**
43
     * The mount path for this page.
44
     */
45
    public static final String MOUNT_PATH = "/connector";
46

47
    private ConnectorConfig config;
48

49
    /**
50
     * Constructor for the overview page.
51
     *
52
     * @param params the page parameters, which should contain the journal ID
53
     */
54
    public GenOverviewPage(PageParameters params) {
55
        super(params);
×
56
        final String journalId = params.get("journal").toString();
×
57
        config = ConnectorConfig.get(journalId);
×
58

59
        add(new TitleBar("titlebar", this, "connectors"));
×
60
        add(new Image("logo", new PackageResourceReference(getConfig().getClass(), getConfig().getLogoFileName())));
×
61

62
        if (getConfig().getTechnicalEditorIds().contains(NanodashSession.get().getUserIri())) {
×
63
            WebMarkupContainer technicalEditorActions = new WebMarkupContainer("technical-editor-actions");
×
64

65
            technicalEditorActions.add(new BookmarkablePageLink<Void>("publish-article-metadata", PublishPage.class,
×
66
                    new PageParameters().add("template", "https://w3id.org/np/RA48p4Ct8tWL--rIc1Dcr2BcYpW_7X1pfuv_2LK3anolY")
×
67
                            .add("template-version", "latest")
×
68
                            .add("param_journal", getConfig().getJournalIssn())
×
69
                            .add("param_journal-title", getConfig().getJournalName())
×
70
                            .add("prtemplate", "https://w3id.org/np/RAekcN47h13fk6ZK4XiObgGgk-qB01sLOjyGyhMCq_jT4")
×
71
                            .add("pitemplate1", "https://w3id.org/np/RA5R_qv3VsZIrDKd8Mr37x3HoKCsKkwN5tJVqgQsKhjTE")
×
72
                            .add("piparam1_type", getConfig().getNanopubType() == null ? "" : getConfig().getNanopubType().stringValue())
×
73
                            .add("pitemplate2", "https://w3id.org/np/RA16U9Wo30ObhrK1NzH7EsmVRiRtvEuEA_Dfc-u8WkUCA")
×
74
                            .add("target-namespace", getConfig().getTargetNamespace() == null ? "https://w3id.org/np/" : getConfig().getTargetNamespace())
×
75
            ));
76
            add(technicalEditorActions);
×
77
        } else {
×
78
            add(new WebMarkupContainer("technical-editor-actions").setVisible(false));
×
79
        }
80

81
        try {
82

83
            final WebMarkupContainer c = new WebMarkupContainer("owncandidates-component");
×
84
            c.setOutputMarkupId(true);
×
85
            add(c);
×
86

87
            if (NanodashSession.get().getUserIri() != null) {
×
88
                QueryRef queryRef = new QueryRef(getConfig().getCandidateNanopubsApiCall(), "creator", NanodashSession.get().getUserIri().stringValue());
×
89
                ApiResponse resp = ApiCache.retrieveResponse(queryRef);
×
90
                while (resp == null) {
×
91
                    // we only get here in case of second-generation API calls
92
                    // TODO Do this in an AJAX way:
93
                    try {
94
                        Thread.sleep(200);
×
95
                    } catch (InterruptedException ex) {
×
96
                        logger.error("Thread interrupted", ex);
×
97
                    }
×
98
                    resp = ApiCache.retrieveResponse(queryRef);
×
99
                }
100

101
                final List<ApiResponseEntry> listData = new ArrayList<ApiResponseEntry>();
×
102
                final ArrayList<ApiResponseEntry> fullList = new ArrayList<>();
×
103
                for (ApiResponseEntry a : resp.getData()) {
×
104
                    if (listData.size() < 10) listData.add(a);
×
105
                    // TODO This will become inefficient at some point:
106
                    fullList.add(a);
×
107
                }
×
108

109
                c.add(new DataView<ApiResponseEntry>("own", new ListDataProvider<ApiResponseEntry>(listData)) {
×
110

111
                    @Override
112
                    protected void populateItem(Item<ApiResponseEntry> item) {
113
                        ApiResponseEntry e = item.getModelObject();
×
114
                        PageParameters params = new PageParameters().add("journal", journalId).add("id", e.get("np")).add("mode", "author");
×
115
                        BookmarkablePageLink<Void> l = new BookmarkablePageLink<Void>("ownlink", GenNanopubPage.class, params);
×
116
                        l.add(new Label("ownlinktext", "\"" + e.get("label") + "\""));
×
117
                        item.add(l);
×
118
                        String pubkeyhash = Utils.createSha256HexHash(e.get("pubkey"));
×
119
                        String username = User.getShortDisplayNameForPubkeyhash(null, pubkeyhash);
×
120
                        item.add(new Label("ownnote", "by " + username + " on " + e.get("date").substring(0, 10)));
×
121
                    }
×
122

123
                });
124

125
                c.add(new AjaxLink<>("allowncandidates") {
×
126

127
                    @Override
128
                    public void onClick(AjaxRequestTarget target) {
129
                        try {
130
                            listData.clear();
×
131
                            listData.addAll(fullList);
×
132
                            target.add(c);
×
133
                            setVisible(false);
×
134
                            target.add(this);
×
135
                        } catch (Exception ex) {
×
136
                            logger.error("Error showing all candidates", ex);
×
137
                        }
×
138
                    }
×
139

140
                }.setVisible(fullList.size() > 10));
×
141

142
                add(new BookmarkablePageLink<Void>("create-new", GenSelectPage.class, params));
×
143
            } else {
×
144
                c.add(new Label("allowncandidates", "").setVisible(false));
×
145
                c.add(new Label("own", "").setVisible(false));
×
146
                if (NanodashPreferences.get().isOrcidLoginMode()) {
×
147
                    String loginUrl = OrcidLoginPage.getOrcidLoginUrl(getMountPath(), getPageParameters());
×
148
                    add(new ExternalLink("create-new", loginUrl, "Login to See More"));
×
149
                } else {
×
150
                    add(new ExternalLink("create-new", Utils.getUrlWithParameters(getMountPath(), getPageParameters()), "Complete Your Profile to See More"));
×
151
                }
152
            }
153
        } catch (Exception ex) {
×
154
            logger.error("Error in own candidates section", ex);
×
155
        }
×
156

157
        try {
158
            final WebMarkupContainer c = new WebMarkupContainer("candidates-component");
×
159
            c.setOutputMarkupId(true);
×
160
            add(c);
×
161

162
            QueryRef queryRef = new QueryRef(getConfig().getCandidateNanopubsApiCall());
×
163
            ApiResponse resp = ApiCache.retrieveResponse(queryRef);
×
164
            while (resp == null) {
×
165
                // TODO Do this in an AJAX way:
166
                try {
167
                    Thread.sleep(200);
×
168
                } catch (InterruptedException ex) {
×
169
                    logger.error("Thread interrupted", ex);
×
170
                }
×
171
                resp = ApiCache.retrieveResponse(queryRef);
×
172
            }
173

174
            final List<ApiResponseEntry> listData = new ArrayList<ApiResponseEntry>();
×
175
            final ArrayList<ApiResponseEntry> fullList = new ArrayList<>();
×
176
            for (ApiResponseEntry a : resp.getData()) {
×
177
                if (listData.size() < 10) listData.add(a);
×
178
                // TODO This will become inefficient at some point:
179
                fullList.add(a);
×
180
            }
×
181

182
            c.add(new DataView<ApiResponseEntry>("candidates", new ListDataProvider<ApiResponseEntry>(listData)) {
×
183

184
                @Override
185
                protected void populateItem(Item<ApiResponseEntry> item) {
186
                    ApiResponseEntry e = item.getModelObject();
×
187
                    PageParameters params = new PageParameters().add("journal", journalId).add("id", e.get("np")).add("mode", "candidate");
×
188
                    BookmarkablePageLink<Void> l = new BookmarkablePageLink<Void>("candidatelink", GenNanopubPage.class, params);
×
189
                    l.add(new Label("candidatelinktext", "\"" + e.get("label") + "\""));
×
190
                    item.add(l);
×
191
                    String pubkeyhash = Utils.createSha256HexHash(e.get("pubkey"));
×
192
                    String username = User.getShortDisplayNameForPubkeyhash(null, pubkeyhash);
×
193
                    item.add(new Label("candidatenote", "by " + username + " on " + e.get("date").substring(0, 10)));
×
194
                }
×
195

196
            });
197

198
            c.add(new AjaxLink<>("allcandidates") {
×
199

200
                @Override
201
                public void onClick(AjaxRequestTarget target) {
202
                    try {
203
                        listData.clear();
×
204
                        listData.addAll(fullList);
×
205
                        target.add(c);
×
206
                        setVisible(false);
×
207
                        target.add(this);
×
208
                    } catch (Exception ex) {
×
209
                        logger.error("Error in all candidates click", ex);
×
210
                    }
×
211
                }
×
212

213
            }.setVisible(fullList.size() > 10));
×
214

215
        } catch (Exception ex) {
×
216
            logger.error("Error in candidates section", ex);
×
217
        }
×
218

219
        if (getConfig().getAcceptedNanopubsApiCall() != null) {
×
220
            try {
221
                final WebMarkupContainer c = new WebMarkupContainer("accepted-component");
×
222
                c.setOutputMarkupId(true);
×
223
                add(c);
×
224

225
                QueryRef queryRef = new QueryRef(getConfig().getAcceptedNanopubsApiCall());
×
226
                ApiResponse resp = ApiCache.retrieveResponse(queryRef);
×
227
                while (resp == null) {
×
228
                    // TODO Do this in an AJAX way:
229
                    try {
230
                        Thread.sleep(200);
×
231
                    } catch (InterruptedException ex) {
×
232
                        logger.error("Thread interrupted", ex);
×
233
                    }
×
234
                    resp = ApiCache.retrieveResponse(queryRef);
×
235
                }
236

237
                final List<ApiResponseEntry> listData = new ArrayList<ApiResponseEntry>();
×
238
                final ArrayList<ApiResponseEntry> fullList = new ArrayList<>();
×
239
                for (ApiResponseEntry a : resp.getData()) {
×
240
                    if (listData.size() < 10) listData.add(a);
×
241
                    // TODO This will become inefficient at some point:
242
                    fullList.add(a);
×
243
                }
×
244

245
                c.add(new DataView<ApiResponseEntry>("accepted", new ListDataProvider<ApiResponseEntry>(listData)) {
×
246

247
                    @Override
248
                    protected void populateItem(Item<ApiResponseEntry> item) {
249
                        ApiResponseEntry e = item.getModelObject();
×
250
                        PageParameters params = new PageParameters().add("journal", journalId).add("id", e.get("np")).add("mode", "final");
×
251
                        BookmarkablePageLink<Void> l = new BookmarkablePageLink<Void>("acceptedlink", GenNanopubPage.class, params);
×
252
                        l.add(new Label("acceptedlinktext", "\"" + e.get("label") + "\""));
×
253
                        item.add(l);
×
254
                        IRI firstAuthorIri = Utils.vf.createIRI(e.get("firstAuthor"));
×
255

256
                        // TODO Move this user name extraction to a helper method:
257
                        String username;
258
                        if (User.getName(firstAuthorIri) != null) {
×
259
                            username = User.getShortDisplayName(firstAuthorIri);
×
260
                        } else {
261
                            try {
262
                                Nanopub np = Utils.getAsNanopub(e.get("np"));
×
263
                                username = Utils.getFoafNameMap(np).get(e.get("firstAuthor"));
×
264
                            } catch (Exception ex) {
×
265
                                logger.error("Error getting FOAF name for {} in {}", e.get("firstAuthor"), e.get("np"), ex);
×
266
                                username = User.getShortDisplayName(firstAuthorIri);
×
267
                            }
×
268
                        }
269

270
                        item.add(new Label("acceptednote", "by " + username + " on " + e.get("date").substring(0, 10)));
×
271
                    }
×
272

273
                });
274

275
                c.add(new AjaxLink<>("allaccepted") {
×
276

277
                    @Override
278
                    public void onClick(AjaxRequestTarget target) {
279
                        try {
280
                            listData.clear();
×
281
                            listData.addAll(fullList);
×
282
                            target.add(c);
×
283
                            setVisible(false);
×
284
                            target.add(this);
×
285
                        } catch (Exception ex) {
×
286
                            logger.error("Error showing all accepted", ex);
×
287
                        }
×
288
                    }
×
289

290
                }.setVisible(fullList.size() > 10));
×
291

292
            } catch (Exception ex) {
×
293
                logger.error("Error in accepted section", ex);
×
294
            }
×
295
        }
296

297
        if (getConfig().getGeneralReactionsApiCall() != null) {
×
298
            try {
299
                final WebMarkupContainer c = new WebMarkupContainer("reactions-component");
×
300
                c.setOutputMarkupId(true);
×
301
                add(c);
×
302

303
                QueryRef queryRef = new QueryRef(getConfig().getGeneralReactionsApiCall());
×
304
                ApiResponse resp = ApiCache.retrieveResponse(queryRef);
×
305
                while (resp == null) {
×
306
                    // TODO Do this in an AJAX way:
307
                    try {
308
                        Thread.sleep(200);
×
309
                    } catch (InterruptedException ex) {
×
310
                        logger.error("Thread interrupted", ex);
×
311
                    }
×
312
                    resp = ApiCache.retrieveResponse(queryRef);
×
313
                }
314

315
                final List<ApiResponseEntry> listData = new ArrayList<ApiResponseEntry>();
×
316
                final ArrayList<ApiResponseEntry> fullList = new ArrayList<>();
×
317
                for (ApiResponseEntry a : resp.getData()) {
×
318
                    if (listData.size() < 10) listData.add(a);
×
319
                    // TODO This will become inefficient at some point:
320
                    fullList.add(a);
×
321
                }
×
322

323
                c.add(new DataView<ApiResponseEntry>("reactions", new ListDataProvider<ApiResponseEntry>(listData)) {
×
324

325
                    @Override
326
                    protected void populateItem(Item<ApiResponseEntry> item) {
327
                        ApiResponseEntry e = item.getModelObject();
×
328
                        PageParameters params = new PageParameters().add("journal", journalId).add("id", e.get("ref_np")).add("mode", "candidate");
×
329
                        BookmarkablePageLink<Void> l = new BookmarkablePageLink<Void>("reactionlink", GenNanopubPage.class, params);
×
330
                        l.add(new Label("reactionlinktext", "\"" + e.get("comment") + "\""));
×
331
                        item.add(l);
×
332
                        String pubkeyhash = Utils.createSha256HexHash(e.get("pubkey"));
×
333
                        String username = User.getShortDisplayNameForPubkeyhash(null, pubkeyhash);
×
334
                        item.add(new Label("reactionnote", "by " + username + " on " + e.get("date").substring(0, 10)));
×
335
                    }
×
336

337
                });
338

339
                c.add(new AjaxLink<>("allreactions") {
×
340

341
                    @Override
342
                    public void onClick(AjaxRequestTarget target) {
343
                        try {
344
                            listData.clear();
×
345
                            listData.addAll(fullList);
×
346
                            target.add(c);
×
347
                            setVisible(false);
×
348
                            target.add(this);
×
349
                        } catch (Exception ex) {
×
350
                            logger.error("Error showing all reactions", ex);
×
351
                        }
×
352
                    }
×
353

354
                }.setVisible(fullList.size() > 10));
×
355

356
            } catch (Exception ex) {
×
357
                logger.error("Error in reactions section", ex);
×
358
            }
×
359
        }
360

361
        add(new Label("pagetitle", config.getJournalName() + " | nanodash"));
×
362
        add(new Label("journal-name-title", config.getJournalName()));
×
363
        add(new ExternalLink("journal-link", config.getJournalUrl(), config.getJournalName()));
×
364
        add(new Label("extra-instructions", config.getExtraInstructions()).setEscapeModelStrings(false));
×
365

366
        if (getConfig().getGeneralReactionsApiCall() == null) {
×
367
            // TODO Fix this in OverviewPage code once refactoring is finished:
368
            add(new Label("reactions-component").setVisible(false));
×
369
        }
370
        add(new ExternalLink("support-link", "mailto:contact-project+knowledgepixels-support-desk@incoming.gitlab.com?subject=[" + config.getJournalAbbrev() + "%20general]%20my%20problem/question&body=type%20your%20problem/question%20here"));
×
371
    }
×
372

373
    /**
374
     * {@inheritDoc}
375
     */
376
    @Override
377
    public String getMountPath() {
378
        return MOUNT_PATH;
×
379
    }
380

381
}
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