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

knowledgepixels / nanodash / 17654691002

11 Sep 2025 07:07PM UTC coverage: 13.751% (-0.04%) from 13.794%
17654691002

push

github

tkuhn
feat: Enable pinned templates for Spaces

432 of 3964 branches covered (10.9%)

Branch coverage included in aggregate %.

1105 of 7213 relevant lines covered (15.32%)

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/Space.java
1
package com.knowledgepixels.nanodash;
2

3
import static com.knowledgepixels.nanodash.Utils.vf;
4

5
import java.io.Serializable;
6
import java.util.ArrayList;
7
import java.util.HashSet;
8
import java.util.List;
9
import java.util.Set;
10
import java.util.concurrent.ConcurrentHashMap;
11
import java.util.concurrent.ConcurrentMap;
12

13
import org.eclipse.rdf4j.model.IRI;
14
import org.eclipse.rdf4j.model.Literal;
15
import org.eclipse.rdf4j.model.Statement;
16
import org.eclipse.rdf4j.model.vocabulary.DCTERMS;
17
import org.nanopub.Nanopub;
18
import org.nanopub.extra.services.ApiResponse;
19
import org.nanopub.extra.services.ApiResponseEntry;
20
import org.nanopub.vocabulary.NTEMPLATE;
21

22
import com.knowledgepixels.nanodash.template.Template;
23
import com.knowledgepixels.nanodash.template.TemplateData;
24

25
/**
26
 * Class representing a "Space", which can be any kind of collaborative unit, like a project, group, or event.
27
 */
