Merge pull request #448 from black-puppydog/feed-pagination
Add simple pagination to user feeds.
This commit is contained in:
commit
eb9e44981a
25
src/index.js
25
src/index.js
@ -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,
|
||||
|
@ -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();
|
||||
|
@ -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",
|
||||
|
@ -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 }) => {
|
||||
|
@ -10,6 +10,8 @@ const paths = [
|
||||
"/inbox",
|
||||
"/mentions",
|
||||
"/profile",
|
||||
"/profile?gt=0",
|
||||
"/profile?lt=100",
|
||||
"/profile/edit",
|
||||
"/public/latest",
|
||||
"/public/latest/extended",
|
||||
|
Loading…
Reference in New Issue
Block a user