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

knowledgepixels / nanodash / 21766377938

06 Feb 2026 09:20PM UTC coverage: 14.086% (+0.2%) from 13.838%
21766377938

push

github

tkuhn
refactor: use nanopub URI as preview page id instead of random UUID

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

577 of 5266 branches covered (10.96%)

Branch coverage included in aggregate %.

1519 of 9614 relevant lines covered (15.8%)

2.07 hits per line

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

0.0
src/main/java/com/knowledgepixels/nanodash/component/PublishForm.java
1
package com.knowledgepixels.nanodash.component;
2

3
import java.lang.reflect.InvocationTargetException;
4
import java.util.ArrayList;
5
import java.util.Collection;
6
import java.util.HashMap;
7
import java.util.List;
8
import java.util.Map;
9

10
import org.apache.commons.lang3.Strings;
11
import org.apache.wicket.Component;
12
import org.apache.wicket.RestartResponseException;
13
import org.apache.wicket.ajax.AjaxEventBehavior;
14
import org.apache.wicket.ajax.AjaxRequestTarget;
15
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
16
import org.apache.wicket.feedback.FeedbackMessage;
17
import org.apache.wicket.markup.html.WebMarkupContainer;
18
import org.apache.wicket.markup.html.WebPage;
19
import org.apache.wicket.markup.html.basic.Label;
20
import org.apache.wicket.markup.html.form.Button;
21
import org.apache.wicket.markup.html.form.CheckBox;
22
import org.apache.wicket.markup.html.form.Form;
23
import org.apache.wicket.markup.html.form.FormComponent;
24
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
25
import org.apache.wicket.markup.html.list.ListItem;
26
import org.apache.wicket.markup.html.list.ListView;
27
import org.apache.wicket.markup.html.panel.FeedbackPanel;
28
import org.apache.wicket.markup.html.panel.Panel;
29
import org.apache.wicket.markup.repeater.Item;
30
import org.apache.wicket.markup.repeater.data.DataView;
31
import org.apache.wicket.markup.repeater.data.ListDataProvider;
32
import org.apache.wicket.model.IModel;
33
import org.apache.wicket.model.Model;
34
import org.apache.wicket.request.mapper.parameter.PageParameters;
35
import org.apache.wicket.validation.IValidatable;
36
import org.apache.wicket.validation.IValidator;
37
import org.apache.wicket.validation.ValidationError;
38
import org.eclipse.rdf4j.model.IRI;
39
import org.eclipse.rdf4j.model.Literal;
40
import org.eclipse.rdf4j.model.Statement;
41
import org.eclipse.rdf4j.model.ValueFactory;
42
import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
43
import org.eclipse.rdf4j.model.vocabulary.FOAF;
44
import org.eclipse.rdf4j.model.vocabulary.RDFS;
45
import org.nanopub.MalformedNanopubException;
46
import org.nanopub.Nanopub;
47
import org.nanopub.NanopubAlreadyFinalizedException;
48
import org.nanopub.NanopubCreator;
49
import org.nanopub.extra.security.SignNanopub;
50
import org.nanopub.extra.security.SignatureAlgorithm;
51
import org.nanopub.extra.security.TransformContext;
52
import org.nanopub.extra.server.PublishNanopub;
53
import org.nanopub.extra.services.ApiResponse;
54
import org.nanopub.extra.services.ApiResponseEntry;
55
import org.nanopub.extra.services.QueryRef;
56
import org.nanopub.vocabulary.NPX;
57
import org.nanopub.vocabulary.NTEMPLATE;
58
import org.slf4j.Logger;
59
import org.slf4j.LoggerFactory;
60
import org.wicketstuff.select2.ChoiceProvider;
61
import org.wicketstuff.select2.Response;
62
import org.wicketstuff.select2.Select2Choice;
63

64
import com.knowledgepixels.nanodash.ApiCache;
65
import com.knowledgepixels.nanodash.LocalUri;
66
import com.knowledgepixels.nanodash.MaintainedResource;
67
import com.knowledgepixels.nanodash.NanodashPreferences;
68
import com.knowledgepixels.nanodash.NanodashSession;
69
import com.knowledgepixels.nanodash.ResourceWithProfile;
70
import com.knowledgepixels.nanodash.QueryApiAccess;
71
import com.knowledgepixels.nanodash.Space;
72
import com.knowledgepixels.nanodash.User;
73
import com.knowledgepixels.nanodash.Utils;
74
import com.knowledgepixels.nanodash.page.ExplorePage;
75
import com.knowledgepixels.nanodash.page.MaintainedResourcePage;
76
import com.knowledgepixels.nanodash.page.NanodashPage;
77
import com.knowledgepixels.nanodash.page.PreviewPage;
78
import com.knowledgepixels.nanodash.page.ResourcePartPage;
79
import com.knowledgepixels.nanodash.page.SpacePage;
80
import com.knowledgepixels.nanodash.page.UserPage;
81
import com.knowledgepixels.nanodash.template.ContextType;
82
import com.knowledgepixels.nanodash.template.Template;
83
import com.knowledgepixels.nanodash.template.TemplateContext;
84
import com.knowledgepixels.nanodash.template.TemplateData;
85
import com.knowledgepixels.nanodash.template.ValueFiller;
86

87
/**
88
 * Form for publishing a nanopublication.
89
 */
