Browse Source

Pagination of the public and private page

Use the query parameters skip and show to control what you can see,
e.g. /alex/admin?skip=0&show=4

Don't use or save the timeline cache if either is set.

The following functions were changed from accepting a single max
parameter to accepting both skip and show:
timeline_simple_list, timeline_list, index_list_desc.
Alex Schroeder 2 years ago
parent
commit
a221237637
5 changed files with 46 additions and 23 deletions
  1. 1 1
      activitypub.c
  2. 10 10
      data.c
  3. 31 8
      html.c
  4. 1 1
      main.c
  5. 3 3
      snac.h

+ 1 - 1
activitypub.c

@@ -1094,7 +1094,7 @@ int activitypub_get_handler(d_char *req, char *q_path,
     else
     if (strcmp(p_path, "outbox") == 0) {
         xs *id = xs_fmt("%s/outbox", snac.actor);
-        xs *elems = timeline_simple_list(&snac, "public", 20);
+        xs *elems = timeline_simple_list(&snac, "public", 0, 20);
         xs *list = xs_list_new();
         msg = msg_collection(&snac, id);
         char *p, *v;

+ 10 - 10
data.c

@@ -359,7 +359,7 @@ d_char *index_list(const char *fn, int max)
 }
 
 
-d_char *index_list_desc(const char *fn, int max)
+d_char *index_list_desc(const char *fn, int skip, int show)
 /* returns an index as a list, in reverse order */
 {
     d_char *list = NULL;
@@ -372,9 +372,9 @@ d_char *index_list_desc(const char *fn, int max)
         char line[256];
         list = xs_list_new();
 
-        /* move to the end minus one entry */
-        if (!fseek(f, 0, SEEK_END) && !fseek(f, -33, SEEK_CUR)) {
-            while (n < max && fgets(line, sizeof(line), f) != NULL) {
+        /* move to the end minus one entry (or more, if skipping entries) */
+        if (!fseek(f, 0, SEEK_END) && !fseek(f, (skip + 1) * -33, SEEK_CUR)) {
+            while (n < show && fgets(line, sizeof(line), f) != NULL) {
                 line[32] = '\0';
                 list = xs_list_append(list, line);
                 n++;
@@ -856,7 +856,7 @@ d_char *timeline_top_level(d_char *list)
 }
 
 
-d_char *timeline_simple_list(snac *snac, const char *idx_name, int max)
+d_char *timeline_simple_list(snac *snac, const char *idx_name, int skip, int show)
 /* returns a timeline (with all entries) */
 {
     int c_max;
@@ -865,19 +865,19 @@ d_char *timeline_simple_list(snac *snac, const char *idx_name, int max)
     c_max = xs_number_get(xs_dict_get(srv_config, "max_timeline_entries"));
 
     /* never more timeline entries than the configured maximum */
-    if (max > c_max)
-        max = c_max;
+    if (show > c_max)
+        show = c_max;
 
     xs *idx = xs_fmt("%s/%s.idx", snac->basedir, idx_name);
 
-    return index_list_desc(idx, max);
+    return index_list_desc(idx, skip, show);
 }
 
 
-d_char *timeline_list(snac *snac, const char *idx_name, int max)
+d_char *timeline_list(snac *snac, const char *idx_name, int skip, int show)
 /* returns a timeline (only top level entries) */
 {
-    xs *list = timeline_simple_list(snac, idx_name, max);
+    xs *list = timeline_simple_list(snac, idx_name, skip, show);
 
     return timeline_top_level(list);
 }

+ 31 - 8
html.c

@@ -967,6 +967,7 @@ int html_get_handler(d_char *req, char *q_path, char **body, int *b_size, char *
     xs *uid = NULL;
     char *p_path;
     int cache = 1;
+    int save = 1;
     char *v;
 
     xs *l = xs_split_n(q_path, "/", 2);
@@ -1004,6 +1005,14 @@ int html_get_handler(d_char *req, char *q_path, char **body, int *b_size, char *
     if ((v = xs_dict_get(srv_config, "disable_cache")) && xs_type(v) == XSTYPE_TRUE)
         cache = 0;
 
+    int skip = 0;
+    int show = 50;
+    char *q_vars = xs_dict_get(req, "q_vars");
+    if ((v = xs_dict_get(q_vars, "skip")) != NULL)
+        skip = atoi(v), cache = 0, save = 0;
+    if ((v = xs_dict_get(q_vars, "show")) != NULL)
+        show = atoi(v), cache = 0, save = 0;
+
     if (p_path == NULL) {
         /* public timeline */
         xs *h = xs_str_localtime(0, "%Y-%m.html");
@@ -1016,13 +1025,20 @@ int html_get_handler(d_char *req, char *q_path, char **body, int *b_size, char *
             status  = 200;
         }
         else {
-            xs *list = timeline_list(&snac, "public", XS_ALL);
-
-            *body   = html_timeline(&snac, list, 1);
+            xs *list = timeline_list(&snac, "public", skip, show);
+
+            *body = html_timeline(&snac, list, 1);
+            if (xs_list_len(list) == show)
+                *body = xs_str_cat(
+                    *body, xs_fmt(
+                        "<p>"
+                        "<a href=\"%s?skip=%d&show=%d\" name=\"snac-more\">More…</a>"
+                        "</p>\n", snac.actor, skip + show, show));
             *b_size = strlen(*body);
             status  = 200;
 
-            history_add(&snac, h, *body, *b_size);
+            if (save)
+                history_add(&snac, h, *body, *b_size);
         }
     }
     else
@@ -1042,13 +1058,20 @@ int html_get_handler(d_char *req, char *q_path, char **body, int *b_size, char *
             else {
                 snac_debug(&snac, 1, xs_fmt("building timeline"));
 
-                xs *list = timeline_list(&snac, "private", XS_ALL);
+                xs *list = timeline_list(&snac, "private", skip, show);
 
                 *body   = html_timeline(&snac, list, 0);
+                if (xs_list_len(list) == show)
+                    *body = xs_str_cat(
+                        *body, xs_fmt(
+                            "<p>"
+                            "<a href=\"%s/admin?skip=%d&show=%d\" name=\"snac-more\">More…</a>"
+                            "</p>\n", snac.actor, skip + show, show));
                 *b_size = strlen(*body);
                 status  = 200;
 
-                history_add(&snac, "timeline.html_", *body, *b_size);
+                if (save)
+                    history_add(&snac, "timeline.html_", *body, *b_size);
             }
         }
     }
@@ -1109,7 +1132,7 @@ int html_get_handler(d_char *req, char *q_path, char **body, int *b_size, char *
     if (strcmp(p_path, ".rss") == 0) {
         /* public timeline in RSS format */
         d_char *rss;
-        xs *elems = timeline_simple_list(&snac, "public", 20);
+        xs *elems = timeline_simple_list(&snac, "public", 0, 20);
         xs *bio   = not_really_markdown(xs_dict_get(snac.config, "bio"));
         char *p, *v;
 
@@ -1202,7 +1225,7 @@ int html_post_handler(d_char *req, char *q_path, d_char *payload, int p_size,
     uid = xs_list_get(l, 1);
     if (!uid || !user_open(&snac, uid)) {
         /* invalid user */
-        srv_log(xs_fmt("html_get_handler bad user %s", uid));
+        srv_log(xs_fmt("html_post_handler bad user %s", uid));
         return 404;
     }
 

+ 1 - 1
main.c

@@ -159,7 +159,7 @@ int main(int argc, char *argv[])
 #endif
 
         xs *idx  = xs_fmt("%s/private.idx", snac.basedir);
-        xs *list = index_list_desc(idx, 256);
+        xs *list = index_list_desc(idx, 0, 256);
         xs *tl   = timeline_top_level(list);
 
         xs *j    = xs_json_dumps_pp(tl, 4);

+ 3 - 3
snac.h

@@ -58,7 +58,7 @@ int index_add(const char *fn, const char *md5);
 int index_del(const char *fn, const char *md5);
 int index_first(const char *fn, char *buf, int size);
 d_char *index_list(const char *fn, int max);
-d_char *index_list_desc(const char *fn, int max);
+d_char *index_list_desc(const char *fn, int skip, int show);
 
 int object_add(const char *id, d_char *obj);
 int object_add_ow(const char *id, d_char *obj);
@@ -85,8 +85,8 @@ d_char *follower_list(snac *snac);
 
 double timeline_mtime(snac *snac);
 int timeline_del(snac *snac, char *id);
-d_char *timeline_simple_list(snac *snac, const char *idx_name, int max);
-d_char *timeline_list(snac *snac, const char *idx_name, int max);
+d_char *timeline_simple_list(snac *snac, const char *idx_name, int skip, int show);
+d_char *timeline_list(snac *snac, const char *idx_name, int skip, int show);
 int timeline_add(snac *snac, char *id, char *o_msg, char *parent, char *referrer);
 void timeline_admire(snac *snac, char *o_msg, char *id, char *admirer, int like);