mirror of
https://github.com/hoytech/strfry.git
synced 2025-06-17 16:58:50 +00:00
wip
This commit is contained in:
@ -1,27 +1,22 @@
|
|||||||
build
|
|
||||||
! move static/Makefile rules into main system
|
|
||||||
! bundle static files in strfry binary
|
|
||||||
|
|
||||||
read
|
read
|
||||||
! caching
|
! pagination on user comments screen, communities?
|
||||||
! non-500 error pages when bech32 fails to parse, for example
|
* caching
|
||||||
! search field: enter anything, pubkey (hex or npub), eventId, etc. maybe even full-text search?
|
* non-500 error pages when bech32 fails to parse, for example
|
||||||
! rss
|
* search field: enter anything, pubkey (hex or npub), eventId, etc. maybe even full-text search?
|
||||||
! click on up/down vote counts to see who voted
|
* rss
|
||||||
? pagination on user comments screen, communities
|
* click on up/down vote counts to see who voted
|
||||||
|
|
||||||
styling
|
styling
|
||||||
! make URLs in user profiles clickable
|
! test a bit on mobile
|
||||||
! make nostr:note1... refs clickable
|
|
||||||
! mobile
|
|
||||||
! favicon
|
|
||||||
! make login/upvote/etc buttons do something when not logged in/no nostr plugin installed
|
! 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)
|
? smarter truncation/abbrev (try to cut at a sentence, or word boundary, don't cut URLs)
|
||||||
? abbrev comments should be smaller? non-pre tag?
|
? abbrev comments should be smaller? non-pre tag?
|
||||||
! limit name length: http://localhost:8080/u/npub1e44hczvjqvnp5shx9tmapmw5w6q9x98wdrd2lxhmwfsdmuf5gp9qwvpk6g
|
|
||||||
|
|
||||||
misc
|
misc
|
||||||
nip-05 checkmarks
|
! nginx/systemd/deb deploy stuff
|
||||||
|
! docs
|
||||||
|
* nip-05 checkmarks
|
||||||
|
|
||||||
write
|
write
|
||||||
? edit profile (or maybe just send them to https://metadata.nostr.com/)
|
? edit profile (or maybe just send them to https://metadata.nostr.com/)
|
||||||
|
@ -14,6 +14,37 @@
|
|||||||
std::string stripUrls(std::string &content);
|
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 += "<a href=\"";
|
||||||
|
output += url;
|
||||||
|
output += "\">";
|
||||||
|
output += text;
|
||||||
|
output += "</a>";
|
||||||
|
};
|
||||||
|
|
||||||
|
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 {
|
struct User {
|
||||||
@ -83,9 +114,15 @@ struct User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string getMeta(std::string_view field) const {
|
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) 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();
|
if (kind0Json->get_object().contains(field) && kind0Json->at(field).is_string()) output = kind0Json->at(field).get_string();
|
||||||
return "";
|
|
||||||
|
output = templarInternal::htmlEscape(output, false);
|
||||||
|
preprocessMetaFieldContent(output);
|
||||||
|
|
||||||
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
void populateContactList(lmdb::txn &txn, Decompressor &decomp) {
|
void populateContactList(lmdb::txn &txn, Decompressor &decomp) {
|
||||||
@ -274,9 +311,8 @@ struct Event {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline void preprocessEventContent(lmdb::txn &txn, Decompressor &decomp, const Event &ev, UserCache &userCache, std::string &content) {
|
||||||
inline void preprocessContent(lmdb::txn &txn, Decompressor &decomp, const Event &ev, UserCache &userCache, std::string &content) {
|
static RE2 matcher(R"((?is)(.*?)(https?://\S+|#\[\d+\]|nostr:note1\w+))");
|
||||||
static RE2 matcher(R"((?is)(.*?)(https?://\S+|#\[\d+\]))");
|
|
||||||
|
|
||||||
std::string output;
|
std::string output;
|
||||||
|
|
||||||
@ -298,6 +334,10 @@ inline void preprocessContent(lmdb::txn &txn, Decompressor &decomp, const Event
|
|||||||
|
|
||||||
if (match.starts_with("http")) {
|
if (match.starts_with("http")) {
|
||||||
appendLink(sv(match), sv(match));
|
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("#[")) {
|
} else if (match.starts_with("#[")) {
|
||||||
bool didTransform = false;
|
bool didTransform = false;
|
||||||
auto offset = std::stoull(std::string(sv(match)).substr(2, match.size() - 3));
|
auto offset = std::stoull(std::string(sv(match)).substr(2, match.size() - 3));
|
||||||
@ -483,7 +523,7 @@ struct EventThread {
|
|||||||
ctx.content = elem.summaryHtml();
|
ctx.content = elem.summaryHtml();
|
||||||
} else {
|
} else {
|
||||||
ctx.content = templarInternal::htmlEscape(elem.json.at("content").get_string(), false);
|
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;
|
ctx.ev = &elem;
|
||||||
|
@ -11,13 +11,13 @@
|
|||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>$(field)</th>
|
<th>$(field)</th>
|
||||||
<td>$(ctx.getMeta(field))</td>
|
<td>$!(ctx.getMeta(field))</td>
|
||||||
</tr> @(const auto &field : { "name", "about" })
|
</tr> @(const auto &field : { "name", "about" })
|
||||||
|
|
||||||
<>
|
<>
|
||||||
<tr>
|
<tr>
|
||||||
<th>$(field)</th>
|
<th>$(field)</th>
|
||||||
<td>$(ctx.getMeta(field))</td>
|
<td>$!(ctx.getMeta(field))</td>
|
||||||
</tr> ?(field != "name" && field != "about")
|
</tr> ?(field != "name" && field != "about")
|
||||||
</> @(const auto &[field, v] : ctx.kind0Json->get_object())
|
</> @(const auto &[field, v] : ctx.kind0Json->get_object())
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user