Check-in by ben on 2024-10-05 22:44:03

 Improve the display of user lists. Show item creator, title, etc
 rather than the bare item id. Paginate list items. Add "back
 link" to account that owns the list.

 INSERTED    DELETED
      119         13 src/list/index.dcgi.m4
        1         10 src/search/index.dcgi.m4
       10          0 src/util.awk
      130         23 TOTAL over 3 changed files

Index: src/list/index.dcgi.m4
==================================================================
--- src/list/index.dcgi.m4
+++ src/list/index.dcgi.m4
@@ -8,14 +8,27 @@
include(src/config.awk)
incl(src/api.awk)
incl(src/cgi.awk)
incl(src/util.awk)

-function main(     acct, cmd, count, iaout, id, is_private, item_id,
-    label, list_id, name, parts, url)
+function main(     acct, client_url, cmd, count, creator, iaout, id,
+    is_private, items, label, list_id, name, name_slug, numfound,
+    page, pages, rows, query, title, type, url)
{
-    count = split(search, parts, "/")
+    rows = 15
+    page = 1
+
+    # parse out page number
+    for (i in parts) {
+        if (parts[i] ~ /^rows[0-9][0-9]*$/) {
+            rows = substr(parts[i], 5)
+        } else if (parts[i] ~ /^page[0-9][0-9]*$/) {
+            page = substr(parts[i], 5)
+        }
+    }
+
+    split(search, parts, "/")
    acct = parts[1]
    list_id = parts[2]

    print acct "'s Lists"
    print ""
@@ -23,39 +36,131 @@
    iaout = gettemp()

    url = api_ssl_endpoint "/services/users/" acct "/lists/" list_id
    api_request(url, "GET", iaout)

-    # format list as a gopher directory (menu)
+    # fetch identifiers of list members
+
    cmd = sprintf("%s <%s 2>&1", cmd_json2tsv, iaout)
    FS = "\t"
-    name = ""
-    id = 0
+    id = ""
    is_private = 0
-    item_id = ""
+    name = ""
+    numfound = 0
+    query = ""

    while ((cmd | getline) > 0) {
        if ($1 == ".value.list_name" && $2 == "s") {
            name = $3
-            print "# List: " name
-            id = 0
            is_private = 0
        } else if ($1 == ".value.is_private" && $2 == "b") {
            if ($3 == "true") {
                is_private = 1
            }
        } else if ($1 == ".value.members[].identifier" && $2 == "s") {
            if (!is_private) {
-                item_id = $3
-                label = shorten_left(item_id, 60)
-                printf "[1|%s|%s/details/%s|%s|%s]\n", label,
-                    cgipath, item_id, server, port
+                id = $3
+                numfound++
+                if (length(query) == 0) {
+                    query = id
+                } else {
+                    query = query "+OR+" id
+                }
+            }
+        }
+    }
+    close(cmd)
+    unlink(iaout)
+
+    # get metadata of list member items
+
+    name_slug = uri_encode(name)
+    gsub(/%20/, "-", name_slug)
+    client_url = api_ssl_endpoint "/details/" acct "/lists/" list_id \
+        "/" name_slug
+    url = api_ssl_endpoint "/services/search/beta/page_production/" \
+        "?user_query=identifier:(" query ")"                        \
+        "&hits_per_page=" rows                                      \
+        "&page=" page                                               \
+        "&aggregations=false"                                       \
+        "&client_url=" client_url
+    api_request(url, "GET", iaout)
+
+    pages = int(numfound / rows)
+    if (numfound % rows != 0) {
+        pages++
+    }
+
+    # format as a gopher directory (menu)
+
+    printf "# List: %s, page %d of %d\n", name, page, pages
+    print ""
+
+    cmd = sprintf("%s <%s 2>&1", cmd_json2tsv, iaout)
+    FS = "\t"
+    count = 0
+    creator = ""
+    id = ""
+    title = ""
+    type = ""
+    while ((cmd | getline) > 0) {
+        if ($1 == ".response.body.hits.hits[].fields.creator[]" &&
+            $2 == "s" && length(creator) == 0)
+        {
+            creator = $3
+        } else if ($1 == ".response.body.hits.hits[].fields.identifier" &&
+            $2 == "s")
+        {
+            id = $3
+        } else if ($1 == ".response.body.hits.hits[].fields.mediatype" &&
+            $2 == "s")
+        {
+            type = $3
+        } else if ($1 == ".response.body.hits.hits[].fields.title" &&
+            $2 == "s")
+        {
+            title = $3
+        } else if ($1 == ".response.body.hits.hits[]._score" && $2 == "a") {
+            # the _score field happens to be toward the end of each item
+            if (length(title) > 0) {
+                if (length(creator) > 0) {
+                    label = sprintf("[%s] %s by %s", mediatype[type], \
+                        gph_encode(shorten(title, 40)), shorten(creator, 18))
+                } else {
+                    label = sprintf("[%s] %s", mediatype[type], \
+                        gph_encode(shorten(title, 58)))
+                }
+                printf "[1|%s|%s/details/%s|%s|%s]\n", label, cgipath, id,
+                    server, port
+                count++
            }
+            creator = ""
+            descr = ""
+            id = ""
+            type = ""
        }
    }
    close(cmd)

+    # only show "page back" if the user is past page 1
+    if (page > 1) {
+        printf "[1|[<<] Page %d|%s/list/page%d/rows%d/%%09%s/%d|%s|%s]\n",
+            page - 1, cgipath, page - 1, rows,
+            acct, list_id, server, port
+    }
+
+    # only show "next page" if the current page is completely full
+    if (count == rows) {
+        printf "[1|[>>] Page %d|%s/list/page%d/rows%d/%%09%s/%d|%s|%s]\n",
+            page + 1, cgipath, page + 1, rows,
+            acct, list_id, server, port
+    }
+
+    print ""
+    printf "[1|Account %s|%s/account/%s|%s|%s]\n", acct, cgipath,
+        acct, server, port
+
    print ""
    printf "[1|PHAROS|%s|%s|%s]\n", cgipath, server, port

    unlink(iaout)
    exit 0
@@ -64,7 +169,8 @@
BEGIN {
    config_init()

    cgi_init()
    uri_encode_init()
+    util_init()
    main()
}

Index: src/search/index.dcgi.m4
==================================================================
--- src/search/index.dcgi.m4
+++ src/search/index.dcgi.m4
@@ -12,20 +12,10 @@

function main(search,     cmd, count, creator, descr, field, fields, i, \
    iaout, id, jsout, label, numfound, order, orders, page, rows,       \
    searchstr, title, type, url)
{
-    mediatype["audio"]      = "aud"
-    mediatype["collection"] = "col"
-    mediatype["data"]       = "dat"
-    mediatype["etree"]      = "aud"
-    mediatype["image"]      = "img"
-    mediatype["movies"]     = "mov"
-    mediatype["software"]   = "bin"
-    mediatype["texts"]      = "txt"
-    mediatype["web"]        = "web"
-
    rows = 15
    page = 1
    delete order
    orders = 0

@@ -144,10 +134,11 @@
        } else if ($1 == ".response.docs[].identifier" && $2 == "s") {
            id = $3
        } else if ($1 == ".response.docs[].mediatype" && $2 == "s") {
            type = $3
        } else if ($1 == ".response.docs[].title" && $2 == "s") {
+            # the title field happens to be toward the end of each item
            title = $3
            count++
            if (length(creator) > 0) {
                label = sprintf("[%s] %s by %s", mediatype[type], \
                    gph_encode(shorten(title, 40)), shorten(creator, 18))

Index: src/util.awk
==================================================================
--- src/util.awk
+++ src/util.awk
@@ -166,10 +166,20 @@
        "Attribution-NonCommercial 4.0 International"
    licenseurl["https://creativecommons.org/licenses/by-nc-sa/4.0/"] = \
        "Attribution-NonCommercial-ShareAlike 4.0 International"
    licenseurl["https://creativecommons.org/licenses/by-nc-nd/4.0/"] = \
        "Attribution-NonCommercial-NoDerivs 4.0 International"
+
+    mediatype["audio"]      = "aud"
+    mediatype["collection"] = "col"
+    mediatype["data"]       = "dat"
+    mediatype["etree"]      = "aud"
+    mediatype["image"]      = "img"
+    mediatype["movies"]     = "mov"
+    mediatype["software"]   = "bin"
+    mediatype["texts"]      = "txt"
+    mediatype["web"]        = "web"

    size_kb = 1024
    size_mb = 1024 * 1024
    size_gb = 1024 * 1024 * 1024
    return