Merge pull request #448 from black-puppydog/feed-pagination

Add simple pagination to user feeds.
This commit is contained in:
Christian Bundy 2020-05-24 10:43:55 -07:00 committed by GitHub
commit eb9e44981a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 114 additions and 12 deletions

View File

@ -264,11 +264,20 @@ router
})
.get("/author/:feed", async (ctx) => {
const { feed } = ctx.params;
const gt = Number(ctx.request.query["gt"] || -1);
const lt = Number(ctx.request.query["lt"] || -1);
if (lt > 0 && gt > 0 && gt >= lt)
throw new Error("Given search range is empty");
const author = async (feedId) => {
const description = await about.description(feedId);
const name = await about.name(feedId);
const image = await about.image(feedId);
const messages = await post.fromPublicFeed(feedId);
const messages = await post.fromPublicFeed(feedId, gt, lt);
const firstPost = await post.firstBy(feedId);
const lastPost = await post.latestBy(feedId);
const relationship = await friend.getRelationship(feedId);
const avatarUrl = `/image/256/${encodeURIComponent(image)}`;
@ -276,6 +285,8 @@ router
return authorView({
feedId,
messages,
firstPost,
lastPost,
name,
description,
avatarUrl,
@ -342,17 +353,27 @@ router
.get("/profile/", async (ctx) => {
const myFeedId = await meta.myFeedId();
const gt = Number(ctx.request.query["gt"] || -1);
const lt = Number(ctx.request.query["lt"] || -1);
if (lt > 0 && gt > 0 && gt >= lt)
throw new Error("Given search range is empty");
const description = await about.description(myFeedId);
const name = await about.name(myFeedId);
const image = await about.image(myFeedId);
const messages = await post.fromPublicFeed(myFeedId);
const messages = await post.fromPublicFeed(myFeedId, gt, lt);
const firstPost = await post.firstBy(myFeedId);
const lastPost = await post.latestBy(myFeedId);
const avatarUrl = `/image/256/${encodeURIComponent(image)}`;
ctx.body = await authorView({
feedId: myFeedId,
messages,
firstPost,
lastPost,
name,
description,
avatarUrl,

View File

@ -627,14 +627,43 @@ module.exports = ({ cooler, isPublic }) => {
})
);
const getLimitPost = async (feedId, reverse) => {
const ssb = await cooler.open();
const source = ssb.createUserStream({ id: feedId, reverse: reverse });
const messages = await new Promise((resolve, reject) => {
pull(
source,
pull.filter((msg) => isDecrypted(msg) === false && isPost(msg)),
pull.take(1),
pull.collect((err, collectedMessages) => {
if (err) {
reject(err);
} else {
resolve(transform(ssb, collectedMessages, feedId));
}
})
);
});
return messages.length ? messages[0] : undefined;
};
const post = {
fromPublicFeed: async (feedId, customOptions = {}) => {
firstBy: async (feedId) => {
return getLimitPost(feedId, false);
},
latestBy: async (feedId) => {
return getLimitPost(feedId, true);
},
fromPublicFeed: async (feedId, gt = -1, lt = -1, customOptions = {}) => {
const ssb = await cooler.open();
const myFeedId = ssb.id;
const options = configure({ id: feedId }, customOptions);
let defaultOptions = { id: feedId };
if (lt >= 0) defaultOptions.lt = lt;
if (gt >= 0) defaultOptions.gt = gt;
defaultOptions.reverse = !(gt >= 0 && lt < 0);
const options = configure(defaultOptions, customOptions);
const { blocking } = await models.friend.getRelationship(feedId);
// Avoid streaming any messages from this feed. If we used the social
@ -661,7 +690,8 @@ module.exports = ({ cooler, isPublic }) => {
);
});
return messages;
if (!defaultOptions.reverse) return messages.reverse();
else return messages;
},
mentionsMe: async (customOptions = {}) => {
const ssb = await cooler.open();

View File

@ -62,6 +62,13 @@ const i18n = {
follow: "Follow",
block: "Block",
unblock: "Unblock",
newerPosts: "Newer posts",
olderPosts: "Older posts",
feedRangeEmpty: "The given range is empty for this feed. Try viewing the ",
seeFullFeed: "full feed",
feedEmpty: "The local client has never seen posts from this account.",
beginningOfFeed: "This is the beginning of the feed",
noNewerPosts: "No newer posts have been received yet.",
relationshipFollowing: "You are following",
relationshipYou: "This is you",
relationshipBlocking: "You are blocking",

View File

@ -505,13 +505,15 @@ exports.editProfileView = ({ name, description }) =>
);
/**
* @param {{avatarUrl: string, description: string, feedId: string, messages: any[], name: string, relationship: object}} input
* @param {{avatarUrl: string, description: string, feedId: string, messages: any[], name: string, relationship: object, firstPost: object, lastPost: object}} input
*/
exports.authorView = ({
avatarUrl,
description,
feedId,
messages,
firstPost,
lastPost,
name,
relationship,
}) => {
@ -600,11 +602,51 @@ exports.authorView = ({
)
);
return template(
i18n.profile,
prefix,
messages.map((msg) => post({ msg }))
);
const linkUrl = relationship.me
? "/profile/"
: `/author/${encodeURIComponent(feedId)}/`;
let items = messages.map((msg) => post({ msg }));
if (items.length === 0) {
if (lastPost === undefined) {
items.push(section(div(span(i18n.feedEmpty))));
} else {
items.push(
section(
div(
span(i18n.feedRangeEmpty),
a({ href: `${linkUrl}` }, i18n.seeFullFeed)
)
)
);
}
} else {
const highestSeqNum = messages[0].value.sequence;
const lowestSeqNum = messages[messages.length - 1].value.sequence;
let newerPostsLink;
if (lastPost !== undefined && highestSeqNum < lastPost.value.sequence)
newerPostsLink = a(
{ href: `${linkUrl}?gt=${highestSeqNum}` },
i18n.newerPosts
);
else newerPostsLink = span(i18n.newerPosts, { title: i18n.noNewerPosts });
let olderPostsLink;
if (lowestSeqNum > firstPost.value.sequence)
olderPostsLink = a(
{ href: `${linkUrl}?lt=${lowestSeqNum}` },
i18n.olderPosts
);
else
olderPostsLink = span(i18n.olderPosts, { title: i18n.beginningOfFeed });
const pagination = section(
{ class: "message" },
footer(div(newerPostsLink, olderPostsLink), br())
);
items.unshift(pagination);
items.push(pagination);
}
return template(i18n.profile, prefix, items);
};
exports.commentView = async ({ messages, myFeedId, parentMessage }) => {

View File

@ -10,6 +10,8 @@ const paths = [
"/inbox",
"/mentions",
"/profile",
"/profile?gt=0",
"/profile?lt=100",
"/profile/edit",
"/public/latest",
"/public/latest/extended",