Browse Source

HTML index generator; simple UID generator; RDF fixes

scossu 3 weeks ago
parent
commit
e35524ebde

+ 10 - 1
config/app.lua

@@ -4,6 +4,12 @@
 local ROOT = os.getenv("PKA_ROOT") or "./"
 local ROOT = os.getenv("PKA_ROOT") or "./"
 
 
 return {
 return {
+    id = {
+        -- Length in ASCII characters of system-generated IDs.
+        len = 16,
+        -- Two seeds for the random ID generator.
+        seed = {256, 512},
+    },
     md = {
     md = {
         -- Single-valued fields. TODO rely on content model cardinality.
         -- Single-valued fields. TODO rely on content model cardinality.
         single_values = {
         single_values = {
@@ -30,10 +36,13 @@ return {
         dc = "http://purl.org/dc/terms/",
         dc = "http://purl.org/dc/terms/",
         foaf = "http://xmlns.com/foaf/0.1/",
         foaf = "http://xmlns.com/foaf/0.1/",
         pas = "http://id.pkar.knowledgetx.com/schema#",
         pas = "http://id.pkar.knowledgetx.com/schema#",
-        par = "http://id.pkar.knowledgetx.com/resource/",
+        par = "urn:pkar:resource/",
         premis = "http://id.loc.gov/vocabulary/preservation/",
         premis = "http://id.loc.gov/vocabulary/preservation/",
         rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
         rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
         rdfs = "http://www.w3.org/2000/01/rdf-schema#",
         rdfs = "http://www.w3.org/2000/01/rdf-schema#",
         xsd = "http://www.w3.org/2001/XMLSchema#",
         xsd = "http://www.w3.org/2001/XMLSchema#",
     },
     },
+    htmlgen = {
+        out_dir = "./out/html",
+    },
 }
 }

+ 0 - 0
out/html/.keep


+ 5 - 3
pocket_archive-scm-1.rockspec

@@ -18,12 +18,13 @@ description = {
         "https://git.knowledgetx.com/scossu/pocket_archive/src/master/LICENSE"
         "https://git.knowledgetx.com/scossu/pocket_archive/src/master/LICENSE"
 }
 }
 dependencies = {
 dependencies = {
-   "lua >= 5.4, < 6",
+   "lua >= 5.4",
 
 
    "csv",
    "csv",
+   "datafile",
+   "etlua",
    "lyaml",
    "lyaml",
    "penlight",
    "penlight",
-   "uuid",
 }
 }
 build = {
 build = {
     type = "builtin",
     type = "builtin",
@@ -31,10 +32,11 @@ build = {
         ["pocket_archive"] = "src/core.lua",
         ["pocket_archive"] = "src/core.lua",
         ["pocket_archive.model_parser"] = "src/model_parser.lua",
         ["pocket_archive.model_parser"] = "src/model_parser.lua",
         ["pocket_archive.submission"] = "src/submission.lua",
         ["pocket_archive.submission"] = "src/submission.lua",
+        ["pocket_archive.html_generator"] = "src/html_generator.lua",
         ["pocket_archive.monocypher"] = {
         ["pocket_archive.monocypher"] = {
             "ext/monocypher/monocypher.c",
             "ext/monocypher/monocypher.c",
             "ext/monocypher/lua_monocypher.c",
             "ext/monocypher/lua_monocypher.c",
         },
         },
     },
     },
-    copy_directories = {"config", "doc",},
+    copy_directories = {"config", "doc", "templates"},
 }
 }

+ 16 - 2
scratch.lua

@@ -1,5 +1,14 @@
-pp = require "pl.pretty"
-sub = require "pocket_archive.submission"
+local pp = require "pl.pretty"
+
+local graph = require "lsup.graph"
+local store = require "lsup.store"
+
+local pkar = require "pocket_archive"
+local sub = require "pocket_archive.submission"
+local hgen = require "pocket_archive.html_generator"
+
+
+local st = store.new(store.MDB, pkar.store_id, true)  -- delete prev archive
 
 
 ---[[
 ---[[
 sip = sub.generate_sip_v2(
 sip = sub.generate_sip_v2(
@@ -7,3 +16,8 @@ sip = sub.generate_sip_v2(
 sub.deposit(sip)
 sub.deposit(sip)
 --]]
 --]]
 
 
+idx = graph.list(pkar.store)
+--assert(#idx == 5)
+
+html = hgen.generate_idx()
+pp.dump(html)

+ 18 - 7
src/core.lua

@@ -1,17 +1,28 @@
+local path = require "pl.path"
+local store = require "lsup.store"
+
 local term = require "lsup.term"
 local term = require "lsup.term"
 local namespace = require "lsup.namespace"
 local namespace = require "lsup.namespace"
-local store = require "lsup.store"
 
 
-config_path = assert(package.searchpath(
-    "app", os.getenv("PA_CONFIG_DIR") or "./config"))
+
+local fpath = debug.getinfo(1, "S").source:sub(2)
+local root_path = path.dirname(path.dirname(fpath))
+local config_path = os.getenv("PA_CONFIG_DIR") or (root_path .. "/config")
 
 
 local M = {
 local M = {
+    root = root_path,
     config = dofile(config_path .. "/app.lua"),
     config = dofile(config_path .. "/app.lua"),
-    nsm = namespace.new()
+    nsm = namespace.new(),
 }
 }
 
 
-M.store_path = os.getenv("PA_BASE") or M.config.fs.dres_path
-for pfx, nsm in pairs(M.config.namespace) do M.nsm:add(pfx, nsm) end
-M.store = store.new(store.MDB, "file://" .. M.store_path)
+M.store_id = "file://" .. (os.getenv("PA_BASE") or M.config.fs.dres_path)
+M.store = store.new(store.MDB, M.store_id)
+
+print(("Default NSM: %s"):format(M.nsm))
+
+for pfx, ns in pairs(M.config.namespace) do M.nsm:add(pfx, ns) end
+
+-- Initialize random ID generator.
+math.randomseed(M.config.id.seed[1], M.config.id.seed[2])
 
 
 return M
 return M

+ 0 - 13
src/generator.lua

@@ -1,13 +0,0 @@
-local graph = require "lsup.graph"
-
-local pkar = require "pocket_archive"
-
-
-local M = {}
-
-M.generate = function()
-
-end
-
-
-return M

+ 33 - 0
src/html_generator.lua

@@ -0,0 +1,33 @@
+local datafile = require "datafile"
+local etlua = require "etlua"
+local pp = require "pl.pretty"
+
+local term = require "lsup.term"
+local graph = require "lsup.graph"
+
+local pkar = require "pocket_archive"
+
+
+local M = {}
+
+M.generate_idx = function()
+    local obj_idx = {}
+    local index_ts = graph.list(pkar.store)
+    for gr_uri in pairs(index_ts) do
+        local obj = {}
+        gr = graph.get(gr_uri, pkar.store)
+        for trp in gr:lookup(gr_uri, term.new_iriref("dc:title")) do
+            if trp.o then obj.title = trp.o end
+        end
+        if obj.title then obj_idx[gr_uri.data] = obj end
+    end
+
+    local fh = datafile.open("templates/index.html")
+    local idx_tpl, err = etlua.compile(fh:read("a"))
+    if not idx then error(err) end
+    pp.dump(obj_idx)
+    print(idx_tpl({obj_idx = obj_idx, term = term}))
+end
+
+
+return M

+ 32 - 14
src/submission.lua

@@ -2,7 +2,6 @@ local io = io
 
 
 local csv = require "csv"
 local csv = require "csv"
 local dir = require "pl.dir"
 local dir = require "pl.dir"
-local uuid = require "uuid"
 local plpath = require "pl.path"
 local plpath = require "pl.path"
 
 
 local term = require "lsup.term"
 local term = require "lsup.term"
@@ -12,12 +11,6 @@ local graph = require "lsup.graph"
 local mc = require "pocket_archive.monocypher"
 local mc = require "pocket_archive.monocypher"
 local pkar = require "pocket_archive"
 local pkar = require "pocket_archive"
 
 
--- Random number generator for uuid()
-local posix_uuid = pcall(function()
-    uuid.set_rng(uuid.rng.urandom())
-end)
--- FIXME
-if not posix_uuid then rng = uuid.set_rng(uuid.rng.win_ffi()) end
 
 
 local M = {}  -- Submission module
 local M = {}  -- Submission module
 
 
@@ -43,6 +36,28 @@ local function escape_pattern(s)
 end
 end
 
 
 
 
+-- For idgen(). Makes a 60-character pool with ~5.9 bits of entropy per char.
+local chpool = {}
+for i = 48, 57  do table.insert(chpool, i) end  -- 0-9
+for i = 65, 90  do table.insert(chpool, i) end  -- A-Z
+for i = 97, 122 do table.insert(chpool, i) end  -- a-z
+
+--[[
+Generate a random, reader-friendly ID.
+
+A 16-character ID with the above defined #chpool of 60 smybols has an entropy
+of 94.5 bits, which should be plenty for a small repository.
+]]
+M.idgen = function(len)
+    local charlist = {}
+    for i = 1, (len or pkar.config.id.len) do
+        table.insert(charlist, string.char(chpool[math.random(1, #chpool)]))
+    end
+
+    return table.concat(charlist)
+end
+
+
 --[=[
 --[=[
 M.generate_sip_v1 = function(path)
 M.generate_sip_v1 = function(path)
     --[[
     --[[
@@ -104,7 +119,7 @@ M.generate_sip_v1 = function(path)
             end
             end
         end
         end
 
 
-        md[ref] = md[ref] or {id = uuid(), path = ref, _sort = i}
+        md[ref] = md[ref] or {id = M.idgen(), path = ref, _sort = i}
         md[ref][k] = md[ref][k] or {}
         md[ref][k] = md[ref][k] or {}
         if k == "type" then
         if k == "type" then
             md[ref][k] = v
             md[ref][k] = v
@@ -157,7 +172,7 @@ M.generate_sip_v2 = function(path)
         if row["path"] ~= "" then
         if row["path"] ~= "" then
             prev_path = row["path"]
             prev_path = row["path"]
             -- New row.
             -- New row.
-            sip[i] = {id = uuid()}
+            sip[i] = {id = M.idgen()}
             for k, v in pairs(row) do
             for k, v in pairs(row) do
                 if v == "" then goto cont1 end  -- skip empty strings.
                 if v == "" then goto cont1 end  -- skip empty strings.
                 if pkar.config.md.single_values[k] then sip[i][k] = v
                 if pkar.config.md.single_values[k] then sip[i][k] = v
@@ -218,12 +233,13 @@ end
 
 
 M.update_rsrc_md = function(rsrc)
 M.update_rsrc_md = function(rsrc)
     -- TODO use a transaction when lsup_lua supports it.
     -- TODO use a transaction when lsup_lua supports it.
-    gr = graph.new(pkar.store, "par:" .. rsrc.id)
-    rsrc.id = nil  -- Exclude from metadata scan.
-
     triples = {}
     triples = {}
-    local s = term.new_iriref("")
+
+    local s = term.new_iriref("par:" .. rsrc.id, pkar.nsm)
+    gr = graph.new(pkar.store, s.data, pkar.nsm)
+    rsrc.id = nil  -- Exclude from metadata scan.
     for k, v in pairs(rsrc) do
     for k, v in pairs(rsrc) do
+        print("Adding attribute:", k, v)
         local p = term.new_iriref(k, pkar.nsm)
         local p = term.new_iriref(k, pkar.nsm)
         if type(v) == "table" then
         if type(v) == "table" then
             for vv, _ in pairs(v) do
             for vv, _ in pairs(v) do
@@ -235,6 +251,8 @@ M.update_rsrc_md = function(rsrc)
     print("Removing triples.")
     print("Removing triples.")
     gr:remove();
     gr:remove();
     print("Adding triples.")
     print("Adding triples.")
+    -- TODO implement lsup_lua fn to add a single triple and add triples in
+    -- the previous loop.
     gr:add(triples)
     gr:add(triples)
 end
 end
 
 
@@ -284,7 +302,7 @@ M.deposit = function(sip)
             out_path = out_dir .. checksum:sub(1,32)
             out_path = out_dir .. checksum:sub(1,32)
             rsrc.path = out_path
             rsrc.path = out_path
             dir.makepath(out_dir)
             dir.makepath(out_dir)
-            print(("Moving file %s t %s"):format(tmp_path, rsrc.path))
+            print(("Moving file %s to %s"):format(tmp_path, rsrc.path))
             dir.movefile(tmp_path, rsrc.path)
             dir.movefile(tmp_path, rsrc.path)
         end
         end
 
 

+ 26 - 0
templates/index.html

@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Pocket Archive</title>
+    </head>
+    <body>
+        <header></header>
+        <main>
+            <section id="obj_list">
+                <ul>
+                <% for uri, data in pairs(obj_idx) do %>
+                    <li class="obj_link">
+                        <a href="<%= uri %>">
+                            <%= data.title.data %>
+                            <%if data.title.lang then %>
+                                <span class="langtag"><%= data.title.lang %></span>
+                            <% end %>
+                        </a>
+                    </li>
+                <% end %>
+                </ul>
+            </section>
+        </main>
+        <footer></footer>
+    </body>
+</html>

+ 0 - 0
test/sample_submission/postcard-bag/data/12345/12345-back/567890.jpg → test/sample_submission/postcard-bag/data/0001/0001-back/567890.jpg


+ 0 - 0
test/sample_submission/postcard-bag/data/12345/12345-front/54321.jpg → test/sample_submission/postcard-bag/data/0001/0001-front/54321.jpg


BIN
test/sample_submission/postcard-bag/data/0006/0685_04.jpg


+ 7 - 5
test/sample_submission/postcard-bag/data/submission-v2.csv

@@ -1,8 +1,10 @@
 "path","dc:identifier","dc:type","dc:title","dc:alternative","dc:description"
 "path","dc:identifier","dc:type","dc:title","dc:alternative","dc:description"
-12345,0001,"Postcard","Example Postcard","This is an alternative label","Note that recto and verso representations have been named front and back, to emphasize that the ordering is not alphabetical."
+0001,0001,"Postcard","Example Postcard","This is an alternative label","Note that recto and verso representations have been named front and back, to emphasize that the ordering is not alphabetical."
 ,,,,"And this is another alternative label","Second description."
 ,,,,"And this is another alternative label","Second description."
 ,,,,"Yet another alt label.",
 ,,,,"Yet another alt label.",
-"12345/12345-front",0002,"Part","Recto",,
-"12345/12345-front/54321.jpg",0003,"StillImage",,,
-"12345/12345-back",0004,"Part","Verso",,
-"12345/12345-back/567890.jpg",0005,"StillImage",,,
+"0001/0001-front",0002,"Part","Recto",,
+"0001/0001-front/54321.jpg",0003,"StillImageFile",,,
+"0001/0001-back",0004,"Part","Verso",,
+"0001/0001-back/567890.jpg",0005,"StillImageFile",,,
+0006,0006,"StillImage","Single Image",,"Preparing kebab at Aqil's during curfew."
+0006/0685_04.jpg,0007,"StillImageFile","Nablus 2002",,