Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch wiki Excluding Merge-Ins
This is equivalent to a diff from ad120f4256 to c6f863dd80
2024-08-04
| ||
21:11 | Merged back links check-in: c743e4b553 user: scstarkey tags: main, trunk | |
21:11 | Back links Closed-Leaf check-in: c6f863dd80 user: scstarkey tags: wiki | |
2024-08-02
| ||
14:40 | Brought fixes back in from main check-in: 993637cf98 user: scstarkey tags: wiki | |
14:31 | Switched to basic from standard check-in: ad120f4256 user: scstarkey tags: main, trunk | |
14:03 | Switching to NIOFSDirectory to see if it'll start up in podman container check-in: a2f0bd53de user: scstarkey tags: main, trunk | |
Changes to src/main/java/app/coffeetime/SearchInterface.java.
1 2 3 4 5 6 7 8 9 10 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | - + - - - - - + + + + + + + + + + + + + + + + + + + - - - + + - + - + - - - | package app.coffeetime; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.core.WhitespaceAnalyzer; import org.apache.lucene.analysis.miscellaneous.PerFieldAnalyzerWrapper; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.document.TextField; import org.apache.lucene.index.*; |
︙ | |||
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | + - + - - + + - - + + + + + - - - - - + + + + + + + + + - + + + + + + - + + + + + - + + + + | return new SearchInterface() { @Override public void save(final PVector<SearchField> fields) { try { final var document = new Document(); fields.forEach(field -> document.add(new Field(field.name(), String.valueOf(field.value()), field.stored() ? TextField.TYPE_STORED : TextField.TYPE_NOT_STORED))); try (final var writer = writerSupplier.get()) { writer.addDocument(document); } } catch (IOException e) { throw new IllegalStateException(e); } } @Override public void delete(final SearchField field) { try (final var writer = writerSupplier.get()) { writer.deleteDocuments(term(field)); } catch (IOException e) { throw new IllegalStateException(e); } } @Override |
Changes to src/main/java/app/coffeetime/models/WikiModel.java.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | + + + + + | package app.coffeetime.models; import app.coffeetime.DatabaseInterface; import app.coffeetime.SearchInterface; import app.coffeetime.SearchInterface.SearchField; import app.coffeetime.util.TextSanitizer; import org.apache.commons.io.IOUtils; import org.jetbrains.annotations.NotNull; import org.pcollections.PVector; import org.pcollections.TreePVector; import org.slf4j.Logger; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.sql.Connection; import java.sql.PreparedStatement; import java.time.Instant; import java.util.Optional; import java.util.TimeZone; import java.util.function.Supplier; import java.util.regex.Pattern; import static app.coffeetime.DatabaseInterface.*; import static app.coffeetime.util.Logging.logSupplier; import static java.lang.String.format; import static java.util.Optional.ofNullable; public class WikiModel { private static final Pattern WIKI_LINK_PATTERN = Pattern.compile("\\[\\[([^\\[]+)]]"); private static final Supplier<Logger> LOG = logSupplier(WikiModel.class); public static final String SEARCH_FIELD_LATEST = "wikiIsLatest"; public static final String SEARCH_FIELD_PAGE_ID = "wikiPageId"; public static final String SEARCH_FIELD_TEAM_ID = "wikiTeamId"; public static final String SEARCH_FIELD_PAGE_NAME = "wikiPageName"; public static final String SEARCH_FIELD_VERSION = "wikiPageVersion"; public static final String SEARCH_FIELD_CONTENT = "wikiContent"; |
︙ | |||
73 74 75 76 77 78 79 | 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | - + + + - + - - - - - - - - + - - - - - - - + + + + + + + + + + + + + + + + - + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + - + - | } }) .orElse("Welcome to your wiki!"); } }.get(); } |
︙ | |||
180 181 182 183 184 185 186 187 | 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 | + - - - - - - + + + + + + + + + + + | private void indexPage(final String teamId, final Integer pageId, final String pageName, final String pageContents, final int version, final boolean latest) { final var processedContents = sanitizeWikiLinks(pageContents); search.save(TreePVector.<SearchField>empty() |
︙ |
Changes to src/main/java/app/coffeetime/web/WikiRouting.java.
︙ | |||
65 66 67 68 69 70 71 72 73 74 75 76 77 78 | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | + + + + + + + + + + + + + + + + + + | }); } } catch (InvalidTokenException e) { LOG.get().error("Invalid CSRF token", e); return redirect("/", e.getUserFriendlyMessage()); } })); router.GET("/teams/:teamId/wiki/:pageName/_backLinks", wrapAuth(userModel, sessionProperties, req -> { final var teamId = req.requestPropertyAsString("teamId"); final var requesterEmail = req.principal().orElse(null); final var team = teamModel.getTeam(requesterEmail, req.timeZone(), teamId).orElseThrow(); final var pageName = req.requestPropertyAsOptionalString("pageName").orElse(WikiModel.HOME_PAGE); return htmlResponse(renderPage(mergeTool, req, "/templates/web/wikiBackLinks.vm", HashTreePMap.<String, Object>empty() .plus("homePage", WikiModel.HOME_PAGE.equals(pageName)) .plus("homePageName", WikiModel.HOME_PAGE) .plus("pageName", pageName) .plus("team", team) .plus("backLinks", wikiModel.getBackLinks(requesterEmail, teamId, pageName)))); })); } @NotNull private static Response wikiResponse(final MergeTool mergeTool, final WikiModel wikiModel, final TeamModel teamModel, final Request req, |
︙ |
Changes to src/main/resources/main.scss.
︙ | |||
1928 1929 1930 1931 1932 1933 1934 | 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 | - + - + | grid-row-gap: 1rem; grid-template-columns: min-content; } } #teamsPanel, #teamPanel, #wikiPanel { h1 { |
︙ |
Added src/main/resources/templates/web/wikiBackLinks.vm.
|
Changes to src/main/resources/templates/web/wikiPage.vm.
1 2 | 1 2 3 4 5 6 7 8 9 10 | - + | <div id="wikiPanel"> <div id="header"> |
︙ |
Changes to src/test/java/app/coffeetime/models/WikiModelTest.java.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | + + + + + | package app.coffeetime.models; import app.coffeetime.fixtures.TestCoffeeTime; import app.coffeetime.util.Logging; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.ConsoleAppender; import io.sentry.SentryOptions; import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.util.AttributeImpl; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.pcollections.HashTreePMap; import org.pcollections.TreePVector; import java.time.Instant; import java.util.Iterator; import java.util.TimeZone; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; import static app.coffeetime.fixtures.TestCoffeeTime.ADMIN_EMAIL; import static app.coffeetime.models.WikiModel.HOME_PAGE; import static org.junit.jupiter.api.Assertions.*; public class WikiModelTest { private static final Instant EXPECTED_NOW = Instant.parse("2024-06-10T12:30:00Z"); private static final AtomicReference<Instant> CURRENT_NOW = new AtomicReference<>(); private static final String DEFAULT_HOME_CONTENT_SNIPPET = "Welcome to your wiki!"; private static final String DEFAULT_NON_HOME_CONTENT_SNIPPET = "There is no content here"; |
︙ | |||
86 87 88 89 90 91 92 | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | - + - - - + + + + - - + + - + - - - - - + + + + + - - + + + | teamModel.addMember(ADMIN_EMAIL, this.publicTeam.getId(), nonAdminMemberUser.userInfo()); teamModel.addMember(ADMIN_EMAIL, this.privateTeam.getId(), nonAdminMemberUser.userInfo()); } @Test public void missingHomePage() { |
︙ | |||
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 | + + + + + + + + + + + + + + + + + + + + + + + + + + | assertNull(wikiModel.getPage(null, publicTeam.getId(), pageName)); assertNull(wikiModel.getPage(null, privateTeam.getId(), pageName)); } @Test public void backLinks() { final var expectedPublicContents = "This is a public page that refers to [[AnotherPage]] that is of note"; final var expectedPrivateContents = "This is a private page that refers to [[Another Page]] that is of note"; wikiModel.savePage(NON_ADMIN_TEAM_MEMBER, publicTeam.getId(), "HomePage", null, "This is a page without any links"); final var publicLinkedResult = wikiModel.savePage(NON_ADMIN_TEAM_MEMBER, publicTeam.getId(), "HomePage", 1, expectedPublicContents); final var privateLinkedResult = wikiModel.savePage(NON_ADMIN_TEAM_MEMBER, privateTeam.getId(), "HomePage", null, expectedPrivateContents); wikiModel.savePage(NON_ADMIN_TEAM_MEMBER, publicTeam.getId(), "AnotherPage", null, "This is another fun page"); final var publicBackLinks = wikiModel.getBackLinks(NON_TEAM_MEMBER, publicTeam.getId(), "AnotherPage"); final var privateBackLinks = wikiModel.getBackLinks(ADMIN_EMAIL, privateTeam.getId(), "AnotherPage"); final var notAllowedBackLinks = wikiModel.getBackLinks(NON_TEAM_MEMBER, privateTeam.getId(), "AnotherPage"); assertEquals(WikiModel.WikiSaveResult.success, publicLinkedResult); assertEquals(WikiModel.WikiSaveResult.success, privateLinkedResult); assertEquals(1, publicBackLinks.size()); assertEquals(1, privateBackLinks.size()); assertEquals(0, notAllowedBackLinks.size()); assertEquals(expectedPublicContents, publicBackLinks.getFirst().content()); assertEquals(HOME_PAGE, publicBackLinks.getFirst().name()); assertEquals(expectedPrivateContents, privateBackLinks.getFirst().content()); assertEquals(HOME_PAGE, privateBackLinks.getFirst().name()); } @Test public void searchAmongLatestPages() { } |
︙ |