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

knowledgepixels / nanodash / 18746796461

23 Oct 2025 11:25AM UTC coverage: 13.683% (+0.8%) from 12.859%
18746796461

push

github

tkuhn
fix: Make sure space data initialization doesn't block user page load

476 of 4402 branches covered (10.81%)

Branch coverage included in aggregate %.

1252 of 8227 relevant lines covered (15.22%)

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

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

6
import org.apache.wicket.Component;
7
import org.apache.wicket.extensions.ajax.markup.html.AjaxLazyLoadPanel;
8
import org.apache.wicket.markup.html.basic.Label;
9
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
10
import org.apache.wicket.model.Model;
11
import org.apache.wicket.request.flow.RedirectToUrlException;
12
import org.apache.wicket.request.mapper.parameter.PageParameters;
13
import org.eclipse.rdf4j.model.IRI;
14
import org.nanopub.extra.services.ApiResponse;
15
import org.nanopub.extra.services.QueryRef;
16
import org.slf4j.Logger;
17
import org.slf4j.LoggerFactory;
18

19
import com.google.common.collect.ArrayListMultimap;
20
import com.google.common.collect.Multimap;
21
import com.knowledgepixels.nanodash.ApiCache;
22
import com.knowledgepixels.nanodash.NanodashSession;
23
import com.knowledgepixels.nanodash.Space;
24
import com.knowledgepixels.nanodash.User;
25
import com.knowledgepixels.nanodash.Utils;
26
import com.knowledgepixels.nanodash.component.ActivityPanel;
27
import com.knowledgepixels.nanodash.component.ApiResultComponent;
28
import com.knowledgepixels.nanodash.component.ItemListElement;
29
import com.knowledgepixels.nanodash.component.ItemListPanel;
30
import com.knowledgepixels.nanodash.component.NanopubResults;
31
import com.knowledgepixels.nanodash.component.TitleBar;
32

33
/**
34
 * Page that shows a user profile, including their nanopubs and stats.
35
 */
