Ver Fonte

HTML index generator; simple UID generator; RDF fixes

scossu há 3 semanas atrás
pai
commit
e35524ebde

+ 10 - 1
config/app.lua

@@ -4,6 +4,12 @@
 local ROOT = os.getenv("PKA_ROOT") or "./"
 
 return {
+    id = {
+        -- Length in ASCII characters of system-generated IDs.
+        len = 16,
+        -- Two seeds for the random ID generator.
+        seed = {256, 512},
+    },
     md = {
         -- Single-valued fields. TODO rely on content model cardinality.
         single_values = {
@@ -30,10 +36,13 @@ return {
         dc = "http://purl.org/dc/terms/",
         foaf = "http://xmlns.com/foaf/0.1/",
         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/",
         rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
         rdfs = "http://www.w3.org/2000/01/rdf-schema#",
         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"
 }
 dependencies = {
-   "lua >= 5.4, < 6",
+   "lua >= 5.4",
 
    "csv",
+   "datafile",
+   "etlua",
    "lyaml",
    "penlight",
-   "uuid",
 }
 build = {
     type = "builtin",
@@ -31,10 +32,11 @@ build = {
         ["pocket_archive"] = "src/core.lua",
         ["pocket_archive.model_parser"] = "src/model_parser.lua",
         ["pocket_archive.submission"] = "src/submission.lua",
+        ["pocket_archive.html_generator"] = "src/html_generator.lua",
         ["pocket_archive.monocypher"] = {
             "ext/monocypher/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(
@@ -7,3 +16,8 @@ sip = sub.generate_sip_v2(
 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 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 = {
+    root = root_path,
     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

+ 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 dir = require "pl.dir"
-local uuid = require "uuid"
 local plpath = require "pl.path"
 
 local term = require "lsup.term"
@@ -12,12 +11,6 @@ local graph = require "lsup.graph"
 local mc = require "pocket_archive.monocypher"
 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
 
@@ -43,6 +36,28 @@ local function escape_pattern(s)
 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)
     --[[
@@ -104,7 +119,7 @@ M.generate_sip_v1 = function(path)
             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 {}
         if k == "type" then
             md[ref][k] = v
@@ -157,7 +172,7 @@ M.generate_sip_v2 = function(path)
         if row["path"] ~= "" then
             prev_path = row["path"]
             -- New row.
-            sip[i] = {id = uuid()}
+            sip[i] = {id = M.idgen()}
             for k, v in pairs(row) do
                 if v == "" then goto cont1 end  -- skip empty strings.
                 if pkar.config.md.single_values[k] then sip[i][k] = v
@@ -218,12 +233,13 @@ end
 
 M.update_rsrc_md = function(rsrc)
     -- 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 = {}
-    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
+        print("Adding attribute:", k, v)
         local p = term.new_iriref(k, pkar.nsm)
         if type(v) == "table" then
             for vv, _ in pairs(v) do
@@ -235,6 +251,8 @@ M.update_rsrc_md = function(rsrc)
     print("Removing triples.")
     gr:remove();
     print("Adding triples.")
+    -- TODO implement lsup_lua fn to add a single triple and add triples in
+    -- the previous loop.
     gr:add(triples)
 end
 
@@ -284,7 +302,7 @@ M.deposit = function(sip)
             out_path = out_dir .. checksum:sub(1,32)
             rsrc.path = out_path
             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)
         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"
-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."
 ,,,,"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",,