From a7cc9013ba0ba9487ff3ee6d5c30b7e3f92a7667 Mon Sep 17 00:00:00 2001 From: Doug Hoyte Date: Fri, 8 Sep 2023 08:29:40 -0400 Subject: [PATCH] wip --- src/apps/web/TODO | 27 ++++++-------- src/apps/web/WebData.h | 52 +++++++++++++++++++++++---- src/apps/web/tmpls/user/metadata.tmpl | 4 +-- 3 files changed, 59 insertions(+), 24 deletions(-) diff --git a/src/apps/web/TODO b/src/apps/web/TODO index 0c0fb9e..98f7541 100644 --- a/src/apps/web/TODO +++ b/src/apps/web/TODO @@ -1,27 +1,22 @@ -build - ! move static/Makefile rules into main system - ! bundle static files in strfry binary - read - ! caching - ! non-500 error pages when bech32 fails to parse, for example - ! search field: enter anything, pubkey (hex or npub), eventId, etc. maybe even full-text search? - ! rss - ! click on up/down vote counts to see who voted - ? pagination on user comments screen, communities + ! pagination on user comments screen, communities? + * caching + * non-500 error pages when bech32 fails to parse, for example + * search field: enter anything, pubkey (hex or npub), eventId, etc. maybe even full-text search? + * rss + * click on up/down vote counts to see who voted styling - ! make URLs in user profiles clickable - ! make nostr:note1... refs clickable - ! mobile - ! favicon + ! test a bit on mobile ! make login/upvote/etc buttons do something when not logged in/no nostr plugin installed + ? limit name length: http://localhost:8080/u/npub1e44hczvjqvnp5shx9tmapmw5w6q9x98wdrd2lxhmwfsdmuf5gp9qwvpk6g ? smarter truncation/abbrev (try to cut at a sentence, or word boundary, don't cut URLs) ? abbrev comments should be smaller? non-pre tag? - ! limit name length: http://localhost:8080/u/npub1e44hczvjqvnp5shx9tmapmw5w6q9x98wdrd2lxhmwfsdmuf5gp9qwvpk6g misc - nip-05 checkmarks + ! nginx/systemd/deb deploy stuff + ! docs + * nip-05 checkmarks write ? edit profile (or maybe just send them to https://metadata.nostr.com/) diff --git a/src/apps/web/WebData.h b/src/apps/web/WebData.h index 2f7d43a..da4b317 100644 --- a/src/apps/web/WebData.h +++ b/src/apps/web/WebData.h @@ -14,6 +14,37 @@ std::string stripUrls(std::string &content); +inline void preprocessMetaFieldContent(std::string &content) { + static RE2 matcher(R"((?is)(.*?)(https?://\S+))"); + + std::string output; + + std::string_view contentSv(content); + re2::StringPiece input(contentSv); + re2::StringPiece prefix, match; + + auto sv = [](re2::StringPiece s){ return std::string_view(s.data(), s.size()); }; + auto appendLink = [&](std::string_view url, std::string_view text){ + output += ""; + output += text; + output += ""; + }; + + while (RE2::Consume(&input, matcher, &prefix, &match)) { + output += sv(prefix); + + if (match.starts_with("http")) { + appendLink(sv(match), sv(match)); + } + } + + if (output.size()) { + output += std::string_view(input.data(), input.size()); + std::swap(output, content); + } +} struct User { @@ -83,9 +114,15 @@ struct User { } std::string getMeta(std::string_view field) const { + std::string output; + if (!kind0Json) throw herr("can't getMeta because user doesn't have kind 0"); - if (kind0Json->get_object().contains(field) && kind0Json->at(field).is_string()) return kind0Json->at(field).get_string(); - return ""; + if (kind0Json->get_object().contains(field) && kind0Json->at(field).is_string()) output = kind0Json->at(field).get_string(); + + output = templarInternal::htmlEscape(output, false); + preprocessMetaFieldContent(output); + + return output; } void populateContactList(lmdb::txn &txn, Decompressor &decomp) { @@ -274,9 +311,8 @@ struct Event { }; - -inline void preprocessContent(lmdb::txn &txn, Decompressor &decomp, const Event &ev, UserCache &userCache, std::string &content) { - static RE2 matcher(R"((?is)(.*?)(https?://\S+|#\[\d+\]))"); +inline void preprocessEventContent(lmdb::txn &txn, Decompressor &decomp, const Event &ev, UserCache &userCache, std::string &content) { + static RE2 matcher(R"((?is)(.*?)(https?://\S+|#\[\d+\]|nostr:note1\w+))"); std::string output; @@ -298,6 +334,10 @@ inline void preprocessContent(lmdb::txn &txn, Decompressor &decomp, const Event if (match.starts_with("http")) { appendLink(sv(match), sv(match)); + } else if (match.starts_with("nostr:note1")) { + std::string path = "/e/"; + path += sv(match).substr(6); + appendLink(path, sv(match)); } else if (match.starts_with("#[")) { bool didTransform = false; auto offset = std::stoull(std::string(sv(match)).substr(2, match.size() - 3)); @@ -483,7 +523,7 @@ struct EventThread { ctx.content = elem.summaryHtml(); } else { ctx.content = templarInternal::htmlEscape(elem.json.at("content").get_string(), false); - preprocessContent(txn, decomp, elem, userCache, ctx.content); + preprocessEventContent(txn, decomp, elem, userCache, ctx.content); } ctx.ev = &elem; diff --git a/src/apps/web/tmpls/user/metadata.tmpl b/src/apps/web/tmpls/user/metadata.tmpl index 1be2449..2511f57 100644 --- a/src/apps/web/tmpls/user/metadata.tmpl +++ b/src/apps/web/tmpls/user/metadata.tmpl @@ -11,13 +11,13 @@ $(field) - $(ctx.getMeta(field)) + $!(ctx.getMeta(field)) @(const auto &field : { "name", "about" }) <> $(field) - $(ctx.getMeta(field)) + $!(ctx.getMeta(field)) ?(field != "name" && field != "about") @(const auto &[field, v] : ctx.kind0Json->get_object())