28
public class Space implements Serializable {
29

30
    /**
31
     * The predicate for the owner of the space.
32
     */
33
    public static final IRI HAS_OWNER = vf.createIRI("https://w3id.org/kpxl/gen/terms/hasOwner");
×
34

35
    /**
36
     * The predicate for pinned templates in the space.
37
     */
38
    public static final IRI HAS_PINNED_TEMPLATE = vf.createIRI("https://w3id.org/kpxl/gen/terms/hasPinnedTemplate");
×
39

40
    /**
41
     * The predicate for pinned queries in the space.
42
     */
43
    public static final IRI HAS_PINNED_QUERY = vf.createIRI("https://w3id.org/kpxl/gen/terms/hasPinnedQuery");
×
44

45
    private static List<Space> spaceList = null;
×
46
    private static ConcurrentMap<String,Space> spacesByCoreInfo = new ConcurrentHashMap<>();
×
47
    private static ConcurrentMap<String,Space> spacesById = new ConcurrentHashMap<>();
×
48

49
    public static synchronized void refresh(ApiResponse resp) {
50
        spaceList = new ArrayList<>();
×
51
        ConcurrentMap<String,Space> prevSpacesByCoreInfoPrev = spacesByCoreInfo;
×
52
        spacesByCoreInfo = new ConcurrentHashMap<>();
×
53
        spacesById.clear();
×
54
        for (ApiResponseEntry entry : resp.getData()) {
×
55
            Space space = new Space(entry);
×
56
            Space prevSpace = prevSpacesByCoreInfoPrev.get(space.getCoreInfoString());
×
57
            if (prevSpace != null) space = prevSpace;
×
58
            spaceList.add(space);
×
59
            spacesByCoreInfo.put(space.getCoreInfoString(), space);
×
60
            spacesById.put(space.getId(), space);
×
61
        }
×
62
    }
×
63

64
    public static void ensureLoaded() {
65
        if (spaceList == null) {
×
66
            refresh(QueryApiAccess.forcedGet("get-spaces"));
×
67
        }
68
    }
×
69

70
    public static List<Space> getSpaceList() {
71
        ensureLoaded();
×
72
        return spaceList;
×
73
    }
74

75
    public static Space get(String id) {
76
        ensureLoaded();
×
77
        return spacesById.get(id);
×
78
    }
79

80
    public static void refresh() {
81
        ensureLoaded();
×
82
        for (Space space : spaceList) {
×
83
            space.dataNeedsUpdate = true;
×
84
        }
×
85
    }
×
86

87
    private String id, label, rootNanopubId, type;
88
    private Nanopub rootNanopub = null;
×
89

90
    private String description = null;
×
91
    private List<IRI> owners = new ArrayList<>();
×
92
    private List<IRI> members = new ArrayList<>();
×
93
    private ConcurrentMap<String,IRI> ownerPubkeyMap = new ConcurrentHashMap<>();
×
94
    private List<Template> templates = new ArrayList<>();
×
95
    private Set<String> templateTags = new HashSet<>();
×
96
    private ConcurrentMap<String, List<Template>> templatesPerTag = new ConcurrentHashMap<>();
×
97
    private List<IRI> queryIds = new ArrayList<>();
×
98
    private IRI defaultProvenance = null;
×
99

100
    private boolean dataInitialized = false;
×
101
    private boolean dataNeedsUpdate = true;
×
102

103
    private Space(ApiResponseEntry resp) {
×
104
        this.id = resp.get("space");
×
105
        this.label = resp.get("label");
×
106
        this.type = resp.get("type");
×
107
        this.rootNanopubId = resp.get("np");
×
108
        this.rootNanopub = Utils.getAsNanopub(rootNanopubId);
×
109

110
        for (Statement st : rootNanopub.getAssertion()) {
×
111
            if (st.getSubject().stringValue().equals(getId())) {
×
112
                if (st.getPredicate().equals(DCTERMS.DESCRIPTION)) {
×
113
                    description = st.getObject().stringValue();
×
114
                } else if (st.getPredicate().equals(HAS_OWNER) && st.getObject() instanceof IRI obj) {
×
115
                    addOwner(obj);
×
116
                } else if (st.getPredicate().equals(HAS_PINNED_TEMPLATE) && st.getObject() instanceof IRI obj) {
×
117
                    templates.add(TemplateData.get().getTemplate(obj.stringValue()));
×
118
                } else if (st.getPredicate().equals(HAS_PINNED_QUERY) && st.getObject() instanceof IRI obj) {
×
119
                    queryIds.add(obj);
×
120
                } else if (st.getPredicate().equals(NTEMPLATE.HAS_DEFAULT_PROVENANCE) && st.getObject() instanceof IRI obj) {
×
121
                    defaultProvenance = obj;
×
122
                }
123
            } else if (st.getPredicate().equals(NTEMPLATE.HAS_TAG) && st.getObject() instanceof Literal l) {
×
124
                templateTags.add(l.stringValue());
×
125
                List<Template> list = templatesPerTag.get(l.stringValue());
×
126
                if (list == null) {
×
127
                    list = new ArrayList<>();
×
128
                    templatesPerTag.put(l.stringValue(), list);
×
129
                }
130
                list.add(TemplateData.get().getTemplate(st.getSubject().stringValue()));
×
131
            }
132
        }
×
133
    }
×
134

135
    private void addOwner(IRI owner) {
136
        // TODO This isn't efficient for long owner lists:
137
        if (owners.contains(owner)) return;
×
138
        owners.add(owner);
×
139
        UserData ud = User.getUserData();
×
140
        for (String pubkeyhash : ud.getPubkeyhashes(owner, true)) {
×
141
            ownerPubkeyMap.put(pubkeyhash, owner);
×
142
        }
×
143
    }
×
144

145
    public String getId() {
146
        return id;
×
147
    }
148

149
    public String getRootNanopubId() {
150
        return rootNanopubId;
×
151
    }
152

153
    public String getCoreInfoString() {
154
        return id + " " + rootNanopubId;
×
155
    }
156

157
    public Nanopub getRootNanopub() {
158
        return rootNanopub;
×
159
    }
160

161
    public String getLabel() {
162
        return label;
×
163
    }
164

165
    public String getType() {
166
        return type;
×
167
    }
168

169
    public String getTypeLabel() {
170
        return type.replaceFirst("^.*/", "");
×
171
    }
172

173
    public String getDescription() {
174
        return description;
×
175
    }
176

177
    public boolean isDataInitialized() {
178
        triggerDataUpdate();
×
179
        return dataInitialized;
×
180
    }
181

182
    public List<IRI> getOwners() {
183
        triggerDataUpdate();
×
184
        return owners;
×
185
    }
186

187
    public List<IRI> getMembers() {
188
        triggerDataUpdate();
×
189
        return members;
×
190
    }
191

192
    public List<Template> getTemplates() {
193
        triggerDataUpdate();
×
194
        return templates;
×
195
    }
196

197
    public Set<String> getTemplateTags() {
198
        return templateTags;
×
199
    }
200

201
    public ConcurrentMap<String, List<Template>> getTemplatesPerTag() {
202
        return templatesPerTag;
×
203
    }
204

205
    public List<IRI> getQueryIds() {
206
        return queryIds;
×
207
    }
208

209
    public IRI getDefaultProvenance() {
210
        return defaultProvenance;
×
211
    }
212

213
    private synchronized void triggerDataUpdate() {
214
        if (dataNeedsUpdate) {
×
215
            new Thread(() -> {
×
216
                for (ApiResponseEntry r : QueryApiAccess.forcedGet("get-owners", "unit", id).getData()) {
×
217
                    String pubkeyhash = r.get("pubkeyhash");
×
218
                    if (ownerPubkeyMap.containsKey(pubkeyhash)) {
×
219
                        addOwner(Utils.vf.createIRI(r.get("owner")));
×
220
                    }
221
                }
×
222
                members = new ArrayList<>();
×
223
                for (ApiResponseEntry r : QueryApiAccess.forcedGet("get-members", "unit", id).getData()) {
×
224
                    IRI memberId = Utils.vf.createIRI(r.get("member"));
×
225
                    // TODO These checks are inefficient for long member lists:
226
                    if (owners.contains(memberId)) continue;
×
227
                    if (members.contains(memberId)) continue;
×
228
                    members.add(memberId);
×
229
                }
×
230
                owners.sort(User.getUserData().userComparator);
×
231
                members.sort(User.getUserData().userComparator);
×
232

233
                for (ApiResponseEntry r : QueryApiAccess.forcedGet("get-pinned-templates", "space", id).getData()) {
×
234
                    Template t = TemplateData.get().getTemplate(r.get("template"));
×
235
                    if (t == null) continue;
×
236
                    // Check pubkey with space owners
237
                    templates.add(t);
×
238
                    String tag = r.get("tag");
×
239
                    if (tag != null && !tag.isEmpty()) {
×
240
                        templateTags.add(r.get("tag"));
×
241
                        List<Template> list = templatesPerTag.get(r.get("tag"));
×
242
                        if (list == null) {
×
243
                            list = new ArrayList<>();
×
244
                            templatesPerTag.put(r.get("tag"), list);
×
245
                        }
246
                        list.add(TemplateData.get().getTemplate(r.get("template")));
×
247
                    }
248
                }
×
249
                dataInitialized = true;
×
250
            }).start();
×
251
            dataNeedsUpdate = false;
×
252
        }
253
    }
×
254

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