90
public class PublishForm extends Panel {
91

92
    private static final Logger logger = LoggerFactory.getLogger(PublishForm.class);
×
93

94
    private static final ValueFactory vf = SimpleValueFactory.getInstance();
×
95

96
    private static String creatorPubinfoTemplateId = "https://w3id.org/np/RAukAcWHRDlkqxk7H2XNSegc1WnHI569INvNr-xdptDGI";
×
97
    private static String licensePubinfoTempalteId = "https://w3id.org/np/RA0J4vUn_dekg-U1kK3AOEt02p9mT2WO03uGxLDec1jLw";
×
98
    private static String defaultProvTemplateId = "https://w3id.org/np/RA7lSq6MuK_TIC6JMSHvLtee3lpLoZDOqLJCLXevnrPoU";
×
99
    private static String supersedesPubinfoTemplateId = "https://w3id.org/np/RAoTD7udB2KtUuOuAe74tJi1t3VzK0DyWS7rYVAq1GRvw";
×
100
    private static String derivesFromPubinfoTemplateId = "https://w3id.org/np/RARW4MsFkHuwjycNElvEVtuMjpf4yWDL10-0C5l2MqqRQ";
×
101

102
    private static String[] fixedPubInfoTemplates = new String[]{creatorPubinfoTemplateId, licensePubinfoTempalteId};
×
103

104
    /**
105
     * Fill modes for the nanopublication to be created.
106
     */
107
    public enum FillMode {
×
108
        /**
109
         * Use fill mode
110
         */
111
        USE,
×
112
        /**
113
         * Supersede fill mode
114
         */
115
        SUPERSEDE,
×
116
        /**
117
         * Derive fill mode
118
         */
119
        DERIVE
×
120
    }
121

122
    protected Form<?> form;
123
    protected FeedbackPanel feedbackPanel;
124
    private final TemplateContext assertionContext;
125
    private TemplateContext provenanceContext;
126
    private List<TemplateContext> pubInfoContexts = new ArrayList<>();
×
127
    private Map<String, TemplateContext> pubInfoContextMap = new HashMap<>();
×
128
    private List<TemplateContext> requiredPubInfoContexts = new ArrayList<>();
×
129
    private String targetNamespace;
130
    private Class<? extends WebPage> confirmPageClass;
131

132
    /**
133
     * Constructor for the PublishForm.
134
     *
135
     * @param id               the Wicket component ID
136
     * @param pageParams       the parameters for the page, which may include information on how to fill the form
137
     * @param publishPageClass the class of the page to redirect to after successful publication
138
     * @param confirmPageClass the class of the confirmation page to show after publication
139
     */
140
    public PublishForm(String id, final PageParameters pageParams, Class<? extends WebPage> publishPageClass, Class<? extends WebPage> confirmPageClass) {
141
        super(id);
×
142
        setOutputMarkupId(true);
×
143
        this.confirmPageClass = confirmPageClass;
×
144

145
        WebMarkupContainer linkMessageItem = new WebMarkupContainer("link-message-item");
×
146
        if (pageParams.get("link-message").isNull()) {
×
147
            linkMessageItem.add(new Label("link-message", ""));
×
148
            linkMessageItem.setVisible(false);
×
149
        } else {
150
            linkMessageItem.add(new Label("link-message", Utils.sanitizeHtml(pageParams.get("link-message").toString())).setEscapeModelStrings(false));
×
151
        }
152
        add(linkMessageItem);
×
153

154
        final Nanopub fillNp;
155
        final FillMode fillMode;
156
        boolean fillOnlyAssertion = false;
×
157
        if (!pageParams.get("use").isNull()) {
×
158
            fillNp = Utils.getNanopub(pageParams.get("use").toString());
×
159
            fillMode = FillMode.USE;
×
160
        } else if (!pageParams.get("use-a").isNull()) {
×
161
            fillNp = Utils.getNanopub(pageParams.get("use-a").toString());
×
162
            fillMode = FillMode.USE;
×
163
            fillOnlyAssertion = true;
×
164
        } else if (!pageParams.get("supersede").isNull()) {
×
165
            fillNp = Utils.getNanopub(pageParams.get("supersede").toString());
×
166
            fillMode = FillMode.SUPERSEDE;
×
167
            targetNamespace = pageParams.get("supersede").toString().replaceFirst("RA[A-Za-z0-9-_]{43}$", "");
×
168
        } else if (!pageParams.get("supersede-a").isNull()) {
×
169
            fillNp = Utils.getNanopub(pageParams.get("supersede-a").toString());
×
170
            fillMode = FillMode.SUPERSEDE;
×
171
            fillOnlyAssertion = true;
×
172
        } else if (!pageParams.get("derive").isNull()) {
×
173
            fillNp = Utils.getNanopub(pageParams.get("derive").toString());
×
174
            fillMode = FillMode.DERIVE;
×
175
        } else if (!pageParams.get("derive-a").isNull()) {
×
176
            fillNp = Utils.getNanopub(pageParams.get("derive-a").toString());
×
177
            fillMode = FillMode.DERIVE;
×
178
            fillOnlyAssertion = true;
×
179
        } else if (!pageParams.get("fill-all").isNull()) {
×
180
            // TODO: This is deprecated and should be removed at some point
181
            fillNp = Utils.getNanopub(pageParams.get("fill-all").toString());
×
182
            fillMode = FillMode.USE;
×
183
        } else if (!pageParams.get("fill").isNull()) {
×
184
            // TODO: This is deprecated and should be removed at some point
185
            fillNp = Utils.getNanopub(pageParams.get("fill").toString());
×
186
            fillMode = FillMode.SUPERSEDE;
×
187
        } else {
188
            fillNp = null;
×
189
            fillMode = null;
×
190
        }
191

192
        final TemplateData td = TemplateData.get();
×
193

194
        // TODO Properly integrate this namespace feature:
195
        String templateId = pageParams.get("template").toString();
×
196
        if (td.getTemplate(templateId).getTargetNamespace() != null) {
×
197
            targetNamespace = td.getTemplate(templateId).getTargetNamespace();
×
198
        }
199
        if (!pageParams.get("target-namespace").isNull()) {
×
200
            targetNamespace = pageParams.get("target-namespace").toString();
×
201
        }
202
        if (targetNamespace == null) {
×
203
            targetNamespace = Template.DEFAULT_TARGET_NAMESPACE;
×
204
        }
205
        String targetNamespaceLabel = targetNamespace + "...";
×
206
        targetNamespace = targetNamespace + "~~~ARTIFACTCODE~~~/";
×
207

208
        assertionContext = new TemplateContext(ContextType.ASSERTION, templateId, "statement", targetNamespace);
×
209
        assertionContext.setFillMode(fillMode);
×
210
        final String prTemplateId;
211
        if (pageParams.get("prtemplate").toString() != null) {
×
212
            prTemplateId = pageParams.get("prtemplate").toString();
×
213
        } else {
214
            if (fillNp != null && !fillOnlyAssertion) {
×
215
                if (td.getProvenanceTemplateId(fillNp) != null) {
×
216
                    prTemplateId = td.getProvenanceTemplateId(fillNp).stringValue();
×
217
                } else {
218
                    prTemplateId = "http://purl.org/np/RAcm8OurwUk15WOgBM9wySo-T3a5h6as4K8YR5MBrrxUc";
×
219
                }
220
            } else if (assertionContext.getTemplate().getDefaultProvenance() != null) {
×
221
                prTemplateId = assertionContext.getTemplate().getDefaultProvenance().stringValue();
×
222
            } else {
223
                prTemplateId = defaultProvTemplateId;
×
224
            }
225
        }
226
        provenanceContext = new TemplateContext(ContextType.PROVENANCE, prTemplateId, "pr-statement", targetNamespace);
×
227
        for (String t : fixedPubInfoTemplates) {
×
228
            // TODO consistently check for latest versions of templates here and below:
229
            TemplateContext c = new TemplateContext(ContextType.PUBINFO, t, "pi-statement", targetNamespace);
×
230
            pubInfoContexts.add(c);
×
231
            pubInfoContextMap.put(c.getTemplate().getId(), c);
×
232
            requiredPubInfoContexts.add(c);
×
233
        }
234
        if (fillMode == FillMode.SUPERSEDE) {
×
235
            TemplateContext c = new TemplateContext(ContextType.PUBINFO, supersedesPubinfoTemplateId, "pi-statement", targetNamespace);
×
236
            pubInfoContexts.add(c);
×
237
            pubInfoContextMap.put(supersedesPubinfoTemplateId, c);
×
238
            //requiredPubInfoContexts.add(c);
239
            c.setParam("np", fillNp.getUri().stringValue());
×
240
        } else if (fillMode == FillMode.DERIVE) {
×
241
            TemplateContext c = new TemplateContext(ContextType.PUBINFO, derivesFromPubinfoTemplateId, "pi-statement", targetNamespace);
×
242
            pubInfoContexts.add(c);
×
243
            pubInfoContextMap.put(derivesFromPubinfoTemplateId, c);
×
244
            c.setParam("np", fillNp.getUri().stringValue());
×
245
        }
246
        for (IRI r : assertionContext.getTemplate().getRequiredPubinfoElements()) {
×
247
            String latestId = QueryApiAccess.getLatestVersionId(r.stringValue());
×
248
            if (pubInfoContextMap.containsKey(r.stringValue()) || pubInfoContextMap.containsKey(latestId)) continue;
×
249
            TemplateContext c = new TemplateContext(ContextType.PUBINFO, r.stringValue(), "pi-statement", targetNamespace);
×
250
            pubInfoContexts.add(c);
×
251
            pubInfoContextMap.put(c.getTemplateId(), c);
×
252
            requiredPubInfoContexts.add(c);
×
253
        }
×
254
        Map<Integer, TemplateContext> piParamIdMap = new HashMap<>();
×
255
        for (String k : pageParams.getNamedKeys()) {
×
256
            if (!k.matches("pitemplate[1-9][0-9]*")) continue;
×
257
            Integer i = Integer.parseInt(k.replaceFirst("^pitemplate([1-9][0-9]*)$", "$1"));
×
258
            String tid = pageParams.get(k).toString();
×
259
            // TODO Allow for automatically using latest template version:
260
            //String piTempalteIdLatest = QueryApiAccess.getLatestVersionId(tid);
261
            TemplateContext c = createPubinfoContext(tid);
×
262
            if (piParamIdMap.containsKey(i)) {
×
263
                // TODO: handle this error better
264
                logger.error("ERROR: pitemplate param identifier assigned multiple times: {}", i);
×
265
            }
266
            piParamIdMap.put(i, c);
×
267
        }
×
268
        if (fillNp != null && !fillOnlyAssertion) {
×
269
            for (IRI piTemplateId : td.getPubinfoTemplateIds(fillNp)) {
×
270
                String piTempalteIdLatest = QueryApiAccess.getLatestVersionId(piTemplateId.stringValue());
×
271
                if (piTempalteIdLatest.equals(supersedesPubinfoTemplateId)) continue;
×
272
                if (!pubInfoContextMap.containsKey(piTempalteIdLatest)) {
×
273
                    // TODO Allow for automatically using latest template version
274
                    createPubinfoContext(piTemplateId.stringValue());
×
275
                }
276
            }
×
277
        }
278
        if (!pageParams.get("values-from-query").isEmpty() && !pageParams.get("values-from-query-mapping").isEmpty()) {
×
279
            String querySpec = pageParams.get("values-from-query").toString();
×
280

281
            String mapping = pageParams.get("values-from-query-mapping").toString();
×
282
            String mapsFrom, mapsTo;
283
            if (mapping.contains(":")) {
×
284
                mapsFrom = mapping.split(":")[0];
×
285
                mapsTo = mapping.split(":")[1];
×
286
            } else {
287
                mapsFrom = mapping;
×
288
                mapsTo = mapping;
×
289
            }
290
            ApiResponse resp = ApiCache.retrieveResponseSync(QueryRef.parseString(querySpec), false);
×
291
            int i = 0;
×
292
            for (ApiResponseEntry e : resp.getData()) {
×
293
                String mapsToSuffix = "";
×
294
                if (i > 0) mapsToSuffix = "__" + i;
×
295
                assertionContext.setParam(mapsTo + mapsToSuffix, e.get(mapsFrom));
×
296
                i++;
×
297
            }
×
298
        }
299
        for (String k : pageParams.getNamedKeys()) {
×
300
            if (k.startsWith("param_")) assertionContext.setParam(k.substring(6), pageParams.get(k).toString());
×
301
            if (k.startsWith("prparam_")) provenanceContext.setParam(k.substring(8), pageParams.get(k).toString());
×
302
            if (k.matches("piparam[1-9][0-9]*_.*")) {
×
303
                Integer i = Integer.parseInt(k.replaceFirst("^piparam([1-9][0-9]*)_.*$", "$1"));
×
304
                if (!piParamIdMap.containsKey(i)) {
×
305
                    // TODO: handle this error better
306
                    logger.error("ERROR: pitemplate param identifier not found: {}", i);
×
307
                    continue;
×
308
                }
309
                String n = k.replaceFirst("^piparam[1-9][0-9]*_(.*)$", "$1");
×
310
                logger.info(n);
×
311
                piParamIdMap.get(i).setParam(n, pageParams.get(k).toString());
×
312
            }
313
        }
×
314

315
        // Init statements only now, in order to pick up parameter values:
316
        assertionContext.initStatements();
×
317
        provenanceContext.initStatements();
×
318
        for (TemplateContext c : pubInfoContexts) {
×
319
            c.initStatements();
×
320
        }
×
321

322
        String latestAssertionId = QueryApiAccess.getLatestVersionId(assertionContext.getTemplateId());
×
323
        if (!assertionContext.getTemplateId().equals(latestAssertionId)) {
×
324
            add(new Label("newversion", "There is a new version of this assertion template:"));
×
325
            PageParameters params = new PageParameters(pageParams);
×
326
            params.set("template", latestAssertionId).remove("formobj");
×
327
            add(new BookmarkablePageLink<Void>("newversionlink", publishPageClass, params));
×
328
            if ("latest".equals(pageParams.get("template-version").toString())) {
×
329
                throw new RestartResponseException(publishPageClass, params);
×
330
            }
331
        } else {
×
332
            add(new Label("newversion", "").setVisible(false));
×
333
            add(new Label("newversionlink", "").setVisible(false));
×
334
        }
335

336
        final Nanopub improveNp;
337
        if (!pageParams.get("improve").isNull()) {
×
338
            improveNp = Utils.getNanopub(pageParams.get("improve").toString());
×
339
        } else {
340
            improveNp = null;
×
341
        }
342

343
        final List<Statement> unusedStatementList = new ArrayList<>();
×
344
        final List<Statement> unusedPrStatementList = new ArrayList<>();
×
345
        final List<Statement> unusedPiStatementList = new ArrayList<>();
×
346
        if (fillNp != null) {
×
347
            ValueFiller filler = new ValueFiller(fillNp, ContextType.ASSERTION, true, fillMode);
×
348
            filler.fill(assertionContext);
×
349
            unusedStatementList.addAll(filler.getUnusedStatements());
×
350

351
            if (!fillOnlyAssertion) {
×
352
                ValueFiller prFiller = new ValueFiller(fillNp, ContextType.PROVENANCE, true);
×
353
                prFiller.fill(provenanceContext);
×
354
                unusedPrStatementList.addAll(prFiller.getUnusedStatements());
×
355

356
                ValueFiller piFiller = new ValueFiller(fillNp, ContextType.PUBINFO, true);
×
357
                if (!assertionContext.getTemplate().getTargetNanopubTypes().isEmpty()) {
×
358
                    for (Statement st : new ArrayList<>(piFiller.getUnusedStatements())) {
×
359
                        if (st.getSubject().stringValue().equals(LocalUri.of("nanopub").stringValue()) && st.getPredicate().equals(NPX.HAS_NANOPUB_TYPE)) {
×
360
                            if (assertionContext.getTemplate().getTargetNanopubTypes().contains(st.getObject())) {
×
361
                                piFiller.removeUnusedStatement(st);
×
362
                            }
363
                        }
364
                    }
×
365
                }
366
                for (TemplateContext c : pubInfoContexts) {
×
367
                    piFiller.fill(c);
×
368
                }
×
369
                piFiller.removeUnusedStatements(NanodashSession.get().getUserIri(), FOAF.NAME, null);
×
370
                if (piFiller.hasUnusedStatements()) {
×
371
                    final String handcodedStatementsTemplateId = "https://w3id.org/np/RAMEgudZsQ1bh1fZhfYnkthqH6YSXpghSE_DEN1I-6eAI";
×
372
                    if (!pubInfoContextMap.containsKey(handcodedStatementsTemplateId)) {
×
373
                        TemplateContext c = createPubinfoContext(handcodedStatementsTemplateId);
×
374
                        c.initStatements();
×
375
                        piFiller.fill(c);
×
376
                    }
377
                }
378
                unusedPiStatementList.addAll(piFiller.getUnusedStatements());
×
379
                // TODO: Also use pubinfo templates stated in nanopub to be filled in?
380
//                                Set<IRI> pubinfoTemplateIds = Template.getPubinfoTemplateIds(fillNp);
381
//                                if (!pubinfoTemplateIds.isEmpty()) {
382
//                                        ValueFiller piFiller = new ValueFiller(fillNp, ContextType.PUBINFO);
383
//                                        for (IRI pubinfoTemplateId : pubinfoTemplateIds) {
384
//                                                // TODO: Make smart choice on the ordering in trying to fill in all pubinfo elements
385
//                                                piFiller.fill(pubInfoContextMap.get(pubinfoTemplateId.stringValue()));
386
//                                        }
387
//                                        warningMessage += (piFiller.getWarningMessage() == null ? "" : "Publication info: " + piFiller.getWarningMessage() + " ");
388
//                                }
389
            }
390
        } else if (improveNp != null) {
×
391
            ValueFiller filler = new ValueFiller(improveNp, ContextType.ASSERTION, true);
×
392
            filler.fill(assertionContext);
×
393
            unusedStatementList.addAll(filler.getUnusedStatements());
×
394
        }
395
        if (!unusedStatementList.isEmpty()) {
×
396
            add(new Label("warnings", "Some content from the existing nanopublication could not be filled in:"));
×
397
        } else {
398
            add(new Label("warnings", "").setVisible(false));
×
399
        }
400
        add(new DataView<Statement>("unused-statements", new ListDataProvider<Statement>(unusedStatementList)) {
×
401

402
            @Override
403
            protected void populateItem(Item<Statement> item) {
404
                item.add(new TripleItem("unused-statement", item.getModelObject(), (fillNp != null ? fillNp : improveNp), null));
×
405
            }
×
406

407
        });
408
        add(new DataView<Statement>("unused-prstatements", new ListDataProvider<Statement>(unusedPrStatementList)) {
×
409

410
            @Override
411
            protected void populateItem(Item<Statement> item) {
412
                item.add(new TripleItem("unused-prstatement", item.getModelObject(), (fillNp != null ? fillNp : improveNp), null));
×
413
            }
×
414

415
        });
416
        add(new DataView<Statement>("unused-pistatements", new ListDataProvider<Statement>(unusedPiStatementList)) {
×
417

418
            @Override
419
            protected void populateItem(Item<Statement> item) {
420
                item.add(new TripleItem("unused-pistatement", item.getModelObject(), (fillNp != null ? fillNp : improveNp), null));
×
421
            }
×
422

423
        });
424

425
        // Finalize statements, which picks up parameter values in repetitions:
426
        assertionContext.finalizeStatements();
×
427
        provenanceContext.finalizeStatements();
×
428
        for (TemplateContext c : pubInfoContexts) {
×
429
            c.finalizeStatements();
×
430
        }
×
431

432
        final CheckBox consentCheck = new CheckBox("consentcheck", new Model<>(false));
×
433
        consentCheck.setRequired(true);
×
434
        consentCheck.add(new InvalidityHighlighting());
×
435
        consentCheck.add(new IValidator<Boolean>() {
×
436

437
            @Override
438
            public void validate(IValidatable<Boolean> validatable) {
439
                if (!Boolean.TRUE.equals(validatable.getValue())) {
×
440
                    validatable.error(new ValidationError("You need to check the checkbox that you understand the consequences."));
×
441
                }
442
            }
×
443

444
        });
445

446
        form = new Form<Void>("form") {
×
447

448
            @Override
449
            protected void onConfigure() {
450
                super.onConfigure();
×
451
                form.getFeedbackMessages().clear();
×
452
//                                formComponents.clear();
453
            }
×
454

455
            protected void onSubmit() {
456
                logger.info("Publish form submitted");
×
457
                Nanopub signedNp = null;
×
458
                try {
459
                    Nanopub np = createNanopub();
×
460
                    logger.info("Nanopublication created: {}", np.getUri());
×
461
                    TransformContext tc = new TransformContext(SignatureAlgorithm.RSA, NanodashSession.get().getKeyPair(), NanodashSession.get().getUserIri(), false, false, false);
×
462
                    signedNp = SignNanopub.signAndTransform(np, tc);
×
463
                    logger.info("Nanopublication signed: {}", signedNp.getUri());
×
464
                    String npUrl = PublishNanopub.publish(signedNp);
×
465
                    logger.info("Nanopublication published: {}", npUrl);
×
466
                } catch (Exception ex) {
×
467
                    signedNp = null;
×
468
                    logger.error("Nanopublication publishing failed: {}", ex);
×
469
                    String message = ex.getClass().getName();
×
470
                    if (ex.getMessage() != null) {
×
471
                        message = ex.getMessage();
×
472
                    }
473
                    feedbackPanel.error(message);
×
474
                }
×
475
                if (!pageParams.get("refresh-upon-publish").isEmpty()) {
×
476
                    String toRefresh = pageParams.get("refresh-upon-publish").toString();
×
477
                    if (toRefresh.equals("spaces")) {
×
478
                        Space.forceRootRefresh(3 * 1000);
×
479
                    } else if (toRefresh.equals("maintainedResources")) {
×
480
                        MaintainedResource.forceRootRefresh(3 * 1000);
×
481
                    } else if (ResourceWithProfile.isResourceWithProfile(toRefresh)) {
×
482
                        ResourceWithProfile.forceRefresh(toRefresh, 3 * 1000);
×
483
                    } else {
484
                        QueryRef queryRef = QueryRef.parseString(toRefresh);
×
485
                        // Make sure the next cache update happens not before 3 seconds from now, at which point the
486
                        // published nanopub should show up in the Nanopub Query instances:
487
                        ApiCache.clearCache(queryRef, 3 * 1000);
×
488
                    }
489
                }
490
                if (signedNp != null) {
×
491
                    String contextId = pageParams.get("context").toString("");
×
492
                    String partId = pageParams.get("part").toString("");
×
493
                    if (!contextId.isEmpty()) {
×
494
                        PageParameters redirectParams = new PageParameters().set("just-published", signedNp.getUri().stringValue());
×
495
                        if (!partId.isEmpty()) {
×
496
                            // User was on a part page (e.g. paper collection); redirect back to the part page
497
                            redirectParams.set("id", partId).set("context", contextId);
×
498
                            throw new RestartResponseException(ResourcePartPage.class, redirectParams);
×
499
                        }
500
                        redirectParams.set("id", contextId);
×
501
                        if (Space.get(contextId) != null) {
×
502
                            throw new RestartResponseException(SpacePage.class, redirectParams);
×
503
                        }
504
                        if (MaintainedResource.get(contextId) != null) {
×
505
                            throw new RestartResponseException(MaintainedResourcePage.class, redirectParams);
×
506
                        }
507
                        if (User.isUser(contextId)) {
×
508
                            throw new RestartResponseException(UserPage.class, redirectParams);
×
509
                        }
510
                    }
511
                    throw new RestartResponseException(getConfirmPage(signedNp, pageParams));
×
512
                } else {
513
                    logger.error("Nanopublication publishing failed");
×
514
                }
515
            }
×
516

517
            @Override
518
            protected void onValidate() {
519
                super.onValidate();
×
520
                for (Component fc : assertionContext.getComponents()) {
×
521
                    processFeedback(fc);
×
522
                }
×
523
                for (Component fc : provenanceContext.getComponents()) {
×
524
                    processFeedback(fc);
×
525
                }
×
526
                for (TemplateContext c : pubInfoContexts) {
×
527
                    for (Component fc : c.getComponents()) {
×
528
                        processFeedback(fc);
×
529
                    }
×
530
                }
×
531
            }
×
532

533
            private void processFeedback(Component c) {
534
                if (c instanceof FormComponent) {
×
535
                    ((FormComponent<?>) c).processInput();
×
536
                }
537
                for (FeedbackMessage fm : c.getFeedbackMessages()) {
×
538
                    form.getFeedbackMessages().add(fm);
×
539
                }
×
540
            }
×
541

542
        };
543
        form.setOutputMarkupId(true);
×
544

545
        //form.add(new Label("nanopub-namespace", targetNamespaceLabel));
546

547
        form.add(new BookmarkablePageLink<Void>("templatelink", ExplorePage.class, new PageParameters().set("id", assertionContext.getTemplate().getId())));
×
548
        form.add(new Label("templatename", assertionContext.getTemplate().getLabel()));
×
549
        String description = assertionContext.getTemplate().getLabel();
×
550
        if (description == null) description = "";
×
551
        form.add(new Label("templatedesc", assertionContext.getTemplate().getDescription()).setEscapeModelStrings(false));
×
552

553
        form.add(new ListView<StatementItem>("statements", assertionContext.getStatementItems()) {
×
554

555
            protected void populateItem(ListItem<StatementItem> item) {
556
                item.add(item.getModelObject());
×
557
            }
×
558

559
        });
560

561
        final Map<String, Boolean> handledProvTemplates = new HashMap<>();
×
562
        final String defaultProvTemplateId;
563
        if (assertionContext.getTemplate().getDefaultProvenance() != null) {
×
564
            defaultProvTemplateId = assertionContext.getTemplate().getDefaultProvenance().stringValue();
×
565
            handledProvTemplates.put(defaultProvTemplateId, true);
×
566
        } else {
567
            defaultProvTemplateId = null;
×
568
        }
569
        final List<String> recommendedProvTemplateOptionIds = new ArrayList<>();
×
570
        final List<String> provTemplateOptionIds = new ArrayList<>();
×
571
        if (pageParams.get("prtemplate-options").isNull()) {
×
572
            // TODO Make this dynamic and consider updated templates:
573
            recommendedProvTemplateOptionIds.add("https://w3id.org/np/RA7lSq6MuK_TIC6JMSHvLtee3lpLoZDOqLJCLXevnrPoU");
×
574
            recommendedProvTemplateOptionIds.add("http://purl.org/np/RAcTpoh5Ra0ssqmcpOgWdaZ_YiPE6demO6cpw-2RvSNs8");
×
575
            recommendedProvTemplateOptionIds.add("http://purl.org/np/RA4LGtuOqTIMqVAkjnfBXk1YDcAPNadP5CGiaJiBkdHCQ");
×
576
            recommendedProvTemplateOptionIds.add("http://purl.org/np/RAl_-VTw9Re_uRF8r8y0rjlfnu7FlhTa8xg_8xkcweqiE");
×
577
            recommendedProvTemplateOptionIds.add("https://w3id.org/np/RASORV2mMEVpS4lWh2bwUTEcV-RWjbD9RPbN7J0PIeYAU");
×
578
            recommendedProvTemplateOptionIds.add("http://purl.org/np/RAjkBbM5yQm7hKH1l_Jk3HAUqWi3Bd57TPmAOZCsZmi_M");
×
579
            recommendedProvTemplateOptionIds.add("http://purl.org/np/RAGXx_k9eQMnXaCbsXMsJbGClwZtQEGNg0GVJu6amdAVw");
×
580
            recommendedProvTemplateOptionIds.add("http://purl.org/np/RA1fnITI3Pu1UQ0CHghNpys3JwQrM32LBnjmDLoayp9-4");
×
581
            recommendedProvTemplateOptionIds.add("http://purl.org/np/RAJgbsGeGdTG-zq_gU0TLw4s3raMgoRk-mPlc2DSLXvE0");
×
582
            recommendedProvTemplateOptionIds.add("http://purl.org/np/RA6SXfhUY-xeblZU8HhPddw6tsu-C5NXevG6C_zv4bMxU");
×
583
            for (String s : recommendedProvTemplateOptionIds) {
×
584
                handledProvTemplates.put(s, true);
×
585
            }
×
586

587
            for (ApiResponseEntry t : td.getProvenanceTemplates()) {
×
588
                String tid = t.get("np");
×
589
                if (handledProvTemplates.containsKey(tid)) continue;
×
590
                provTemplateOptionIds.add(tid);
×
591
                handledProvTemplates.put(tid, true);
×
592
            }
×
593
        } else {
594
            for (String s : pageParams.get("prtemplate-options").toString().split(" ")) {
×
595
                if (handledProvTemplates.containsKey(s)) continue;
×
596
                recommendedProvTemplateOptionIds.add(s);
×
597
                handledProvTemplates.put(s, true);
×
598
            }
599
        }
600

601
        ChoiceProvider<String> prTemplateChoiceProvider = new ChoiceProvider<String>() {
×
602

603
            @Override
604
            public String getDisplayValue(String object) {
605
                if (object == null || object.isEmpty()) return "";
×
606
                Template t = td.getTemplate(object);
×
607
                if (t != null) return t.getLabel();
×
608
                return object;
×
609
            }
610

611
            @Override
612
            public String getIdValue(String object) {
613
                return object;
×
614
            }
615

616
            // Getting strange errors with Tomcat if this method is not overridden:
617
            @Override
618
            public void detach() {
619
            }
×
620

621
            @Override
622
            public void query(String term, int page, Response<String> response) {
623
                if (term == null) term = "";
×
624
                term = term.toLowerCase();
×
625
                if (pageParams.get("prtemplate").toString() != null) {
×
626
                    // Using this work-around with "——" because 'optgroup' is not available through Wicket's Select2 classes
627
                    response.add("—— default for this link ——");
×
628
                    response.add(prTemplateId);
×
629
                }
630
                if (defaultProvTemplateId != null) {
×
631
                    response.add("—— default for this template ——");
×
632
                    response.add(defaultProvTemplateId);
×
633
                }
634
                if (!recommendedProvTemplateOptionIds.isEmpty()) {
×
635
                    if (pageParams.get("prtemplate-options").isNull()) {
×
636
                        response.add("—— recommended ——");
×
637
                    }
638
                    for (String s : recommendedProvTemplateOptionIds) {
×
639
                        if (s.toLowerCase().contains(term) || getDisplayValue(s).toLowerCase().contains(term)) {
×
640
                            response.add(s);
×
641
                        }
642
                    }
×
643
                }
644
                if (!provTemplateOptionIds.isEmpty()) {
×
645
                    response.add("—— others ——");
×
646
                    for (String s : provTemplateOptionIds) {
×
647
                        if (s.toLowerCase().contains(term) || getDisplayValue(s).toLowerCase().contains(term)) {
×
648
                            response.add(s);
×
649
                        }
650
                    }
×
651
                }
652
            }
×
653

654
            @Override
655
            public Collection<String> toChoices(Collection<String> ids) {
656
                return ids;
×
657
            }
658

659
        };
660
        final IModel<String> prTemplateModel = Model.of(provenanceContext.getTemplate().getId());
×
661
        Select2Choice<String> prTemplateChoice = new Select2Choice<String>("prtemplate", prTemplateModel, prTemplateChoiceProvider);
×
662
        prTemplateChoice.setRequired(true);
×
663
        prTemplateChoice.getSettings().setCloseOnSelect(true);
×
664
        prTemplateChoice.add(new AjaxFormComponentUpdatingBehavior("change") {
×
665

666
            @Override
667
            protected void onUpdate(AjaxRequestTarget target) {
668
                String o = prTemplateModel.getObject();
×
669
                if (o.startsWith("——")) {
×
670
                    o = provenanceContext.getTemplate().getId();
×
671
                    prTemplateModel.setObject(o);
×
672
                }
673
                provenanceContext = new TemplateContext(ContextType.PROVENANCE, prTemplateModel.getObject(), "pr-statement", targetNamespace);
×
674
                provenanceContext.initStatements();
×
675
                refreshProvenance(target);
×
676
                provenanceContext.finalizeStatements();
×
677
            }
×
678

679
        });
680
        form.add(prTemplateChoice);
×
681
        refreshProvenance(null);
×
682

683
        final Map<String, Boolean> handledPiTemplates = new HashMap<>();
×
684
        final List<String> recommendedPiTemplateOptionIds = new ArrayList<>();
×
685
        final List<String> piTemplateOptionIds = new ArrayList<>();
×
686
        // TODO Make this dynamic and consider updated templates:
687
        recommendedPiTemplateOptionIds.add("http://purl.org/np/RAXflINqt3smqxV5Aq7E9lzje4uLdkKIOefa6Bp8oJ8CY");
×
688
        recommendedPiTemplateOptionIds.add("https://w3id.org/np/RARW4MsFkHuwjycNElvEVtuMjpf4yWDL10-0C5l2MqqRQ");
×
689
        recommendedPiTemplateOptionIds.add("https://w3id.org/np/RA16U9Wo30ObhrK1NzH7EsmVRiRtvEuEA_Dfc-u8WkUCA");
×
690
        recommendedPiTemplateOptionIds.add("http://purl.org/np/RAdyqI6k07V5nAS82C6hvIDtNWk179EIV4DV-sLbOFKg4");
×
691
        recommendedPiTemplateOptionIds.add("https://w3id.org/np/RAjvEpLZUE7rMoa8q6mWSsN6utJDp-5FmgO47YGsbgw3w");
×
692
        recommendedPiTemplateOptionIds.add("http://purl.org/np/RAxuGRKID6yNg63V5Mf0ot2NjncOnodh-mkN3qT_1txGI");
×
693
        for (TemplateContext c : pubInfoContexts) {
×
694
            String s = c.getTemplate().getId();
×
695
            handledPiTemplates.put(s, true);
×
696
        }
×
697
        for (String s : recommendedPiTemplateOptionIds) {
×
698
            handledPiTemplates.put(s, true);
×
699
        }
×
700

701
        for (ApiResponseEntry entry : td.getPubInfoTemplates()) {
×
702
            String tid = entry.get("np");
×
703
            if (handledPiTemplates.containsKey(tid)) continue;
×
704
            piTemplateOptionIds.add(tid);
×
705
            handledPiTemplates.put(tid, true);
×
706
        }
×
707

708
        ChoiceProvider<String> piTemplateChoiceProvider = new ChoiceProvider<String>() {
×
709

710
            @Override
711
            public String getDisplayValue(String object) {
712
                if (object == null || object.isEmpty()) return "";
×
713
                Template t = td.getTemplate(object);
×
714
                if (t != null) return t.getLabel();
×
715
                return object;
×
716
            }
717

718
            @Override
719
            public String getIdValue(String object) {
720
                return object;
×
721
            }
722

723
            // Getting strange errors with Tomcat if this method is not overridden:
724
            @Override
725
            public void detach() {
726
            }
×
727

728
            @Override
729
            public void query(String term, int page, Response<String> response) {
730
                if (term == null) term = "";
×
731
                term = term.toLowerCase();
×
732
                if (!recommendedPiTemplateOptionIds.isEmpty()) {
×
733
                    response.add("—— recommended ——");
×
734
                    for (String s : recommendedPiTemplateOptionIds) {
×
735
                        boolean isAlreadyUsed = false;
×
736
                        for (TemplateContext c : pubInfoContexts) {
×
737
                            // TODO: make this more efficient/nicer
738
                            if (c.getTemplate().getId().equals(s)) {
×
739
                                isAlreadyUsed = true;
×
740
                                break;
×
741
                            }
742
                        }
×
743
                        if (isAlreadyUsed) continue;
×
744
                        if (s.toLowerCase().contains(term) || getDisplayValue(s).toLowerCase().contains(term)) {
×
745
                            response.add(s);
×
746
                        }
747
                    }
×
748
                }
749
                if (!piTemplateOptionIds.isEmpty()) {
×
750
                    response.add("—— others ——");
×
751
                    for (String s : piTemplateOptionIds) {
×
752
                        boolean isAlreadyUsed = false;
×
753
                        for (TemplateContext c : pubInfoContexts) {
×
754
                            // TODO: make this more efficient/nicer
755
                            if (c.getTemplate().getId().equals(s)) {
×
756
                                isAlreadyUsed = true;
×
757
                                break;
×
758
                            }
759
                        }
×
760
                        if (isAlreadyUsed) continue;
×
761
                        if (s.toLowerCase().contains(term) || getDisplayValue(s).toLowerCase().contains(term)) {
×
762
                            response.add(s);
×
763
                        }
764
                    }
×
765
                }
766
            }
×
767

768
            @Override
769
            public Collection<String> toChoices(Collection<String> ids) {
770
                return ids;
×
771
            }
772

773
        };
774
        final IModel<String> newPiTemplateModel = Model.of();
×
775
        Select2Choice<String> piTemplateChoice = new Select2Choice<String>("pitemplate", newPiTemplateModel, piTemplateChoiceProvider);
×
776
        piTemplateChoice.getSettings().setCloseOnSelect(true);
×
777
        piTemplateChoice.getSettings().setPlaceholder("add element...");
×
778
        piTemplateChoice.add(new AjaxFormComponentUpdatingBehavior("change") {
×
779

780
            @Override
781
            protected void onUpdate(AjaxRequestTarget target) {
782
                if (newPiTemplateModel.getObject().startsWith("——")) {
×
783
                    newPiTemplateModel.setObject(null);
×
784
                    refreshPubInfo(target);
×
785
                    return;
×
786
                }
787
                String id = newPiTemplateModel.getObject();
×
788
                TemplateContext c = new TemplateContext(ContextType.PUBINFO, id, "pi-statement", targetNamespace);
×
789
                c.initStatements();
×
790
                pubInfoContexts.add(c);
×
791
                newPiTemplateModel.setObject(null);
×
792
                refreshPubInfo(target);
×
793
                c.finalizeStatements();
×
794
            }
×
795

796
        });
797
        form.add(piTemplateChoice);
×
798
        refreshPubInfo(null);
×
799

800
        form.add(consentCheck);
×
801

802
        form.add(new Button("preview-button") {
×
803
            @Override
804
            public void onSubmit() {
805
                try {
806
                    Nanopub np = createNanopub();
×
807
                    TransformContext tc = new TransformContext(SignatureAlgorithm.RSA, NanodashSession.get().getKeyPair(), NanodashSession.get().getUserIri(), false, false, false);
×
808
                    Nanopub signedNp = SignNanopub.signAndTransform(np, tc);
×
809
                    String previewId = signedNp.getUri().stringValue();
×
810
                    NanodashSession.get().setPreviewNanopub(previewId,
×
811
                            new NanodashSession.PreviewNanopub(signedNp, pageParams, confirmPageClass));
812
                    throw new RestartResponseException(PreviewPage.class, new PageParameters().set("id", previewId));
×
813
                } catch (RestartResponseException ex) {
×
814
                    throw ex;
×
815
                } catch (Exception ex) {
×
816
                    logger.error("Preview failed: {}", ex);
×
817
                    String message = ex.getClass().getName();
×
818
                    if (ex.getMessage() != null) {
×
819
                        message = ex.getMessage();
×
820
                    }
821
                    feedbackPanel.error(message);
×
822
                }
823
            }
×
824
        });
825

826
        add(form);
×
827

828
        feedbackPanel = new FeedbackPanel("feedback");
×
829
        feedbackPanel.setOutputMarkupId(true);
×
830
        add(feedbackPanel);
×
831
    }
×
832

833
    private void refreshProvenance(AjaxRequestTarget target) {
834
        if (target != null) {
×
835
            form.remove("prtemplatelink");
×
836
            form.remove("pr-statements");
×
837
            target.add(form);
×
838
            target.appendJavaScript("updateElements();");
×
839
        }
840
        form.add(new BookmarkablePageLink<Void>("prtemplatelink", ExplorePage.class, new PageParameters().set("id", provenanceContext.getTemplate().getId())));
×
841
        ListView<StatementItem> list = new ListView<StatementItem>("pr-statements", provenanceContext.getStatementItems()) {
×
842

843
            protected void populateItem(ListItem<StatementItem> item) {
844
                item.add(item.getModelObject());
×
845
            }
×
846

847
        };
848
        list.setOutputMarkupId(true);
×
849
        form.add(list);
×
850
    }
×
851

852
    private void refreshPubInfo(AjaxRequestTarget target) {
853
        ListView<TemplateContext> list = new ListView<TemplateContext>("pis", pubInfoContexts) {
×
854

855
            protected void populateItem(ListItem<TemplateContext> item) {
856
                final TemplateContext pic = item.getModelObject();
×
857
                item.add(new Label("pitemplatename", pic.getTemplate().getLabel()));
×
858
                item.add(new BookmarkablePageLink<Void>("pitemplatelink", ExplorePage.class, new PageParameters().set("id", pic.getTemplate().getId())));
×
859
                Label remove = new Label("piremove", "×");
×
860
                item.add(remove);
×
861
                remove.add(new AjaxEventBehavior("click") {
×
862

863
                    @Override
864
                    protected void onEvent(AjaxRequestTarget target) {
865
                        pubInfoContexts.remove(pic);
×
866
                        target.add(PublishForm.this);
×
867
                        target.appendJavaScript("updateElements();");
×
868
                    }
×
869

870
                });
871
                if (requiredPubInfoContexts.contains(pic)) remove.setVisible(false);
×
872
                item.add(new ListView<StatementItem>("pi-statements", pic.getStatementItems()) {
×
873

874
                    protected void populateItem(ListItem<StatementItem> item) {
875
                        item.add(item.getModelObject());
×
876
                    }
×
877

878
                });
879
            }
×
880

881
        };
882
        list.setOutputMarkupId(true);
×
883
        if (target == null) {
×
884
            form.add(list);
×
885
        } else {
886
            form.remove("pis");
×
887
            form.add(list);
×
888
            target.add(form);
×
889
            target.appendJavaScript("updateElements();");
×
890
        }
891
    }
×
892

893
    private TemplateContext createPubinfoContext(String piTemplateId) {
894
        TemplateContext c;
895
        if (pubInfoContextMap.containsKey(piTemplateId)) {
×
896
            c = pubInfoContextMap.get(piTemplateId);
×
897
        } else {
898
            c = new TemplateContext(ContextType.PUBINFO, piTemplateId, "pi-statement", targetNamespace);
×
899
            pubInfoContextMap.put(piTemplateId, c);
×
900
            pubInfoContexts.add(c);
×
901
        }
902
        return c;
×
903
    }
904

905
    private synchronized Nanopub createNanopub() throws MalformedNanopubException, NanopubAlreadyFinalizedException {
906
        assertionContext.getIntroducedIris().clear();
×
907
        NanopubCreator npCreator = new NanopubCreator(targetNamespace);
×
908
        npCreator.setAssertionUri(vf.createIRI(targetNamespace + "assertion"));
×
909
        assertionContext.propagateStatements(npCreator);
×
910
        provenanceContext.propagateStatements(npCreator);
×
911
        for (TemplateContext c : pubInfoContexts) {
×
912
            c.propagateStatements(npCreator);
×
913
        }
×
914
        for (IRI introducedIri : assertionContext.getIntroducedIris()) {
×
915
            npCreator.addPubinfoStatement(NPX.INTRODUCES, introducedIri);
×
916
        }
×
917
        for (IRI embeddedIri : assertionContext.getEmbeddedIris()) {
×
918
            npCreator.addPubinfoStatement(NPX.EMBEDS, embeddedIri);
×
919
        }
×
920
        npCreator.addNamespace("this", targetNamespace);
×
921
        npCreator.addNamespace("sub", targetNamespace + "/");
×
922
        npCreator.addTimestampNow();
×
923
        IRI templateUri = assertionContext.getTemplate().getNanopub().getUri();
×
924
        npCreator.addPubinfoStatement(NTEMPLATE.WAS_CREATED_FROM_TEMPLATE, templateUri);
×
925
        IRI prTemplateUri = provenanceContext.getTemplate().getNanopub().getUri();
×
926
        npCreator.addPubinfoStatement(NTEMPLATE.WAS_CREATED_FROM_PROVENANCE_TEMPLATE, prTemplateUri);
×
927
        for (TemplateContext c : pubInfoContexts) {
×
928
            IRI piTemplateUri = c.getTemplate().getNanopub().getUri();
×
929
            npCreator.addPubinfoStatement(NTEMPLATE.WAS_CREATED_FROM_PUBINFO_TEMPLATE, piTemplateUri);
×
930
        }
×
931
        String nanopubLabel = getNanopubLabel(npCreator);
×
932
        if (nanopubLabel != null) {
×
933
            npCreator.addPubinfoStatement(RDFS.LABEL, vf.createLiteral(nanopubLabel));
×
934
        }
935
        for (IRI type : assertionContext.getTemplate().getTargetNanopubTypes()) {
×
936
            npCreator.addPubinfoStatement(NPX.HAS_NANOPUB_TYPE, type);
×
937
        }
×
938
        IRI userIri = NanodashSession.get().getUserIri();
×
939
        if (User.getName(userIri) != null) {
×
940
            npCreator.addPubinfoStatement(userIri, FOAF.NAME, vf.createLiteral(User.getName(userIri)));
×
941
            npCreator.addNamespace("foaf", FOAF.NAMESPACE);
×
942
        }
943
        String websiteUrl = NanodashPreferences.get().getWebsiteUrl();
×
944
        if (websiteUrl != null) {
×
945
            npCreator.addPubinfoStatement(NPX.WAS_CREATED_AT, vf.createIRI(websiteUrl));
×
946
        }
947
        return npCreator.finalizeNanopub();
×
948
    }
949

950
    private String getNanopubLabel(NanopubCreator npCreator) {
951
        if (assertionContext.getTemplate().getNanopubLabelPattern() == null) return null;
×
952

953
        Map<IRI, String> labelMap = new HashMap<>();
×
954
        for (Statement st : npCreator.getCurrentPubinfoStatements()) {
×
955
            if (st.getPredicate().equals(RDFS.LABEL) && st.getObject() instanceof Literal objL) {
×
956
                labelMap.put((IRI) st.getSubject(), objL.stringValue());
×
957
            }
958
        }
×
959

960
        String nanopubLabel = assertionContext.getTemplate().getNanopubLabelPattern();
×
961
        while (nanopubLabel.matches(".*\\$\\{[_a-zA-Z0-9-]+\\}.*")) {
×
962
            String placeholderPostfix = nanopubLabel.replaceFirst("^.*\\$\\{([_a-zA-Z0-9-]+)\\}.*$", "$1");
×
963
            IRI placeholderIriHash = vf.createIRI(assertionContext.getTemplateId() + "#" + placeholderPostfix);
×
964
            IRI placeholderIriSlash = vf.createIRI(assertionContext.getTemplateId() + "/" + placeholderPostfix);
×
965
            IRI placeholderIri = null;
×
966
            String placeholderValue = "";
×
967
            if (assertionContext.getComponentModels().get(placeholderIriSlash) != null) {
×
968
                placeholderIri = placeholderIriSlash;
×
969
            } else {
970
                placeholderIri = placeholderIriHash;
×
971
            }
972
            IModel<String> m = (IModel<String>) assertionContext.getComponentModels().get(placeholderIri);
×
973
            if (m != null) placeholderValue = m.orElse("").getObject();
×
974
            if (placeholderValue == null) placeholderValue = "";
×
975
            String placeholderLabel = placeholderValue;
×
976
            if (assertionContext.getTemplate().isUriPlaceholder(placeholderIri)) {
×
977
                try {
978
                    // TODO Fix this. It doesn't work for placeholders with auto-encode placeholders, etc.
979
                    //      Not sure we need labels for these, but this code should be improved anyway.
980
                    String prefix = assertionContext.getTemplate().getPrefix(placeholderIri);
×
981
                    if (prefix != null) placeholderValue = prefix + placeholderValue;
×
982
                    IRI placeholderValueIri = vf.createIRI(placeholderValue);
×
983
                    String l = assertionContext.getTemplate().getLabel(placeholderValueIri);
×
984
                    if (labelMap.containsKey(placeholderValueIri)) {
×
985
                        l = labelMap.get(placeholderValueIri);
×
986
                    }
987
                    if (l == null) l = GuidedChoiceItem.getLabel(placeholderValue);
×
988
                    if (assertionContext.getTemplate().isAgentPlaceholder(placeholderIri) && !placeholderValue.isEmpty()) {
×
989
                        l = User.getName(vf.createIRI(placeholderValue));
×
990
                    }
991
                    if (l != null && !l.isEmpty()) {
×
992
                        placeholderLabel = l.replaceFirst(" - .*$", "");
×
993
                    } else {
994
                        placeholderLabel = Utils.getShortNameFromURI(placeholderValueIri);
×
995
                    }
996
                } catch (Exception ex) {
×
997
                    logger.error("Nanopub label placeholder IRI error: {}", ex.getMessage());
×
998
                }
×
999
            }
1000
            placeholderLabel = placeholderLabel.replaceAll("\\s+", " ");
×
1001
            if (placeholderLabel.length() > 100) placeholderLabel = placeholderLabel.substring(0, 97) + "...";
×
1002
            nanopubLabel = Strings.CS.replace(nanopubLabel, "${" + placeholderPostfix + "}", placeholderLabel);
×
1003
        }
×
1004
        return nanopubLabel;
×
1005
    }
1006

1007
    private NanodashPage getConfirmPage(Nanopub signedNp, PageParameters pageParams) {
1008
        try {
1009
            return (NanodashPage) confirmPageClass.getConstructor(Nanopub.class, PageParameters.class).newInstance(signedNp, pageParams);
×
1010
        } catch (InstantiationException | IllegalAccessException | IllegalArgumentException |
×
1011
                 InvocationTargetException | NoSuchMethodException | SecurityException ex) {
1012
            logger.error("Could not create instance of confirmation page: {}", ex.getMessage());
×
1013
        }
1014
        return null;
×
1015
    }
1016

1017
    /**
1018
     * Returns a hint whether the form is stateless or not.
1019
     *
1020
     * @return false if the form is stateful, true if it is stateless.
1021
     */
1022
    // This is supposed to solve the problem that sometimes (but only sometimes) form content is reset
1023
    // if the user browses other pages in parallel:
1024
    protected boolean getStatelessHint() {
1025
        return false;
×
1026
    }
1027

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