This commit is contained in:
Doug Hoyte
2023-09-07 15:53:09 -04:00
parent c7cb8285ea
commit 0ade447926
5 changed files with 138 additions and 23 deletions

View File

@ -357,6 +357,23 @@ inline std::string stripUrls(std::string &content) {
} }
struct ReplyCtx {
uint64_t timestamp;
TemplarResult rendered;
};
struct RenderedEventCtx {
std::string content;
std::string timestamp;
const Event *ev = nullptr;
const User *user = nullptr;
bool isFullThreadLoaded = false;
bool eventPresent = true;
bool abbrev = false;
bool highlight = false;
bool showActions = true;
std::vector<ReplyCtx> replies;
};
struct EventThread { struct EventThread {
@ -444,25 +461,9 @@ struct EventThread {
auto now = hoytech::curr_time_s(); auto now = hoytech::curr_time_s();
flat_hash_set<uint64_t> processedLevIds; flat_hash_set<uint64_t> processedLevIds;
struct Reply {
uint64_t timestamp;
TemplarResult rendered;
};
struct RenderedEvent {
std::string content;
std::string timestamp;
const Event *ev = nullptr;
const User *user = nullptr;
bool isFullThreadLoaded = false;
bool eventPresent = true;
bool abbrev = false;
bool highlight = false;
std::vector<Reply> replies;
};
std::function<TemplarResult(const std::string &)> process = [&](const std::string &id){ std::function<TemplarResult(const std::string &)> process = [&](const std::string &id){
RenderedEvent ctx; RenderedEventCtx ctx;
auto p = eventCache.find(id); auto p = eventCache.find(id);
if (p != eventCache.end()) { if (p != eventCache.end()) {
@ -508,7 +509,7 @@ struct EventThread {
struct { struct {
TemplarResult foundEvents; TemplarResult foundEvents;
std::vector<Reply> orphanNodes; std::vector<ReplyCtx> orphanNodes;
} ctx; } ctx;
ctx.foundEvents = process(rootEventId); ctx.foundEvents = process(rootEventId);

View File

@ -2,6 +2,9 @@
#include "WebData.h" #include "WebData.h"
#include "WebStaticFiles.h"
@ -93,7 +96,7 @@ void doSearch(lmdb::txn &txn, Decompressor &decomp, std::string_view search, std
TemplarResult renderCommunityEvents(lmdb::txn &txn, Decompressor &decomp, UserCache &userCache, const CommunitySpec &communitySpec) { TemplarResult renderCommunityEvents(lmdb::txn &txn, Decompressor &decomp, UserCache &userCache, const CommunitySpec &communitySpec) {
AlgoScanner a(txn, communitySpec.algo); AlgoScanner a(txn, communitySpec.algo);
auto events = a.getEvents(txn, decomp, 300); auto events = a.getEvents(txn, decomp, 60);
std::vector<TemplarResult> rendered; std::vector<TemplarResult> rendered;
auto now = hoytech::curr_time_s(); auto now = hoytech::curr_time_s();
@ -176,7 +179,20 @@ HTTPResponse WebServer::generateReadResponse(lmdb::txn &txn, Decompressor &decom
EventThread et(txn, decomp, decodeBech32Simple(u.path[1])); EventThread et(txn, decomp, decodeBech32Simple(u.path[1]));
body = et.render(txn, decomp, userCache); body = et.render(txn, decomp, userCache);
} else if (u.path.size() == 3) { } else if (u.path.size() == 3) {
if (u.path[2] == "raw.json") { if (u.path[2] == "reply") {
auto ev = Event::fromIdExternal(txn, u.path[1]);
ev.populateJson(txn, decomp);
RenderedEventCtx ctx;
ctx.timestamp = renderTimestamp(startTime / 1'000'000, ev.getCreatedAt());
ctx.content = templarInternal::htmlEscape(ev.json.at("content").get_string(), false);
ctx.ev = &ev;
ctx.user = userCache.getUser(txn, decomp, ev.getPubkey());
ctx.showActions = false;
body = tmpl::event::reply(ctx);
} else if (u.path[2] == "raw.json") {
auto ev = Event::fromIdExternal(txn, u.path[1]); auto ev = Event::fromIdExternal(txn, u.path[1]);
ev.populateJson(txn, decomp); ev.populateJson(txn, decomp);
rawBody = tao::json::to_string(ev.json, 4); rawBody = tao::json::to_string(ev.json, 4);

View File

@ -79,6 +79,91 @@ document.addEventListener('alpine:init', () => {
let json = await resp.json(); let json = await resp.json();
if (json.message === 'ok' && json.written === true) {
window.location = `/e/${json.event}`
} else {
this.$refs.msg.innerText = `Sending note failed: ${json.message}`;
console.error(json);
}
},
}));
Alpine.data('newReply', (note) => ({
async init() {
let resp = await fetch(`/e/${note}/raw.json`);
this.repliedTo = await resp.json();
},
async submit() {
this.$refs.msg.innerText = '';
let ev = {
created_at: Math.floor(((new Date()) - 0) / 1000),
kind: 1,
tags: [],
content: this.$refs.post.value,
};
{
// e tags
let rootId;
for (let t of this.repliedTo.tags) {
if (t[0] === 'e' && t[3] === 'root') {
rootId = t[1];
break;
}
}
if (!rootId) {
for (let t of this.repliedTo.tags) {
if (t[0] === 'e') {
rootId = t[1];
break;
}
}
}
if (rootId) {
ev.tags.push(['e', rootId, '', 'root']);
ev.tags.push(['e', this.repliedTo.id, '', 'reply']);
} else {
ev.tags.push(['e', this.repliedTo.id, '', 'root']);
}
// p tags
let seenPTags = {};
for (let t of this.repliedTo.tags) {
if (t[0] === 'p' && !seenPTags[t[1]]) {
ev.tags.push(['p', t[1]]);
seenPTags[t[1]] = true;
}
}
if (!seenPTags[this.repliedTo.pubkey]) {
ev.tags.push(['p', this.repliedTo.pubkey]);
}
// t tags
ev.tags.push(['t', 'oddbean']);
}
ev = await window.nostr.signEvent(ev);
let resp = await fetch("/submit-post", {
method: "post",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(ev),
});
let json = await resp.json();
if (json.message === 'ok' && json.written === true) { if (json.message === 'ok' && json.written === true) {
window.location = `/e/${json.event}` window.location = `/e/${json.event}`
} else { } else {

View File

@ -17,10 +17,11 @@
<> | <a href="/e/$(ctx.ev->getParentNoteId())">parent</a> </> ?(ctx.ev->parent.size()) <> | <a href="/e/$(ctx.ev->getParentNoteId())">parent</a> </> ?(ctx.ev->parent.size())
<br/> <>
| <a href="/e/$(ctx.ev->getNoteId())/reply">reply</a>
<a href="">reply</a>
| <a href="" class="f">flag</a> | <a href="" class="f">flag</a>
</> ?(ctx.showActions)
<>+$(ctx.ev->upVotes)</> ?(ctx.ev->upVotes) <>+$(ctx.ev->upVotes)</> ?(ctx.ev->upVotes)
<>-$(ctx.ev->downVotes)</> ?(ctx.ev->downVotes) <>-$(ctx.ev->downVotes)</> ?(ctx.ev->downVotes)
</div> </div>

View File

@ -0,0 +1,12 @@
<div x-data="newReply('$(ctx.ev->getNoteId())')" class="new-post">
$(event::event(ctx))
<textarea id="post-text" name="post-text" x-ref="post" rows="8" cols="80" wrap="virtual"></textarea>
<div @click="submit" class="submit-button">
<button>Reply</button>
</div>
<div class="result-message" x-ref="msg">
</div>
</div>