36
public class UserPage extends NanodashPage {
37

38
    private static final Logger logger = LoggerFactory.getLogger(UserPage.class);
×
39

40
    /**
41
     * The mount path for this page.
42
     */
43
    public static final String MOUNT_PATH = "/user";
44

45
    /**
46
     * {@inheritDoc}
47
     */
48
    @Override
49
    public String getMountPath() {
50
        return MOUNT_PATH;
×
51
    }
52

53
    private IRI userIri;
54
    private String pubkeyHashes = "";
×
55

56
    /**
57
     * Constructor for UserPage.
58
     *
59
     * @param parameters Page parameters, must include "id" with the user IRI.
60
     */
61
    public UserPage(final PageParameters parameters) {
62
        super(parameters);
×
63
        setOutputMarkupId(true);
×
64

65
        if (parameters.get("id") == null) throw new RedirectToUrlException(ProfilePage.MOUNT_PATH);
×
66
        final String userIriString = parameters.get("id").toString();
×
67
        userIri = Utils.vf.createIRI(userIriString);
×
68
        //NanodashSession session = NanodashSession.get();
69

70
        for (String pk : User.getPubkeyhashes(userIri, null)) {
×
71
            pubkeyHashes += " " + pk;
×
72
        }
×
73
        if (!pubkeyHashes.isEmpty()) pubkeyHashes = pubkeyHashes.substring(1);
×
74

75
        String pageType = "users";
×
76
        add(new TitleBar("titlebar", this, pageType));
×
77

78
        final String displayName = User.getShortDisplayName(userIri);
×
79
        add(new Label("pagetitle", displayName + " (user) | nanodash"));
×
80
        add(new Label("username", displayName));
×
81

82
        add(new BookmarkablePageLink<Void>("fullid", ExplorePage.class, parameters.set("label", displayName)).setBody(Model.of(userIriString)));
×
83

84
        add(new BookmarkablePageLink<Void>("showprofile", ProfilePage.class).setVisible(userIri.equals(NanodashSession.get().getUserIri())));
×
85

86
//                final Map<String,String> statsParams = new HashMap<>();
87
//                final String statsQueryName;
88
//                if (pubkeyHashes.isEmpty()) {
89
//                        statsQueryName = "get-user-stats-from-userid";
90
//                        statsParams.put("userid", userIriString);
91
//                } else {
92
//                        statsQueryName = "get-user-stats-from-pubkeys";
93
//                        statsParams.put("userid", userIriString);
94
//                        statsParams.put("pubkeyhashes", pubkeyHashes);
95
//                } 
96
//                Map<String,String> statsMap = ApiCache.retrieveMap(statsQueryName, statsParams);
97
//                if (statsMap != null) {
98
//                        add(new StatsPanel("stats", userIriString, pubkeyHashes, statsMap));
99
//                } else {
100
//                        add(new AjaxLazyLoadPanel<Component>("stats") {
101
//        
102
//                                @Override
103
//                                public Component getLazyLoadComponent(String markupId) {
104
//                                        Map<String,String> m = null;
105
//                                        while (true) {
106
//                                                try {
107
//                                                        Thread.sleep(500);
108
//                                                } catch (InterruptedException ex) {
109
//                                                        logger.error();
110
//                                                }
111
//                                                if (!ApiCache.isRunning(statsQueryName, statsParams)) {
112
//                                                        m = ApiCache.retrieveMap(statsQueryName, statsParams);
113
//                                                        if (m != null) break;
114
//                                                }
115
//                                        }
116
//                                        return new StatsPanel(markupId, userIriString, pubkeyHashes, m);
117
//                                }
118
//
119
//                                @Override
120
//                                protected void onContentLoaded(Component content, Optional<AjaxRequestTarget> target) {
121
//                                        super.onContentLoaded(content, target);
122
//                                        if (target.get() != null) target.get().appendJavaScript("updateElements();");
123
//                                }
124
//        
125
//                        });
126
//                }
127

128
        add(new BookmarkablePageLink<Void>("showchannel", ListPage.class, new PageParameters().add("userid", userIriString)));
×
129

130
        final Multimap<String, String> params = ArrayListMultimap.create();
×
131
        final String queryName;
132
        if (pubkeyHashes.isEmpty()) {
×
133
            queryName = "get-latest-nanopubs-from-userid";
×
134
            params.put("userid", userIri.stringValue());
×
135
        } else {
136
            queryName = "get-latest-nanopubs-from-pubkeys";
×
137
            params.put("pubkeyhashes", pubkeyHashes);
×
138
            params.put("userid", userIri.stringValue());
×
139
        }
140
        final QueryRef queryRef = new QueryRef(queryName, params);
×
141
        ApiResponse response = ApiCache.retrieveResponse(queryRef);
×
142
        if (response != null) {
×
143
            add(makeNanopubResultComponent("latestnanopubs", response));
×
144
        } else {
145
            add(new AjaxLazyLoadPanel<Component>("latestnanopubs") {
×
146

147
                @Override
148
                public Component getLazyLoadComponent(String markupId) {
149
                    ApiResponse r = null;
×
150
                    while (true) {
151
                        try {
152
                            Thread.sleep(500);
×
153
                        } catch (InterruptedException ex) {
×
154
                            logger.error("Thread interrupted while waiting for API response", ex);
×
155
                        }
×
156
                        if (!ApiCache.isRunning(queryRef)) {
×
157
                            r = ApiCache.retrieveResponse(queryRef);
×
158
                            if (r != null) break;
×
159
                        }
160
                    }
161
                    return makeNanopubResultComponent(markupId, r);
×
162
                }
163

164
//                                @Override
165
//                                protected void onContentLoaded(Component content, Optional<AjaxRequestTarget> target) {
166
//                                        super.onContentLoaded(content, target);
167
//                                        if (target.get() != null) target.get().appendJavaScript("updateElements();");
168
//                                }
169

170
            });
171
        }
172

173
        Space.triggerAllDataUpdates();
×
174
        add(new ItemListPanel<Space>(
×
175
                "spaces",
176
                "Spaces",
177
                () -> Space.areAllSpacesInitialized(),
×
178
                () -> {
179
                    List<Space> spaces = new ArrayList<>();
×
180
                    for (Space space : Space.getSpaceList()) {
×
181
                        if (space.isMember(userIri)) spaces.add(space);
×
182
                    }
×
183
                    return spaces;
×
184
                },
185
                (s) -> new ItemListElement("item", SpacePage.class, new PageParameters().add("id", s.getId()), s.getLabel(), "(" + s.getTypeLabel() + ")")
×
186
        ));
187

188
        if (pubkeyHashes.isEmpty()) {
×
189
            add(new Label("activity", "<span class=\"negative\">Activity cannot be shown for this user due to missing user introduction.</span>").setEscapeModelStrings(false));
×
190
        } else {
191
            final QueryRef activityQueryRef = new QueryRef("get-monthly-type-overview-by-pubkeys");
×
192
            for (String pk : pubkeyHashes.split(" ")) {
×
193
                activityQueryRef.getParams().put("pubkey", pk);
×
194
            }
195
            ApiResponse activityQueryResponse = ApiCache.retrieveResponse(activityQueryRef);
×
196
            if (activityQueryResponse != null) {
×
197
                if (activityQueryResponse.getData().isEmpty()) {
×
198
                    add(new Label("activity", "<em>No recent activity to show for this user.</em>").setEscapeModelStrings(false));
×
199
                } else {
200
                    add(new ActivityPanel("activity", activityQueryResponse));
×
201
                }
202
            } else {
203
                add(new ApiResultComponent("activity", activityQueryRef) {
×
204
    
205
                    @Override
206
                    public Component getApiResultComponent(String markupId, ApiResponse response) {
207
                        if (response.getData().isEmpty()) {
×
208
                            return new Label(markupId, "<em>No recent activity to show for this user.</em>").setEscapeModelStrings(false);
×
209
                        } else {
210
                            return new ActivityPanel(markupId, response);
×
211
                        }
212
                    }
213
                });
214
    
215
            }
216
        }
217
    }
×
218

219
    private static Component makeNanopubResultComponent(String markupId, ApiResponse response) {
220
        if (response.getData().isEmpty()) {
×
221
            return new Label(markupId, "(none)");
×
222
        } else {
223
            return NanopubResults.fromApiResponse(markupId, response, 5);
×
224
        }
225
    }
226

227
    /**
228
     * <p>hasAutoRefreshEnabled.</p>
229
     *
230
     * @return a boolean
231
     */
232
    protected boolean hasAutoRefreshEnabled() {
233
        return true;
×
234
    }
235

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