mirror of
https://github.com/hoytech/strfry.git
synced 2025-06-19 17:37:43 +00:00
paginate followers
This commit is contained in:
@ -1,5 +1,4 @@
|
||||
read
|
||||
! paginate followers
|
||||
* nostr: links not replaced in feed titles
|
||||
* support nprofile/nevent/etc links
|
||||
* non-500 error pages when bech32 fails to parse, for example
|
||||
|
@ -128,13 +128,15 @@ struct User {
|
||||
kind3Event = loadKindEvent(txn, decomp, 3);
|
||||
}
|
||||
|
||||
std::vector<std::string> getFollowers(lmdb::txn &txn, Decompressor &decomp, const std::string &pubkey) {
|
||||
std::vector<std::string> getFollowers(lmdb::txn &txn, Decompressor &decomp, const std::string &pubkey, uint64_t offset = 0, uint64_t limit = MAX_U64, uint64_t *countOut = nullptr) {
|
||||
std::vector<std::string> output;
|
||||
flat_hash_set<std::string> alreadySeen;
|
||||
|
||||
std::string prefix = "p";
|
||||
prefix += pubkey;
|
||||
|
||||
uint64_t curr = 0;
|
||||
|
||||
env.generic_foreachFull(txn, env.dbi_Event__tag, prefix, "", [&](std::string_view k, std::string_view v){
|
||||
ParsedKey_StringUint64 parsedKey(k);
|
||||
if (parsedKey.s != prefix) return false;
|
||||
@ -148,13 +150,15 @@ struct User {
|
||||
|
||||
if (!alreadySeen.contains(pubkey)) {
|
||||
alreadySeen.insert(pubkey);
|
||||
output.emplace_back(std::move(pubkey));
|
||||
curr++;
|
||||
if (curr >= offset && curr - offset < limit) output.emplace_back(std::move(pubkey));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
if (countOut) *countOut = curr;
|
||||
return output;
|
||||
}
|
||||
};
|
||||
|
@ -186,8 +186,11 @@ HTTPResponse WebServer::generateReadResponse(lmdb::txn &txn, Decompressor &decom
|
||||
auto handleFeed = [&](std::string_view feedId){
|
||||
uint64_t resultsPerPage = 30;
|
||||
uint64_t page = 0;
|
||||
auto pageStr = u.lookupQuery("p");
|
||||
if (pageStr) page = std::stoull(std::string(*pageStr));
|
||||
|
||||
try {
|
||||
auto pageStr = u.lookupQuery("p");
|
||||
if (pageStr) page = std::stoull(std::string(*pageStr));
|
||||
} catch(...) {}
|
||||
|
||||
feedReader.emplace(txn, decomp, feedId);
|
||||
|
||||
@ -267,28 +270,54 @@ HTTPResponse WebServer::generateReadResponse(lmdb::txn &txn, Decompressor &decom
|
||||
title = std::string("following: ") + user.username;
|
||||
user.populateContactList(txn, decomp);
|
||||
|
||||
uint64_t numFollowing = 0;
|
||||
if (user.kind3Event) {
|
||||
for (const auto &tagJson : user.kind3Event->at("tags").get_array()) {
|
||||
const auto &tag = tagJson.get_array();
|
||||
if (tag.size() >= 2 && tag.at(0).get_string() == "p") numFollowing++;
|
||||
}
|
||||
}
|
||||
|
||||
struct {
|
||||
User &user;
|
||||
std::function<const User*(const std::string &)> getUser;
|
||||
uint64_t numFollowing;
|
||||
} ctx = {
|
||||
user,
|
||||
[&](const std::string &pubkey){ return userCache.getUser(txn, decomp, pubkey); },
|
||||
numFollowing,
|
||||
};
|
||||
|
||||
body = tmpl::user::following(ctx);
|
||||
} else if (u.path[2] == "followers") {
|
||||
uint64_t resultsPerPage = 500;
|
||||
uint64_t page = 0;
|
||||
|
||||
try {
|
||||
auto pageStr = u.lookupQuery("p");
|
||||
if (pageStr) page = std::stoull(std::string(*pageStr));
|
||||
} catch(...) {}
|
||||
|
||||
User user(txn, decomp, userPubkey);
|
||||
title = std::string("followers: ") + user.username;
|
||||
auto followers = user.getFollowers(txn, decomp, user.pubkey);
|
||||
uint64_t numFollowers = 0;
|
||||
auto followers = user.getFollowers(txn, decomp, user.pubkey, page * resultsPerPage, resultsPerPage, &numFollowers);
|
||||
uint64_t numPages = (numFollowers + resultsPerPage + 1) / resultsPerPage;
|
||||
|
||||
struct {
|
||||
const User &user;
|
||||
const std::vector<std::string> &followers;
|
||||
uint64_t numFollowers;
|
||||
std::function<const User*(const std::string &)> getUser;
|
||||
uint64_t page;
|
||||
uint64_t numPages;
|
||||
} ctx = {
|
||||
user,
|
||||
followers,
|
||||
numFollowers,
|
||||
[&](const std::string &pubkey){ return userCache.getUser(txn, decomp, pubkey); },
|
||||
page,
|
||||
numPages,
|
||||
};
|
||||
|
||||
body = tmpl::user::followers(ctx);
|
||||
|
@ -292,6 +292,14 @@ table.vert {
|
||||
margin-left: 40px;
|
||||
}
|
||||
|
||||
.pagination-links {
|
||||
margin-top: 40px;
|
||||
text-align: center;
|
||||
> * {
|
||||
margin: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.feed-info {
|
||||
.feed-id {
|
||||
background-color: #dfdfdf;
|
||||
|
@ -3,6 +3,6 @@
|
||||
</div>
|
||||
|
||||
<div class="feed-nav-links">
|
||||
<a href="./?p=$(ctx.page + 1)">More</a> ?(ctx.n != 0)
|
||||
<a href="?p=$(ctx.page + 1)">More</a> ?(ctx.n != 0)
|
||||
<span>The end.</span> ?(ctx.n == 0)
|
||||
</div>
|
||||
|
@ -1,4 +1,6 @@
|
||||
<div class="user-followers">
|
||||
<h2><a href="/u/$(ctx.user.npubId)">$(ctx.user.username)</a> has $(ctx.numFollowers) known followers.</h2>
|
||||
|
||||
<table class="vert">
|
||||
<tr>
|
||||
<th>user</th>
|
||||
@ -16,4 +18,10 @@
|
||||
</>
|
||||
|
||||
</table>
|
||||
|
||||
<div class="pagination-links">
|
||||
<a href="?p=$(ctx.page - 1)">Prev</a> ?(ctx.numPages && ctx.page > 0)
|
||||
<span>$(ctx.page + 1) / $(ctx.numPages)</span>
|
||||
<a href="?p=$(ctx.page + 1)">Next</a> ?(ctx.numPages && ctx.page < ctx.numPages-1)
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,4 +1,6 @@
|
||||
<div class="user-following">
|
||||
<h2><a href="/u/$(ctx.user.npubId)">$(ctx.user.username)</a> is following $(ctx.numFollowing) users.</h2> ?(ctx.user.kind3Event)
|
||||
|
||||
<div> ?(!ctx.user.kind3Event)
|
||||
No kind 3 contact list found for $(ctx.user.npubId)
|
||||
</div>
|
||||
|
Reference in New Issue
Block a user