diff --git a/.gitignore b/.gitignore index 16c31aef..0ab9b85d 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,9 @@ __pycache__/ # internal edoc/resources/xsl/xspec/ .existdb.json +edoc/rest2/v2.json # node-reladted stuff node_modules/ +.codex diff --git a/.gitmodules b/.gitmodules index 12fc6c69..e86326c7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "edoc/include/xstring"] - path = edoc/include/xstring - url = https://github.com/dariok/XStringUtils [submodule "edoc/include/wdbmeta"] path = edoc/include/wdbmeta url = https://github.com/dariok/wdbmeta diff --git a/README.md b/README.md index a09379b8..6d5184f5 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,47 @@ This framework still lacks a good name. If you have an idea, please let me know! ## Incompatible changes +### 25Q3 + +Release 25Q3 dropped support for more unsued functions: +- `wdb:getFilePath ( $id as xs:string )`: use the map from `wdbFiles:getFullPath` instead +- the default layout of all `resources` collections has changed to group files by type. This also affects the main + project specific overrides, i.e. `project.js` and `project.css`. An XQuery is provided to move all files to their + appropriate new locations (TODO: add file name here). + This also affects `edoc/data/resources` and `edoc/resources` so you might have to change imports manually if you make + use of any file in these collections. + +Changes in standard behaviour +- sub-projects will now make use of process inheritance; i.e., they only define empty `processes` with no `command`. A + `command` is then picked by traversing up through parent `wdbmeta.xml` (i.e., one that is pointed to by a + `struct/import`; worst case: data). This way, you can still have different `command` defined for sub-projects (and + their children) but do not need to change the path for every sub-project. +- as part of this, no XSLTs are being copied to `{$subproject}/resources` as inheritance is now the standard. This way, + surplus XSLTs do not have to be deleted or kept up to date. As said above, it is still possible to create a `command` + for this sub-project tree and create specific XSLTs (usually by including the main XSLTs) +- standard XSLTs for a new project are now bare: they only include `/edoc/data/resources/xslt/{$currentFileName}`, and + `tei-common.xsl` (unless it’s common itself). + +### 24Q4 + +Release 24Q4 dropped another set of functions that were unused: +- `wdb:getEdFromFileID( $id as xs:string )`: `(wdbFiles:getFullPath($id))?projectPath` returns the base path to `wdbmeta.xml` +- `wdb:getMetaElementFromEd ( $ed as xs:string )`: use + `doc( (doc("/db/apps/edoc/index/project-index.xml")/id($ed))/@path || '/wdbmeta.xml' )/id($ed)[self::meta:projectMD]` instead +- `wdb:getMetaFile( $pathToEd )`: `(wdbFiles:getFullPath($ed))?projectPath` returns the base path to `wdbmeta.xml` +- `wdb:getProjectPathFromId ( $ed )`: use `(wdbFiles:getFullPath($ed))?projectPath` instead + +### 24Q2 + +Release 24Q2 dropped functions `wdb:getEdPath( $ed as xs:string , $absolute as xs:boolean() )`, +`wdb:getEdPath( $ed as xs:string )`, and `wdb:findProjectXQM( $project )`. These queries can be replaced by +`(wdbFiles:getFullPath($id))` which returns a map with `projectPath` (the path to the project, i.e. the collection where +`wdbmeta.xml`¹ is stored), `collectionPath` (for the subcollection where a file is actually located), `mainProject` for +the path to the project containing `project.xqm`, and `fileName`. +1) (24Q4): this corrects a typo as previous versions incorrectly read `project.xqm`. + +### 24Q1 + Release 24Q1 dropped support for METS-based projects. As METS files can have a number of very different ways of encoding information, especially when it comes to behaviours, native support is hard to achieve. At the same time, most installations use wdb+’s native wdbmeta system as this is what the admin functions work with. @@ -64,9 +105,11 @@ into `/db/apps/edoc` and want to put your projects into `/db/apps/edoc/data/your - - /db/apps/edoc/resources/xsl/tei-transcript.xsl - + + + /db/apps/edoc/resources/xsl/tei-transcript.xsl + + @@ -89,12 +132,15 @@ See the Wiki for details! * HAB Wolfenbüttel * Editionsprojekt Karlstadt -* ACDH Wien - * Wien[n]erisches Diarium Digital - * Repertotium frühneuzeitlicher Rechtsquellen - * Protokolle der Sitzungen der Gesamtakadmie * Akademie der Wissenschaften, Heidelberg * Theologenbriefwechsel * ULB Darmstadt + * TUEditions + * WDM If you use wdbplus for your editions, please drop me a message so I can add you to this list. + +## Sponsoring + +Development of wdb+ is chiefly done in projects funded by DFG and the German BMBF. +Additionally, we would like to say thank you to BrowserStack for giving us sponsored access! diff --git a/build.xml b/build.xml index d1a0ed34..40d61c3d 100644 --- a/build.xml +++ b/build.xml @@ -1,23 +1,25 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + diff --git a/addins/do-not-remove b/edoc/addins/do-not-remove similarity index 100% rename from addins/do-not-remove rename to edoc/addins/do-not-remove diff --git a/edoc/admin/admin.xqm b/edoc/admin/admin.xqm index 7f9aaa44..e2feb608 100644 --- a/edoc/admin/admin.xqm +++ b/edoc/admin/admin.xqm @@ -2,73 +2,61 @@ xquery version "3.1"; module namespace wdbAdmin = "https://github.com/dariok/wdbplus/Admin"; -import module namespace console = "http://exist-db.org/xquery/console" at "java:org.exist.console.xquery.ConsoleModule"; -import module namespace templates = "http://exist-db.org/xquery/html-templating"; -import module namespace wdb = "https://github.com/dariok/wdbplus/wdb" at "/db/apps/edoc/modules/app.xqm"; -import module namespace wdbErr = "https://github.com/dariok/wdbplus/errors" at "/db/apps/edoc/modules/error.xqm"; +import module namespace config = "https://github.com/dariok/wdbplus/config" at "../modules/wdb-config.xqm"; +import module namespace wdbErr = "https://github.com/dariok/wdbplus/errors" at "../modules/error.xqm"; +import module namespace wdbm = "https://github.com/dariok/wdbplus/model" at "../modules/model.xqm"; -declare namespace meta = "https://github.com/dariok/wdbplus/wdbmeta"; -declare namespace sm = "http://exist-db.org/xquery/securitymanager"; +declare namespace meta = "https://github.com/dariok/wdbplus/wdbmeta"; +declare namespace sm = "http://exist-db.org/xquery/securitymanager"; +declare namespace templates = "http://exist-db.org/xquery/html-templating"; +declare namespace wdb = "https://github.com/dariok/wdbplus/wdb"; (:~ - : populate the model for functions pages (similar but not identical to wdb:populateModel) + : populate the model for admin pages : : @param $ed The ID of a _project_ : @return The model :) declare - %templates:default("ed", "") -function wdbAdmin:start ( $node as node(), $model as map(*), $ed as xs:string ) { - try { - let $pathToEd := if ( $ed = "" ) - then $wdb:data - else wdb:getEdPath($ed, true()) - - (: The meta data are taken from wdbmeta.xml :) - let $infoFileLoc := wdb:getMetaFile($pathToEd) - , $title := normalize-space((doc($infoFileLoc)//meta:title)[1]) - - return map { - "ed": if ( $pathToEd = $wdb:data ) then "data" else $ed, - "infoFileLoc": $infoFileLoc, - "page": substring-after(request:get-uri(), "admin/"), - "pathToEd": $pathToEd, - "title": $title, - "auth": sm:id()/sm:id - } - } catch * { - util:log("error", "No collection found for project ID " || $ed), - map { - "ed": "" - } - } + %templates:default("ed", "data") +function wdbAdmin:start ( $node as node(), $model as map(*), $ed as xs:string ) as item()* { + wdbm:populateModel((), $ed, "", "", "") }; -declare function wdbAdmin:getEd ( $node as node(), $model as map(*) ) as element(meta) { - -}; +declare function wdbAdmin:getEd ( $node as node(), $model as map(*) ) as item()+ {( + comment { "Created in admin.xqm for "|| $node/@data-template }, + , + +)}; -declare function wdbAdmin:heading ($node as node(), $model as map(*)) { +declare function wdbAdmin:heading ( $node as node(), $model as map(*) ) as element()+ { let $opts := if (request:get-parameter('job', '') != '') then globale Optionen else () return ( +

{ - if ($model?page = 'admin.html') - then "Admin-Seite" - else if ($model?page = 'global.html') - then "Globale Einstellungen" - else if ($model?ed = '') - then "Projekte" - else ("Projekt ", {$model?title}, " (" || $model?ed || ")") + comment { "Created in admin.xqm for "|| $node/@data-template }, + if ($model?page = 'admin.html') then + "Admin-Seite" + else if ($model?page = 'global.html') then + "Globale Einstellungen" + else if ($model?ed = '') then + "Projekte" + else ( + "Projekt ", + {$model?title}, + " (" || $model?ed || ")" + ) }

, $opts ) }; -declare function wdbAdmin:getAside ($node as node(), $model as map(*)) as element() { +declare function wdbAdmin:getAside ( $node as node(), $model as map(*) ) as element() { }; -declare function wdbAdmin:css ( $node as node(), $model as map(*) ) as element()* { - if ( unparsed-text-available($wdb:data || "/resources/wdb.css") ) - then +declare function wdbAdmin:css ( $node as node(), $model as map(*) ) as item()* { + comment { "Created in admin.xqm for "|| $node/@data-template }, + if ( unparsed-text-available($config:data || "/resources/css/wdb.css") ) + then else (), - if ( unparsed-text-available($wdb:data || "/resources/admin.css") ) - then + if ( unparsed-text-available($config:data || "/resources/css/admin.css") ) + then else () }; diff --git a/edoc/admin/directoryForm.html b/edoc/admin/directoryForm.html index 61c9f547..47a138b1 100644 --- a/edoc/admin/directoryForm.html +++ b/edoc/admin/directoryForm.html @@ -1,29 +1,27 @@
-

Funktion

-
-
- Verzeichnis ohne Eintragen in wdbmeta
- Verzeichnis mit Eintragen in wdbmeta
- Datei(en) ohne Eintragen in wdbmeta
- Datei(en) mit Eintragen in wdbmeta
+

Funktion

+ +
+ Verzeichnis(se) (relative Pfade)
+ Datei(en)
-
- -
-      
- - -
-
- - -
- - -

- loading -

- +
+ +
+         
+ + +
+
+ + +
+ + +

+ loading +

+
diff --git a/edoc/admin/global.xqm b/edoc/admin/global.xqm index 1e759203..ecc8b735 100644 --- a/edoc/admin/global.xqm +++ b/edoc/admin/global.xqm @@ -1,22 +1,19 @@ -xquery version "3.0"; +xquery version "3.1"; module namespace wdbGS = "https://github.com/dariok/wdbplus/GlobalSettings"; -import module namespace wdb = "https://github.com/dariok/wdbplus/wdb" at "../modules/app.xqm"; -import module namespace console = "http://exist-db.org/xquery/console"; +import module namespace config = "https://github.com/dariok/wdbplus/config" at "../modules/wdb-config.xqm"; -declare namespace config = "https://github.com/dariok/wdbplus/config"; declare namespace exgit = "http://exist-db.org/xquery/exgit"; declare namespace meta = "https://github.com/dariok/wdbplus/wdbmeta"; declare namespace system = "http://exist-db.org/xquery/system"; -declare function wdbGS:getRest ( $node as node(), $model as map(*) ) { - +declare function wdbGS:getRest ( $node as node(), $model as map(*) ) as element(meta) { + $config:restMetaElement }; declare function wdbGS:body ( $node as node(), $model as map(*) ) { let $param := request:get-parameter('job', 'main') - let $metaFile := doc('../config.xml') return switch ( $param ) case 'main' return @@ -32,24 +29,24 @@ declare function wdbGS:body ( $node as node(), $model as map(*) ) { case 'title' return - local:titleForm($metaFile) + local:titleForm($config:configFile) case 'chgTitle' return - let $u1 := update replace $metaFile//config:meta/config:name + let $u1 := update replace $config:configFile//config:meta/config:name with {request:get-parameter('longTitle', '')} - let $u1 := update replace $metaFile//config:meta/config:short + let $u1 := update replace $config:configFile//config:meta/config:short with {request:get-parameter('shortTitle', '')} - return local:titleForm($metaFile) + return local:titleForm($config:configFile) case 'role' return - local:roleForm($metaFile) + local:roleForm($config:configFile) case 'chgRole' return - let $u1 := update replace $metaFile//config:role/config:type + let $u1 := update replace $config:configFile//config:role/config:type with {request:get-parameter('role', '')} - let $u1 := update replace $metaFile//config:role/config:other + let $u1 := update replace $config:configFile//config:role/config:other with {request:get-parameter('other', '')} - return local:roleForm($metaFile) + return local:roleForm($config:configFile) default return
@@ -58,23 +55,23 @@ declare function wdbGS:body ( $node as node(), $model as map(*) ) {
}; -declare function local:titleForm($metaFile) { +declare function local:titleForm($config:configFile) {

Titeldaten verändern


+ value="{$config:configFile//config:meta/config:name}" />

+ value="{$config:configFile//config:meta/config:short}" />
}; -declare function local:roleForm($metaFile) { - let $role := $metaFile//config:role/config:type - let $other := $metaFile//config:role/config:other +declare function local:roleForm($config:configFile) { + let $role := $config:configFile//config:role/config:type + let $other := $config:configFile//config:role/config:other return
@@ -85,7 +82,7 @@ declare function local:roleForm($metaFile) {

@@ -95,5 +92,5 @@ declare function local:roleForm($metaFile) { }; declare function wdbGS:ingest($node as node(), $model as map(*)) { - bestehendes Projekt hochladen -}; \ No newline at end of file + bestehendes Projekt hochladen +}; diff --git a/edoc/admin/modelFunctions.xql b/edoc/admin/modelFunctions.xql index a7cd83b4..75d05bd2 100644 --- a/edoc/admin/modelFunctions.xql +++ b/edoc/admin/modelFunctions.xql @@ -2,6 +2,9 @@ xquery version "3.1"; module namespace trigger="http://exist-db.org/xquery/trigger"; +declare namespace meta = "https://github.com/dariok/wdbplus/wdbmeta"; +declare namespace index = "https://github.com/dariok/wdbplus/index"; + declare function trigger:after-update-document ( $uri as xs:anyURI ) as xs:string { if ( ends-with($uri, 'instance.xqm') or ends-with($uri, 'project.xqm') ) then let $projectPath := if ( ends-with($uri, 'instance.xqm') ) @@ -12,5 +15,59 @@ declare function trigger:after-update-document ( $uri as xs:anyURI ) as xs:strin else 'project-functions.xml' return xmldb:store($projectPath, $statFileName, inspect:inspect-module($uri)) + else if ( ends-with($uri, 'wdbmeta.xml') ) then + let $meta := doc($uri) + , $projectId := $meta/meta:projectMD/@xml:id + , $files := $meta//meta:file + , $title := $meta//meta:title[@type='main'] + , $projectIndex := doc("/db/apps/edoc/index/project-index.xml") + , $fileIndex := doc("/db/apps/edoc/index/file-index.xml") + , $projectEntry := + + (: enter or update project :) + let $insertProject := if ( exists($projectIndex/id($projectId)) ) + then update replace $projectIndex/id($projectId) with $projectEntry + else update insert $projectEntry into $projectIndex/index:index + + (: enter or update files entries :) + let $entries := for $file in $files + let $id := $file/@xml:id + , $entry := + + return if ( exists($fileIndex/id($id)) ) + then update replace $fileIndex/id($id) with $entry + else update insert $entry into $fileIndex/index:index + + (: enter or update subcorpora :) + let $subcorpora := for $subcorpus in $meta//meta:struct[@xml:id] + let $id := $subcorpus/@xml:id + , $entry := + + return if ( exists($fileIndex/id($id)) ) + then update replace $fileIndex/id($id) with $entry + else update insert $entry into $fileIndex/index:index + + return $uri + (: else if ( ends-with($uri, '.xml') ) then + let $id := doc($uri)/*/@xml:id + , $present := doc("/db/apps/edoc/index/file-index.xml")/id($id) + , $entry := + , $insert := if ( $present ) + then update replace $present with $entry + else update insert $entry into doc("/db/apps/edoc/index/file-index.xml")/* + return $uri :) else "" }; diff --git a/edoc/admin/new.xqm b/edoc/admin/new.xqm index 540770d6..99b27f7b 100644 --- a/edoc/admin/new.xqm +++ b/edoc/admin/new.xqm @@ -1,108 +1,48 @@ -xquery version "3.0"; +xquery version "3.1"; module namespace wdbPN = "https://github.com/dariok/wdbplus/ProjectNew"; -import module namespace wdb = "https://github.com/dariok/wdbplus/wdb" at "/db/apps/edoc/modules/app.xqm"; -import module namespace wdbRc = "https://github.com/dariok/wdbplus/RestCollections" at "/db/apps/edoc/rest/rest-coll.xql"; -import module namespace sm = "http://exist-db.org/xquery/securitymanager"; +import module namespace sm = "http://exist-db.org/xquery/securitymanager"; -declare namespace config = "https://github.com/dariok/wdbplus/config"; -declare namespace http = "http://expath.org/ns/http-client"; -declare namespace map = "http://www.w3.org/2005/xpath-functions/map"; -declare namespace meta = "https://github.com/dariok/wdbplus/wdbmeta"; -declare namespace tei = "http://www.tei-c.org/ns/1.0"; +declare namespace http = "http://expath.org/ns/http-client"; +declare namespace map = "http://www.w3.org/2005/xpath-functions/map"; +declare namespace meta = "https://github.com/dariok/wdbplus/wdbmeta"; +declare namespace tei = "http://www.tei-c.org/ns/1.0"; declare function wdbPN:body ( $node as node(), $model as map(*), $pName as xs:string*, $pShort as xs:string*, - $pID as xs:string*, $pColl as xs:string*, $pDate as xs:string*, $pDesc as xs:string*, $pLic as xs:string* ) { - let $user := sm:id() - - return if (not($user//sm:group = 'dba')) + $pID as xs:string*, $collection as xs:string* ) + (:), $pDate as xs:string*, $pDesc as xs:string*, $pLic as xs:string*, $data as xs:string* ) to be implemented later when a UI for project MD exists :) + as element() { + if ( not(sm:id()//sm:group = 'dba') ) then

Diese Seite ist nur für Administratoren zugänglich!

- else if (0 = (string-length($pName), string-length($pID), string-length($pColl))) + else if (0 = (string-length($pName), string-length($pID), string-length($collection))) then -
-
-
-
-
-
+ +
+
+
+
+ + else - let $collectionData := - - {$pName} - {$pID} - {$pColl} - - - let $targetCollection := if ( $model?ed eq '' ) then 'data' else $model?ed - , $create := wdbRc:createSubcollectionXml ($collectionData, $targetCollection) - - return if ( ($create)[1]//http:response/@status = '201') - then - let $collection-uri := $create[2] - let $textCollection := xmldb:create-collection($collection-uri, "texts") - let $resourcesCollection := xmldb:create-collection($collection-uri, "resources") - let $metaFile := $collection-uri || "/wdbmeta.xml" - - let $copy := if (system:function-available(xs:QName("xmldb:copy-collection"), 2)) - then util:eval("xmldb:copy-collection($source, $destination)", false(), ( - xs:QName("source"), $wdb:edocBaseDB || "/resources/xsl", - xs:QName("destination"), $collection-uri - )) - else util:eval("xmldb:copy($source, $destination)", false(), ( - xs:QName("source"), $wdb:edocBaseDB || "/resources/xsl", - xs:QName("destination"), $collection-uri - )) - - let $chmod := ( - sm:chmod(xs:anyURI($collection-uri), 'rwxrwxr-x'), - sm:chmod(xs:anyURI($textCollection), 'rwxrwxr-x'), - sm:chmod(xs:anyURI($resourcesCollection), 'rwxrwxr-x'), - sm:chmod(xs:anyURI($metaFile), 'rw-rw-r--'), - sm:chmod(xs:anyURI($collection-uri || "/xsl"), "rwxrwxr-x"), - sm:chown(xs:anyURI($collection-uri), "wdb:wdbusers"), - sm:chown(xs:anyURI($textCollection), "wdb:wdbusers"), - sm:chown(xs:anyURI($resourcesCollection), "wdb:wdbusers"), - sm:chown(xs:anyURI($metaFile), "wdb:wdbusers"), - sm:chown(xs:anyURI($collection-uri || "/xsl"), "wdb:wdbusers"), - for $f in xmldb:get-child-resources($collection-uri || "/xsl") - return ( - sm:chmod(xs:anyURI($collection-uri || "/xsl/" || $f), "rwxrwxr-x"), - sm:chown(xs:anyURI($collection-uri || "/xsl/" || $f), "wdb:wdbusers") - ) - ) - - let $MD := doc($metaFile) - let $addMD := ( - if ($pShort != "") - then - update insert {$pShort} into $MD//meta:titleData - else (), - if ($pDate != "") - then - update insert {$pDate} into $MD//meta:titleData - else (), - if ($pLic != "") - then - update insert {$pLic} into $MD//meta:legal - else () - ) - - return -
-
Collection
-
{$create[2]}
-
wdbmeta.xml:
-
{$metaFile}
-
Admin
-
Upload
-
- else $create +
+
Collection
+
{ $collection }
+
Name
+
{ $pName }
+
Short title
+
{ $pShort }
+
Admin
+
+ +
+
}; diff --git a/edoc/admin/project-template/project.xqm b/edoc/admin/project-template/project.xqm new file mode 100644 index 00000000..4b869cb3 --- /dev/null +++ b/edoc/admin/project-template/project.xqm @@ -0,0 +1,5 @@ +xquery version "3.1"; + +module namespace wdbPF = "https://github.com/dariok/wdbplus/projectFiles"; + +declare namespace tei = "http://www.tei-c.org/ns/1.0"; \ No newline at end of file diff --git a/edoc/admin/project-template/resources/xsl/tei-common.xsl b/edoc/admin/project-template/resources/xsl/tei-common.xsl new file mode 100644 index 00000000..c2ae9bdb --- /dev/null +++ b/edoc/admin/project-template/resources/xsl/tei-common.xsl @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/edoc/admin/project-template/resources/xsl/tei-transcript.xsl b/edoc/admin/project-template/resources/xsl/tei-transcript.xsl new file mode 100644 index 00000000..3c7883c4 --- /dev/null +++ b/edoc/admin/project-template/resources/xsl/tei-transcript.xsl @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/edoc/admin/project-template/wdbmeta.xml b/edoc/admin/project-template/wdbmeta.xml new file mode 100644 index 00000000..d74ff535 --- /dev/null +++ b/edoc/admin/project-template/wdbmeta.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + full text of transcribed sources + + + + + + + (no licence stated) + + + + + + + resources/xsl/tei-transcript.xsl + + + + + + + diff --git a/edoc/admin/projects.xqm b/edoc/admin/projects.xqm index 0400a10f..e6401017 100644 --- a/edoc/admin/projects.xqm +++ b/edoc/admin/projects.xqm @@ -1,20 +1,17 @@ -xquery version "3.0"; +xquery version "3.1"; module namespace wdbPL = "https://github.com/dariok/wdbplus/ProjectList"; -import module namespace sm = "http://exist-db.org/xquery/securitymanager"; -import module namespace wdb = "https://github.com/dariok/wdbplus/wdb" at "../modules/app.xqm"; -import module namespace wdbs = "https://github.com/dariok/wdbplus/stats" at "../modules/stats.xqm"; -import module namespace xstring = "https://github.com/dariok/XStringUtils" at "../include/xstring/string-pack.xql"; +import module namespace config = "https://github.com/dariok/wdbplus/config" at "../modules/wdb-config.xqm"; +import module namespace sm = "http://exist-db.org/xquery/securitymanager"; +import module namespace wdbFiles = "https://github.com/dariok/wdbplus/files" at "../modules/wdb-files.xqm"; +import module namespace wdbs = "https://github.com/dariok/wdbplus/stats" at "../modules/stats.xqm"; -declare namespace config = "https://github.com/dariok/wdbplus/config"; declare namespace meta = "https://github.com/dariok/wdbplus/wdbmeta"; declare namespace tei = "http://www.tei-c.org/ns/1.0"; -declare function wdbPL:pageTitle ($node as node(), $model as map(*)) { - let $t := $wdb:configFile//config:short - - return {normalize-space($t)} – Admin +declare function wdbPL:pageTitle ( $node as node(), $model as map(*) ) as element(title) { + { normalize-space($config:configFile//config:short) } – Admin }; declare function wdbPL:body ( $node as node(), $model as map(*) ) { @@ -31,46 +28,48 @@ declare function wdbPL:body ( $node as node(), $model as map(*) ) { let $metaFile := doc($metaPath) let $relativePath := substring-after($file, $model?pathToEd || '/') - let $subColl := xstring:substring-before-last($file, '/') - let $resource := xstring:substring-after-last($file, '/') + let $subColl := if (starts-with($file, '/')) + then '/' || string-join(tokenize(normalize-space($file), '/')[position() lt last()], '/') + else string-join(tokenize(normalize-space($file), '/')[position() lt last()], '/') + let $resource := tokenize(normalize-space($file), '/')[last()] let $fileEntry := $metaFile//meta:file[@path = $relativePath] let $xml := doc($file) return switch ($job) case 'add' return let $ins := let $up1 := update insert $ins into $metaFile//meta:files - return local:getFileStat($model , $file) + return wdbPL:getFileStat($model , $file) case 'uuid' return let $ins := attribute uuid {util:uuid($xml)} let $up1 := if ($fileEntry/@uuid) then update replace $fileEntry/@uuid with $ins else update insert $ins into $fileEntry - return local:getFileStat($model, $file) + return wdbPL:getFileStat($model, $file) case 'pid' return let $ins := attribute pid { string($xml//tei:publicationStmt/tei:idno[@type = 'URI']) } let $up1 := if ($fileEntry/@pid) then update replace $fileEntry/@pid with $ins else update insert $ins into $fileEntry - return local:getFileStat($model, $file) + return wdbPL:getFileStat($model, $file) case 'date' return let $ins := attribute date {xmldb:last-modified($subColl, $resource)} let $up1 := if ($fileEntry/@date) then update replace $fileEntry/@date with $ins else update insert $ins into $fileEntry - return local:getFileStat($model, $file) + return wdbPL:getFileStat($model, $file) case 'id' return let $ins := attribute xml:id {normalize-space($xml/tei:TEI/@xml:id)} let $upd1 := if ($fileEntry/@xml:id) then update replace $fileEntry/@xml:id with $ins else update insert $ins/@xml:id into $fileEntry - return local:getFileStat($model, $file) + return wdbPL:getFileStat($model, $file) case 'private' return let $id := normalize-space($xml/tei:TEI/@xml:id) @@ -80,7 +79,7 @@ declare function wdbPL:body ( $node as node(), $model as map(*) ) { else if ($view/@private = 'false') then update value $view/@private with 'true' else update insert attribute private {'true'} into $view - return local:getFileStat($model, $file) + return wdbPL:getFileStat($model, $file) default return

Strange Error

@@ -92,7 +91,7 @@ declare function wdbPL:body ( $node as node(), $model as map(*) ) { else if ($model?ed != 'data' and $model?ed != ''and $file = '') then local:getFiles($model) else - local:getFileStat($model, $file) + wdbPL:getFileStat($model, $file) }; declare function local:getFiles($model) { @@ -136,7 +135,7 @@ declare function local:getFiles($model) { {substring($info[4], 1, 100)} -
+ } @@ -144,20 +143,20 @@ declare function local:getFiles($model) { }; -declare function local:getFileStat($model, $file) { - let $filePath := wdb:getFilePath($file) - let $doc := doc($filePath) - let $metaFile := doc($model?infoFileLoc) - let $entry := $metaFile/id($file) - let $uuid := util:uuid($doc) - let $pid := $entry/@pid - let $date := xmldb:last-modified(xstring:substring-before-last($filePath, "/"), - xstring:substring-after-last($filePath, "/")) +declare %private function wdbPL:getFileStat( $model as map(*), $id as xs:string ) as element(div) { + let $fullPath := wdbFiles:getFullPath($id) + , $filePath := $fullPath?collectionPath || "/" || $fullPath?fileName + , $doc := doc($filePath) + , $metaFile := doc($fullPath?projectPath || "/wdbmeta.xml") + , $entry := $metaFile/id($id) + , $uuid := util:uuid($doc) + , $pid := $entry/@pid + , $date := xmldb:last-modified($fullPath?collectionPath, $fullPath?fileName) return
-

{$file}

+

{ $id }


anzeigenanzeigen
@@ -189,7 +188,7 @@ declare function local:getFileStat($model, $file) { {if ($entry/@path != '') then - else + else } {if ($entry/@path != '') @@ -198,28 +197,31 @@ declare function local:getFileStat($model, $file) { {if ($entry/@uuid = $uuid) then - else + else } , , {if ($entry/@date = $date) then - else + else } , {if ($entry/@xml:id = $doc/tei:TEI/@xml:id) then - else + else } ) @@ -228,8 +230,8 @@ declare function local:getFileStat($model, $file) {
Eintrag in wdbmeta.xml vorhanden?OKfehlt hinzufügenfehlt
UUID in wdbMetaOK: {$uuid}{normalize-space($entry/@uuid)}
UUID aktualisieren
{normalize-space($entry/@uuid)} +
externe PID {if ($entry/@pid = $pid) then "OK: " || string($entry/@pid) - else PID aus Datei übernehmen + else }
Timestamp in wdbMetaOK: {$date}{normalize-space($entry/@date)}
Timestamp aktualisieren
{normalize-space($entry/@date)} +
@xml:id in wdbMetaOK: {$entry/@xml:id/string()}{normalize-space($entry/@xml:id)}
ID aktualisieren
{normalize-space($entry/@xml:id)} +
{ - if ($wdb:role = 'workbench') then - let $remoteMetaFilePath := $wdb:peer || '/' || substring-after($model?pathToEd, $wdb:data) || '/wdbmeta.xml' + (: if ( $config:role = 'workbench' ) then + let $remoteMetaFilePath := $config:peer || '/' || substring-after($model?pathToEd, $config:data) || '/wdbmeta.xml' let $remoteMetaFile := try { doc($remoteMetaFilePath) } catch * { @@ -238,7 +240,7 @@ declare function local:getFileStat($model, $file) { c: ' || $err:value || ' in ' || $err:module || ' a: ' || $err:additional) } - let $remoteEntry := $remoteMetaFile//meta:file[@xml:id = $file] + let $remoteEntry := $remoteMetaFile//meta:file[@xml:id = $id] return (

Peer Info

, @@ -246,7 +248,7 @@ declare function local:getFileStat($model, $file) { Peer Server - {$wdb:peer} + { $config:peer } Eintrag in wdbmeta.xml vorhanden? @@ -273,8 +275,8 @@ declare function local:getFileStat($model, $file) { , @xml:id in wdbMeta - {if ($remoteEntry/@xml:id = $file) - then OK: {$file} + {if ($remoteEntry/@xml:id = $id) + then OK: { $id } else Diff: {normalize-space($remoteEntry/@xml:id)} } @@ -284,13 +286,13 @@ declare function local:getFileStat($model, $file) { ) - else () + else () :) } { - if ($wdb:role = 'standalone') then - let $status := if ($metaFile//meta:view[@file = $file]) + if ( $config:role = 'standalone' ) then + let $status := if ($metaFile//meta:view[@file = $id]) then - let $view := ($metaFile//meta:view[@file = $file])[1] + let $view := ($metaFile//meta:view[@file = $id])[1] return if ($view/@private = true()) then 'intern' else 'sichtbar' @@ -305,7 +307,7 @@ declare function local:getFileStat($model, $file) { if ($status = 'Kein Struktureintrag') then $status else - let $link := umschalten + let $link := return ($status,
, $link) } @@ -316,4 +318,4 @@ declare function local:getFileStat($model, $file) { }
-}; \ No newline at end of file +}; diff --git a/edoc/admin/transform-test.xql b/edoc/admin/transform-test.xql deleted file mode 100644 index 9bbecb62..00000000 --- a/edoc/admin/transform-test.xql +++ /dev/null @@ -1,40 +0,0 @@ -xquery version "3.1"; - -import module namespace wdb = "https://github.com/dariok/wdbplus/wdb" at "modules/app.xql"; - -let $id := "edoc_wd_1703-08-20" - -let $model := wdb:populateModel($id, "", map{}) - - let $file := $model("fileLoc") - let $xslt := $model("xslt") - let $params := - - - - - - { - if ($model("view") != '') - then - else () - } - - (: ambiguous rule match soll nicht zum Abbruch führen :) - let $attr := - - let $re := - try { transform:transform(doc($file), doc($xslt), $params, $attr, "expand-xincludes=no") } - catch * { - - {$file} - {$xslt} - {$params} - {$attr} - {$err:code || ': ' || $err:description} - {$err:module || '@' || $err:line-number ||':'||$err:column-number} - {$err:additional} - - } - -return ($model, $re) \ No newline at end of file diff --git a/edoc/admin/view.xql b/edoc/admin/view.xql index 211c57b4..09eedc4b 100644 --- a/edoc/admin/view.xql +++ b/edoc/admin/view.xql @@ -7,7 +7,6 @@ xquery version "3.1"; declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization"; -import module namespace config = "http://exist-db.org/xquery/apps/config" at "../modules/config.xqm"; import module namespace templates = "http://exist-db.org/xquery/html-templating"; import module namespace wdb = "https://github.com/dariok/wdbplus/wdb" at "../modules/app.xqm"; import module namespace wdbAdmin = "https://github.com/dariok/wdbplus/Admin" at "admin.xqm"; @@ -24,8 +23,9 @@ declare option output:media-type "text/html"; : The following modules provide functions which will be called by the : templating. :) +let $app-root := "/db/" || substring-after(system:get-module-load-path(), "/db/") => substring-before("admin") let $config := map { - $templates:CONFIG_APP_ROOT: $config:app-root, + $templates:CONFIG_APP_ROOT: $app-root, $templates:CONFIG_STOP_ON_ERROR: true() } diff --git a/edoc/config.xml b/edoc/config.xml index 9570ec01..391c2e40 100644 --- a/edoc/config.xml +++ b/edoc/config.xml @@ -28,7 +28,8 @@ http://localhost:8080/exist/apps/edoc - http://localhost:8080/exist/restxq/edoc/ + http://localhost:8080/exist/restxq/edoc/ + https://localhost/exist/apps/edoc @@ -36,11 +37,24 @@ +
-
+
+
- + + + diff --git a/edoc/config/edoc/data/collection.xconf b/edoc/config/edoc/data/collection.xconf index 503ecb9a..aafe121e 100644 --- a/edoc/config/edoc/data/collection.xconf +++ b/edoc/config/edoc/data/collection.xconf @@ -3,48 +3,33 @@ - - - - - - - - - - - + - - + + + - - - - - - - - - - - - + + - - - - + + + + + - - - + + + + + + @@ -54,15 +39,23 @@ - + + - - + + + + + + + + + @@ -77,6 +70,8 @@ + + diff --git a/edoc/config/edoc/data/documentation/collection.xconf b/edoc/config/edoc/data/documentation/collection.xconf new file mode 100644 index 00000000..56fb2470 --- /dev/null +++ b/edoc/config/edoc/data/documentation/collection.xconf @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/edoc/controller.xql b/edoc/controller.xql index f39f39e8..d1f5e867 100644 --- a/edoc/controller.xql +++ b/edoc/controller.xql @@ -5,13 +5,11 @@ :) xquery version "3.1"; -import module namespace config = "http://exist-db.org/xquery/apps/config" at "/db/apps/eXide/modules/config.xqm"; -import module namespace login = "http://exist-db.org/xquery/login" at "resource:org/exist/xquery/modules/persistentlogin/login.xql"; -import module namespace request = "http://exist-db.org/xquery/request" at "java:org.exist.xquery.functions.request.RequestModule"; -import module namespace sm = "http://exist-db.org/xquery/securitymanager" at "java:org.exist.xquery.functions.securitymanager.SecurityManagerModule"; -import module namespace wdba = "https://github.com/dariok/wdbplus/auth" at "/db/apps/edoc/modules/auth.xqm"; +import module namespace request = "http://exist-db.org/xquery/request" at "java:org.exist.xquery.functions.request.RequestModule"; -declare namespace exist = "http://exist.sourceforge.net/NS/exist"; +declare namespace config = "https://github.com/dariok/wdbplus/config"; +declare namespace exist = "http://exist.sourceforge.net/NS/exist"; +declare namespace meta = "https://github.com/dariok/wdbplus/wdbmeta"; declare variable $exist:path external; declare variable $exist:resource external; @@ -19,56 +17,74 @@ declare variable $exist:controller external; declare variable $exist:prefix external; declare variable $exist:root external; -(: von eXide geklaut :) -declare function local:user-allowed() { - ( - request:get-attribute("wd.user") and - request:get-attribute("wd.user") != "guest" - ) or config:get-configuration()/restrictions/@guest = "yes" -}; -declare function local:query-execution-allowed() { - ( - config:get-configuration()/restrictions/@execute-query = "yes" - and local:user-allowed() - ) - or sm:is-dba((request:get-attribute("wd.user"),request:get-attribute("xquery.user"), 'nobody')[1]) -}; +declare variable $local:isget := request:get-method() = ("GET","get"); +declare variable $local:config := doc("/db/apps/edoc/config.xml")/config:config; -let $cookiePath := substring-before(request:get-uri(), $exist:path) - , $duration := xs:dayTimeDuration("P2D") +(: util:log("info", "Request-Path: " || $exist:path || "; Resource: " || $exist:resource || "; Controller: " || $exist:controller || "; Prefix: " || $exist:prefix || "; Root: " || $exist:root), :) +util:log("info", request:get-method() || " " || request:get-url() || ' ? ' || request:get-query-string() || " → resource: " || $exist:resource), + +(: static HTML page for API documentation should be served directly to make sure it is always accessible :) +if ( $local:isget and $exist:resource = ('v2.json', 'v2.html', 'v2.yaml') ) then + + + -return -if ( $exist:resource eq '' or $exist:resource eq 'index.html' ) then - - - (: login :) else if ( $exist:resource = 'login' ) then - ( - login:set-user("wd", $cookiePath, $duration, false()), - try { - if (request:get-parameter('logout', '') = 'logout') then - wdba:getAuth(
, map {'res': 'logout'}) - else if (local:user-allowed()) then - wdba:getAuth(
, map {'auth': {request:get-attribute("wd.user")}}) - else ( - response:set-status-code(401), - fail - ) - } catch * { - response:set-status-code(403), - {$err:description} - } - ) + + + { + if ( $local:config//config:origin = request:get-header('origin') ) + then ( + , + + ) + else () + } + + +(: logout :) +else if ( $exist:resource = 'logout' ) then + + + { + if ( $local:config//config:origin = request:get-header('origin') ) + then + else () + } + + + +(: REST API :) +else if ( contains($exist:path, 'api/v2') ) then + + + { + (: we currently need this workaround here as Jetty snatches all OPTIONS requests before they can be parsed by roaster :) + if ( request:get-method() = ('options', 'OPTIONS') and $local:config//config:origin = request:get-header('origin') ) + then ( + , + , + , + + ) + else () + } + + + +(: global index.html :) +else if ( $exist:resource eq '' or $exist:resource eq 'index.html' ) then + + + + (: admin pages :) else if ( ends-with($exist:resource, ".html") and contains($exist:path, '/admin/') ) then - { login:set-user("wd", $cookiePath, $duration, false()) } - - { login:set-user("wd", $cookiePath, $duration, false()) } - + @@ -80,28 +96,47 @@ else if ( ends-with($exist:resource, ".html") ) then - { login:set-user("wd", $cookiePath, $duration, false()) } - + { + for $header in $local:config//config:header + return { $header/@* } + } + + +(: generic resources :) else if ( contains($exist:path, "/$shared/") ) then - + { + for $header in $local:config//config:header + return { $header/@* } + } -else if ( ends-with($exist:path, ".xql") ) then +(: instance specific resources :) +else if ( contains($exist:path, "/$global/") ) then + + + { + for $header in $local:config//config:header + return { $header/@* } + } + + + +else if ( ends-with($exist:path, ".xql") or ends-with($exist:path, ".xq") ) then - { login:set-user("wd", $cookiePath, $duration, false()) } -else + (: everything else is passed through :) +else diff --git a/edoc/data/documentation/project.xqm b/edoc/data/documentation/project.xqm new file mode 100644 index 00000000..4b869cb3 --- /dev/null +++ b/edoc/data/documentation/project.xqm @@ -0,0 +1,5 @@ +xquery version "3.1"; + +module namespace wdbPF = "https://github.com/dariok/wdbplus/projectFiles"; + +declare namespace tei = "http://www.tei-c.org/ns/1.0"; \ No newline at end of file diff --git a/edoc/data/documentation/resources/xsl/tei-common.xsl b/edoc/data/documentation/resources/xsl/tei-common.xsl new file mode 100644 index 00000000..c2ae9bdb --- /dev/null +++ b/edoc/data/documentation/resources/xsl/tei-common.xsl @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/edoc/data/documentation/resources/xsl/tei-transcript.xsl b/edoc/data/documentation/resources/xsl/tei-transcript.xsl new file mode 100644 index 00000000..3c7883c4 --- /dev/null +++ b/edoc/data/documentation/resources/xsl/tei-transcript.xsl @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/edoc/data/documentation/wdbmeta.xml b/edoc/data/documentation/wdbmeta.xml new file mode 100644 index 00000000..c5cf4197 --- /dev/null +++ b/edoc/data/documentation/wdbmeta.xml @@ -0,0 +1,49 @@ + + + + + wdb+ Documentation + + + + + + + + + + + + + + + + docu + + + + + + full text of transcribed sources + + + + + + + (no licence stated) + + + + + + + resources/xsl/tei-transcript.xsl + + + + + + + \ No newline at end of file diff --git a/edoc/data/instance.xqm b/edoc/data/instance.xqm index 3b80af62..85ef0bc4 100644 --- a/edoc/data/instance.xqm +++ b/edoc/data/instance.xqm @@ -6,4 +6,4 @@ declare namespace tei = "http://www.tei-c.org/ns/1.0"; declare function wdbPF:getInstanceName () as xs:string { doc('wdbmeta.xml')//*:title[1] -}; \ No newline at end of file +}; diff --git a/edoc/data/resources/blobs/.gitkeep b/edoc/data/resources/blobs/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/edoc/data/resources/css/.gitkeep b/edoc/data/resources/css/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/edoc/data/resources/html/.gitkeep b/edoc/data/resources/html/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/edoc/data/resources/images/.gitkeep b/edoc/data/resources/images/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/edoc/data/resources/js/.gitkeep b/edoc/data/resources/js/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/edoc/data/resources/xq/.gitkeep b/edoc/data/resources/xq/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/edoc/data/resources/xsl/tei-common.xsl b/edoc/data/resources/xsl/tei-common.xsl new file mode 100644 index 00000000..c2ae9bdb --- /dev/null +++ b/edoc/data/resources/xsl/tei-common.xsl @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/edoc/data/resources/xsl/tei-transcript.xsl b/edoc/data/resources/xsl/tei-transcript.xsl new file mode 100644 index 00000000..3c7883c4 --- /dev/null +++ b/edoc/data/resources/xsl/tei-transcript.xsl @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/edoc/data/wdbmeta.xml b/edoc/data/wdbmeta.xml index e6f1825c..1a412122 100644 --- a/edoc/data/wdbmeta.xml +++ b/edoc/data/wdbmeta.xml @@ -2,7 +2,7 @@ - + wdb+ main project collection @@ -22,8 +22,12 @@ - - - + + + + + + + - \ No newline at end of file + diff --git a/edoc/doc/Dokumentation.xml b/edoc/doc/Dokumentation.xml index 7a34a861..e073932a 100644 --- a/edoc/doc/Dokumentation.xml +++ b/edoc/doc/Dokumentation.xml @@ -61,7 +61,7 @@ Where to find the function

the files can be found in /edoc/modules/start.xqm - /edoc/resources/start.xsl + /edoc/resources/xsl/start.xsl

The start.xqm @@ -79,7 +79,7 @@
If you want to change it on a project-level: link to - project/resource/startLeft.html and startRight.html; if you want to change it + {$project}/resource/html/startLeft.html and {$project}/resource/html/startRight.html; if you want to change it globally, you can override the default behaviour by changing edoc/data/instance.xqm

diff --git a/edoc/doc/outline-view.html b/edoc/doc/outline-view.html index a4447d58..af600f75 100644 --- a/edoc/doc/outline-view.html +++ b/edoc/doc/outline-view.html @@ -40,7 +40,7 @@

...

-
+
diff --git a/edoc/doc/wdbadmin_object.dita b/edoc/doc/wdbadmin_object.dita index 0466cf58..c5ea4733 100644 --- a/edoc/doc/wdbadmin_object.dita +++ b/edoc/doc/wdbadmin_object.dita @@ -9,10 +9,6 @@ displayRight(url) get info from URL and display it on the right - - showFile(ed, file) - Show file information on the right - showJob(job, file) Show job results diff --git a/edoc/expath-pkg.xml b/edoc/expath-pkg.xml index fe43428b..62d3e393 100644 --- a/edoc/expath-pkg.xml +++ b/edoc/expath-pkg.xml @@ -1,4 +1,6 @@ - + W. Digitale Bibliothek + + diff --git a/edoc/include/xstring b/edoc/include/xstring deleted file mode 160000 index 375c9791..00000000 --- a/edoc/include/xstring +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 375c97910f230dd01ad0d65a7e25ff0bfa945dd3 diff --git a/edoc/index/file-index.xml b/edoc/index/file-index.xml new file mode 100644 index 00000000..edc5cd73 --- /dev/null +++ b/edoc/index/file-index.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/edoc/index/index-projects.xq b/edoc/index/index-projects.xq new file mode 100644 index 00000000..ff08a3ff --- /dev/null +++ b/edoc/index/index-projects.xq @@ -0,0 +1,27 @@ +xquery version "3.1"; + +declare namespace index = "https://github.com/dariok/wdbplus/index"; +declare namespace meta = "https://github.com/dariok/wdbplus/wdbmeta"; + +update delete doc("/db/apps/edoc/index/project-index.xml")/index:index/*, +update delete doc("/db/apps/edoc/index/file-index.xml")/index:index/*, +for $project in collection('/db/apps/edoc/data')//meta:projectMD + let $path := util:collection-name($project) + let $files := $project//meta:file + let $file-entries := for $file in $files + return + + return ( + update insert into doc("/db/apps/edoc/index/project-index.xml")/index:index, + if ( not(empty($file-entries)) ) + then update insert $file-entries into doc("/db/apps/edoc/index/file-index.xml")/index:index + else () + ), +xmldb:reindex("/db/apps/edoc/index") diff --git a/edoc/index/project-index.xml b/edoc/index/project-index.xml new file mode 100644 index 00000000..40982b50 --- /dev/null +++ b/edoc/index/project-index.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/edoc/logs/errors.xml b/edoc/logs/errors.xml new file mode 100644 index 00000000..ff5db007 --- /dev/null +++ b/edoc/logs/errors.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/edoc/modules/addin.xqm b/edoc/modules/addin.xqm index 606dc0fe..6098d724 100644 --- a/edoc/modules/addin.xqm +++ b/edoc/modules/addin.xqm @@ -5,15 +5,15 @@ xquery version "3.1"; module namespace wdbAddinMain = "https://github.com/dariok/wdbplus/addins-main"; -import module namespace wdb = "https://github.com/dariok/wdbplus/wdb" at "app.xqm"; -import module namespace wdbErr = "https://github.com/dariok/wdbplus/errors" at "error.xqm"; +import module namespace wdbErr = "https://github.com/dariok/wdbplus/errors" at "error.xqm"; +declare namespace request = "http://exist-db.org/xquery/request"; declare namespace wdbadd = "https://github.com/dariok/wdbplus/addins"; (: load the main XQuery module for the requested addin. It is mandatory these implement wdbadd:main($map as map(*)) :) declare function wdbAddinMain:body ( $node as node(), $model as map(*) ) as element()+ { let $addinName := substring-before(substring-after(request:get-uri(), 'addins/'), '/') - , $path := $wdb:edocBaseDB || "/addins/" || $addinName || "/addin.xqm" + , $path := "/db/apps/edoc/addins/" || $addinName || "/addin.xqm" , $map := map { "location-hints": $path } let $module := try { diff --git a/edoc/modules/annotations.xqm b/edoc/modules/annotations.xqm index 71b6b32e..e6a9592c 100644 --- a/edoc/modules/annotations.xqm +++ b/edoc/modules/annotations.xqm @@ -2,7 +2,9 @@ xquery version "3.1"; module namespace wdbanno = "https://github.com/dariok/wdbplus/anno"; -import module namespace wdb = "https://github.com/dariok/wdbplus/wdb" at "app.xqm"; +import module namespace config = "https://github.com/dariok/wdbplus/config" at "wdb-config.xqm"; + +declare namespace xmldb = "http://exist-db.org/xquery/xmldb"; (:~ : return the annotation file for the given user on the given file. @@ -13,8 +15,8 @@ import module namespace wdb = "https://github.com/dariok/wdbplus/wdb" at "app.xq : @return node(): the annotation file :) declare function wdbanno:getAnnoFile($file as xs:anyURI, $username as xs:string) as node() { - let $annotationCollectionName := substring-before(substring-after($file, $wdb:data), '.xml') - let $annotationCollectionBase := $wdb:edocBaseDB || '/annotations/' + let $annotationCollectionName := substring-before(substring-after($file, $config:data), '.xml') + let $annotationCollectionBase := $config:edocBaseDB || '/annotations/' let $annotationCollection := if (xmldb:collection-available($annotationCollectionBase || $annotationCollectionName)) then $annotationCollectionBase || $annotationCollectionName else if (sm:has-access($annotationCollectionBase, 'w')) diff --git a/edoc/modules/app.xqm b/edoc/modules/app.xqm index 3f191fd6..31c7319b 100644 --- a/edoc/modules/app.xqm +++ b/edoc/modules/app.xqm @@ -11,93 +11,15 @@ xquery version "3.1"; module namespace wdb = "https://github.com/dariok/wdbplus/wdb"; -import module namespace templates = "http://exist-db.org/xquery/html-templating"; +import module namespace config = "https://github.com/dariok/wdbplus/config" at "wdb-config.xqm"; import module namespace wdbErr = "https://github.com/dariok/wdbplus/errors" at "error.xqm"; import module namespace wdbFiles = "https://github.com/dariok/wdbplus/files" at "wdb-files.xqm"; -import module namespace wdbPF = "https://github.com/dariok/wdbplus/projectFiles" at "/db/apps/edoc/data/instance.xqm"; -import module namespace xConf = "http://exist-db.org/xquery/apps/config" at "config.xqm"; -import module namespace xstring = "https://github.com/dariok/XStringUtils" at "../include/xstring/string-pack.xql"; +import module namespace wdbPF = "https://github.com/dariok/wdbplus/projectFiles" at "../data/instance.xqm"; -declare namespace config = "https://github.com/dariok/wdbplus/config"; -declare namespace main = "https://github.com/dariok/wdbplus"; -declare namespace meta = "https://github.com/dariok/wdbplus/wdbmeta"; -declare namespace rest = "http://exquery.org/ns/restxq"; -declare namespace tei = "http://www.tei-c.org/ns/1.0"; - -(: ALL-PURPOSE VARIABLES :) -(:~ - : load the config file - : See https://github.com/dariok/wdbplus/wiki/Global-Configuration - :) -declare variable $wdb:configFile := doc('../config.xml'); - -(:~ - : the base of this instance within the db - :) -declare variable $wdb:edocBaseDB := $wdb:configFile => base-uri() => substring-before('/config.xml'); - -(:~ - : Try to get the data collection. Documentation explicitly tells users to have a wdbmeta.xml - : in the Collection that contains all projects - :) -declare variable $wdb:data := - if ($wdb:configFile//config:data) - then normalize-space($wdb:configFile//config:data) - else - let $editionsW := collection($wdb:edocBaseDB)//meta:projectMD - - let $paths := for $f in $editionsW - let $path := base-uri($f) - where contains($path, '.xml') - order by string-length($path) - return $path - - return replace(xstring:substring-before-last($paths[1], '/'), '//', '/') -; - -(:~ - : get the base URI either from the data of the last call or from the configuration - :) -declare variable $wdb:edocBaseURL := - if ($wdb:configFile//config:server) - then normalize-space($wdb:configFile//config:server) - else - let $dir := try { xstring:substring-before-last(request:get-uri(), '/') } catch * { "" } - let $db := substring-after($wdb:edocBaseDB, 'db/') - let $local := xstring:substring-after($dir, $db) - let $path := if (string-length($local) > 0) - then xstring:substring-before($dir, $local) (: there is a local part, e.g. 'admin' :) - else $dir (: no local part, e.g. for view.html in app root :) - - return wdb:getServerApp() || replace($path, '//', '/') -; - -(: ~ - : get the base URL for REST calls - :) -declare variable $wdb:restURL := - if ($wdb:configFile//config:rest) - then normalize-space($wdb:configFile//config:rest) - else if ($wdb:edocBaseURL = "") - then rest:base-uri() || "/edoc" - else substring-before($wdb:edocBaseURL, substring-after($wdb:edocBaseDB, '/db/')) || "restxq/edoc/"; - - -(:~ - : the server role - :) -declare variable $wdb:role := - ($wdb:configFile//main:role/main:type, "standalone")[1] -; -(:~ - : the peer in a sandbox/publication configuration - :) -declare variable $wdb:peer := - if ($wdb:role != "standalone") - then $wdb:configFile//main:role/main:peer - else "" -; -(: END ALL-PURPOSE VARIABLES :) +declare namespace main = "https://github.com/dariok/wdbplus"; +declare namespace meta = "https://github.com/dariok/wdbplus/wdbmeta"; +declare namespace rest = "http://exquery.org/ns/restxq"; +declare namespace tei = "http://www.tei-c.org/ns/1.0"; (: FUNCTIONS TO GET SERVER INFO :) (:~ @@ -105,9 +27,9 @@ declare variable $wdb:peer := : : @return (node()) HTML div :) -declare function wdb:test($node as node(), $model as map(*)) as node() { +declare function wdb:test( $node as node(), $model as map(*) ) as node() {
-

APP CONTEXT test on {$wdb:configFile//config:name}

+

APP CONTEXT test on {$config:configFile//config:name}

global variables (function.xqm)

@@ -128,13 +50,13 @@ declare function wdb:test($node as node(), $model as map(*)) as node() {
-

populateModel (app.xqm)

+

populateModel (model.xqm)

{ if (exists($model?id)) - then - let $computedModel := wdb:populateModel($model?id, "", map {}) - return wdbErr:get($computedModel, "") + then "currently, no model view is available" + (: let $computedModel := wdb:populateModel($model?id, "", map {}) + return wdbErr:get($computedModel, "") :) else "Keine ID zur Auswertung vorhanden" }
@@ -157,292 +79,9 @@ declare function wdb:test($node as node(), $model as map(*)) as node() {
}; - -(: ~ - : get the name of the server, possibly including the port - : If resolution fails, set the value in config.xml instead - : This cannot be used for RESTXQ - :) -declare function wdb:getServerApp() as xs:string { - (: config:server contains the full base URL :) - let $config := - let $scheme := substring-before($wdb:configFile//config:server, '//') - let $server := substring-before(substring-after($wdb:configFile//config:server, '//'), '/') - return if ($scheme != "") then $scheme || '//' || $server else () - - let $origin := try { request:get-header("Origin") } catch * { () } - let $request := try { - let $scheme := if (request:get-header-names() = 'X-Forwarded-Proto') - then normalize-space(request:get-header('X-Forwarded-Proto')) - else normalize-space(request:get-scheme()) - - return if (request:get-server-port() != 80) - then $scheme || '://' || request:get-server-name() || ':' || request:get-server-port() - else $scheme || '://' || request:get-server-name() - } catch * { () } - let $ref := try { - let $r := request:get-header('referer') - let $scheme := substring-before($r, '://') - let $server := substring-before(substring-after($r, '://'), '/') - return $scheme || '://' || $server - } catch * { () } - - let $server := ($config, $request, $ref, $origin) - return if (count($server) > 0) - then $server[1] - else "" -}; (: END FUNCTIONS TO GET SERVER INFO :) (: FUNCTIONS USED BY THE TEMPLATING SYSTEM :) -(:~ - : Templating function; called from layout.html. Entry point for content pages - :) -declare - %templates:default("view", "") - %templates:default("p", "") -function wdb:getEE($node as node(), $model as map(*), $id as xs:string, $view as xs:string, $p as xs:string) as item()* { - try { - let $newModel := wdb:populateModel($id, $view, $model, $p) - - return if ( contains($newModel?fileLoc, 'http') ) then - $newModel - else - let $last-modified := - wdbFiles:getModificationDate($newModel?filePathInfo?collectionPath, $newModel?filePathInfo?fileName) - => wdbFiles:ietfDate() - - let $requestedModified := ( - request:get-attribute("if-modified"), - request:get-header("If-Modified-Since") - )[1] - let $isModified := if ( $requestedModified != '' ) - then wdbFiles:evaluateIfModifiedSince($id, $requestedModified) - else 200 - - (: TODO: use a function to get the actual content language :) - return if ( count($newModel) = 1 and $isModified = 200 ) - then ( - response:set-header("Last-Modified", $last-modified), - - { - for $h in $node/* return - if ( $h/*[@data-template] ) then - for $c in $h/* return try { - templates:apply($c, $wdb:lookup, $newModel) - } catch * { - util:log("error", $err:description) - } - else - try { - templates:apply($h, $wdb:lookup, $newModel) - } catch * { - util:log("error", $err:description) - } - } - - ) - else if ( $isModified = 304 ) then - response:set-status-code(304) - else - - -
-

An unknown error has occurred

-
- - { util:log("error", $newModel) } - - } catch * { - util:log("error", $err:code || ': ' || $err:description), - wdbErr:error(map { - "code": $err:code, - "model": $model, - "err:value": $err:value, - "err:description": $err:description, - "err:additional": $err:additional, - "location": $err:module || '@' || $err:line-number || ':' || $err:column-number - }) - } -}; - -(:~ - : Populate the model with the most important global settings when displaying a file - : Moved to a separate function as this one may be called by other functions, too - : - : @param $id the id for the file to be displayed - : @param $view a string to be passed to the processing XSLT - : @param $p general parameter to be passed to the processing XSLT - : @return a map; in case of error, an HTML file - :) -declare function wdb:populateModel ( $id as xs:string, $view as xs:string, $model as map(*) ) as item()* { - wdb:populateModel($id, $view, $model, "") -}; -declare function wdb:populateModel ( $id as xs:string, $view as xs:string, $model as map(*), $p as xs:string ) as item()* { - let $filePathInfo := wdbFiles:getFullPath($id) - , $pathToFile := if ( map:keys($filePathInfo) = 'fileURL' ) - then - $filePathInfo?fileURL - else - $filePathInfo?collectionPath || '/' || $filePathInfo?fileName - , $pathToEd := $filePathInfo?projectPath - , $infoFileLoc := $filePathInfo?projectPath || '/wdbmeta.xml' - - let $ed := string(doc($infoFileLoc)/meta:projectMD/@xml:id) - - let $xsl := if ( $filePathInfo?fileName = "wdbmeta.xml" ) - then - (: TODO get path to XSL via function (use what’s in rest-files.xql) :) - xs:anyURI($wdb:data || '/resources/nav.xsl') - else wdb:getXslFromWdbMeta($infoFileLoc, $id, 'html') - - let $xslt := if (doc-available($xsl)) - then $xsl - else if (doc-available($pathToEd || '/' || $xsl)) - then $pathToEd || '/' || $xsl - else "" - - let $title := normalize-space((doc($pathToFile)//tei:title)[1]) - - let $proFile := wdb:findProjectXQM($pathToEd) - , $mainProject := substring-before($proFile, "project.xqm") - , $resource := $mainProject || "resources/" - - let $projectFunctions := for $function in doc($mainProject || "project-functions.xml")//function - return $function/@name || '#' || count($function/argument) - , $instanceFunctions := for $function in doc($wdb:data || "/instance-functions.xml")//function - return $function/@name || '#' || count($function/argument) - - let $header := if ( request:exists() ) - then map:merge( for $header in request:get-header-names() return map:entry($header, request:get-header($header)) ) - else () - , $requestUrl := if ( request:exists() ) - then request:get-url() - else () - - (: TODO read global parameters from config.xml and store as a map :) - let $map := map { - "ed": $ed, - "fileLoc": $pathToFile, - "filePathInfo": $filePathInfo, - "functions": map { "project": $projectFunctions, "instance": $instanceFunctions }, - "header": $header, - "id": $id, - "infoFileLoc": $infoFileLoc, - "mainEd": substring-after($mainProject, 'data/') => substring-before('/'), - "p": $p, - "pathToEd": $pathToEd, - "projectFile": $proFile, - "projectResources": $resource, - "requestUrl": $requestUrl, - "title": $title, - "view": $view, - "xslt": $xslt - } - - return $map -}; - -(: ~ - : Create the head for HTML files served via the templating system - : @created 2018-02-02 DK - :) -declare function wdb:getHead ( $node as node(), $model as map(*) ) as element(head) { - - - - - - - - { $model("title") } – { normalize-space($wdb:configFile//config:short) } - - { - if ( wdb:findProjectFunction($model, "wdbPF:overrideCssJs", 1) ) then - (wdb:getProjectFunction($model, "wdbPF:overrideCssJs", 1))($model) - else ( - , - if ( util:binary-doc-available($wdb:data || "/resources/wdb.css") ) - then - else (), - , - if ( util:binary-doc-available($wdb:data || "/resources/view.css") ) - then - else (), - wdb:getBlob($node, $model, 'jquery-ui-css'), - wdb:getProjectFiles($node, $model, 'css'), - wdb:getBlob($node, $model, 'jquery'), - wdb:getBlob($node, $model, 'jquery-ui-js'), - , - , - , - if ( util:binary-doc-available($wdb:data || "/resources/function.js") ) - then - else (), - wdb:getProjectFiles($node, $model, 'js') - ) - } - -}; - -(:~ - : return the header - if there is a project specific function, use it - : - : order of evaluation: - : 1. {$projectResources}/header.html – this must contain one html:header, the - : contents of which will be sent through the templating system - : 2. instance or project specific wdbPF:getHeader#1 - : 3. evaluation of all 4 constituents of the header in a row - : a) wdbPF:getHeaderLeft#1 or {$wdb:data}/resources/headerLeft.html or empty html:p - : b) wdbPF:getHeaderCentre#1 or {$wdb:data}/resources/headerCentre.html or html:h1 - : c) wdbPF:getHeaderMenu#1 or {$wdb:data}/resources/headerMenu.html or html:button - : d) wdbPF:getHeaderRight#1 or {$wdb:data}/resources/headerRight.html or empty html:p - :) -declare function wdb:getHeader ( $node as node(), $model as map(*) ) as element() { -
{ - if ( doc-available($model?projectResources || '/header.html') ) - then templates:apply(doc($model?projectResources || '/header.html')/header/*, $wdb:lookup, $model) - else if ( wdb:findProjectFunction($model, 'wdbPF:getHeader', 1) ) then - (wdb:getProjectFunction($model, "wdbPF:getHeader", 1))($model) - else ( - , -
{ - if ( wdb:findProjectFunction($model, 'wdbPF:getHeaderCentre', 1) ) then - (wdb:getProjectFunction($model, "wdbPF:getHeaderCentre", 1))($model) - else if ( doc-available($wdb:data || "/resources/headerCentre.html") ) then - templates:apply(doc($wdb:data || "/resources/headerCentre.html"), $wdb:lookup, $model)/* - else -

{$model("title")}

- }
, - , - - ) - }
-}; - -declare function wdb:pageTitle($node as node(), $model as map(*)) { - let $ti := $model("title") - return {normalize-space($wdb:configFile//main:short)} – {$ti} -}; - (:~ : generic function to wrap some info from the model in an HTML element via templating :) @@ -450,178 +89,12 @@ declare function wdb:wrapText ( $node as node(), $model as map(*), $key as xs:st element { node-name($node) } { $model($key) } }; -(:~ - : return the body - :) -declare function wdb:getContent($node as node(), $model as map(*)) { - let $file := $model("fileLoc") - - let $xslt := if (string-length($model?xslt) = 0) - then wdbErr:error(map {"code": "wdbErr:wdb0002", "model": $model}) - else $model("xslt") - - let $params := - - - - - - { - if ($model("view") != '') - then - else () - } - { - if ($model("p") != '') - then - else () - } - - - - (: do not stop transformation on ambiguous rule match and similar warnings :) - let $attr := - - (: TODO: use generic processXSL function (currently in restFiles.xql but to be moved) so there is only one way of doing things :) - (: TODO: consider removing this entirely and instead load content of main via AJAX :) - return - try { -
- { transform:transform(doc($file), doc($xslt), $params, $attr, "") } - { wdb:getLeftFooter($node, $model) } -
- } catch * { (util:log("error", - - {$file} - {$xslt} - {$params} - {$attr} - {$err:code || ': ' || $err:description} - {$err:module || '@' || $err:line-number ||':'||$err:column-number} - {$err:additional} - ), - wdbErr:error(map{"code": "wdbErr:wdb1001", "model": $model, "additional": $params, "error": map { - "code": $err:code, "desc": $err:description, "module": $err:module, "line": $err:line-number, - "col": $err:column-number, "add": $err:additional - }})) - } -}; - -(:~ - : return the global (i.e., full width) footer - : - : order of evaluation: - : 1. {$wdb:data}/resources/mainFooter.html - : 2. {$projectResources}/mainFooter.html - : 3. wdbPF:getMainFooter#1 - :) -declare function wdb:getGlobalFooter($node as node(), $model as map(*)) { - if ( doc-available($wdb:data || "/resources/mainFooter.html") ) - then templates:apply(doc($wdb:data || "/resources/mainFooter.html"), $wdb:lookup, $model) - else if ( doc-available($model?projectResources || '/mainFooter.html') ) - then templates:apply(doc($model?projectResources || '/mainFooter.html'), $wdb:lookup, $model) - else if ( wdb:findProjectFunction($model, "wdbPF:getMainFooter", 1) ) then - (wdb:getProjectFunction($model, "wdbPF:getMainFooter", 1))($model) - else () -}; - -declare function wdb:getLeftFooter($node as node(), $model as map(*)) as element()? { - if (doc-available($model?projectResources || "/footer.html")) then - templates:apply(doc($model?projectResources || "/footer.html"), $wdb:lookup, $model) - else if (wdb:findProjectFunction($model, "wdbPF:getProjectFooter", 1)) then - (wdb:getProjectFunction($model, "wdbPF:getProjectFooter", 1))($model) - else if (doc-available($wdb:edocBaseDB || "/resources/footer.html")) then - templates:apply(doc($wdb:edocBaseDB || "/resources/footer.html"), $wdb:lookup, $model) - else () -}; -declare function wdb:getRightFooter($node as node(), $model as map(*)) as element()? { - if (doc-available($model?projectResources || "/projectRightFooter.html")) then - templates:apply(doc($model?projectResources || "/projectRightFooter.html"), $wdb:lookup, $model) - else if (wdb:findProjectFunction($model, "wdbPF:getProjectRightFooter", 1)) then - (wdb:getProjectFunction($model, "wdbPF:getProjectRightFooter", 1))($model) - else if (doc-available($wdb:data || "/resources/rightFooter.html")) then - templates:apply(doc($wdb:data || "/resources/rightFooter.html"), $wdb:lookup, $model) - else () -}; - declare function wdb:getAnnotationDialogue ( $node as node(), $model as map(*) ) { () }; (: END FUNCTIONS USED BY THE TEMPLATING SYSTEM :) (: FUNCTIONS DEALING WITH PROJECTS AND RESOURCES :) -(:~ - : Return the full URI to the (edition) XML file with the given ID - : The scope is the whole data collection; documentation states in several places that file IDs need to be unique - : - : This function raises errors that are to be caught by the caller - : - : @param $id as xs:string: the file ID - : @return xs:string the full URI to the file within the database - : @throws wdbErr:wdb0000 - : @throws wdbErr:wdb0001 - :) -declare function wdb:getFilePath ( $id as xs:string ) as xs:string { - let $files := wdbFiles:getFilePaths($wdb:data, $id) - - (: do not just return a random URI but add some checks for better error messages: - : no files found or more than one TEI file found or only wdbmeta entry but no other info :) - let $pathToFile := if ( count($files) = 0 ) then - error( - QName('https://github.com/dariok/wdbErr', 'wdb0000'), - "no file with ID " || $id || " in " || $wdb:data, - map { "id": $id, "request": request:get-url() } - ) - else if ( count($files) > 1 ) then - error( - QName('https://github.com/dariok/wdbErr', 'wdb0001'), - "multiple files with ID " || $id || " in " || $wdb:data, - map { "id": $id, "request": request:get-url() } - ) - else if ( local-name($files[1]) = 'id' ) then - base-uri($files[1]) || '#' || $id - else - xstring:substring-before-last(base-uri($files[1]), '/') || '/' || $files[1] - - return if ( starts-with($files[1], '$') ) - then - let $peer := $files[1] => substring(2) => substring-before('/') - , $id := $files[1] => substring-after('/') - return $wdb:configFile/id($peer) || '/' || $id - else $pathToFile -}; - -(:~ - : Return the (relative or absolute) path to the project - : - : @param $id the ID of a resource within a project - : @param $absolute (optional) if true(), return an absolute URL - : - : @returns the path (relative) to the app root - :) -declare function wdb:getEdPath($id as xs:string, $absolute as xs:boolean) as xs:string { - let $file := collection($wdb:data)/id($id)[self::meta:file or self::meta:projectMD or self::meta:struct] - - let $edPath := if ( count($file) = 1 ) then - xstring:substring-before-last(base-uri($file), '/') - else if ( count($file) > 1 ) then - fn:error(fn:QName('https://github.com/dariok/wdbErr', 'wdb0001')) - else - fn:error(fn:QName('https://github.com/dariok/wdbErr', 'wdb0200')) - - return if ($absolute) then replace($edPath, '//', '/') else substring-after($edPath, $wdb:edocBaseDB) -}; - -(:~ - : Return the relative path to the project - : - : @param $id the ID of a resource within a project - : @return the path relative to the app root - :) -declare function wdb:getEdPath($id as xs:string) as xs:string { - wdb:getEdPath($id, false()) -}; - (:~ : Tries to return an absolute path for a path within a project : @@ -632,18 +105,7 @@ declare function wdb:getEdPath($id as xs:string) as xs:string { declare function wdb:getAbsolutePath ( $ed as xs:string, $path as xs:string ) { if ( starts-with($path, '/') ) then $path - else wdb:getEdPath($ed, true()) || "/" || $path -}; - -(:~ - : Return the ID of a project from a resource ID within the project - : - : @param $id the ID of a resource within a project - : @return the ID of the project - :) -declare function wdb:getEdFromFileId ($id as xs:string) as xs:string { - let $file := collection($wdb:data)/id($id)[self::meta:file] - return $file/ancestor::meta:projectMD/@xml:id + else (wdbFiles:getFullPath($ed))?projectPath || "/" || $path }; (: ~ @@ -655,10 +117,15 @@ declare function wdb:getEdFromFileId ($id as xs:string) as xs:string { : @return the path :) declare function wdb:getEdFromPath($path as xs:string, $absolute as xs:boolean) as xs:string { - let $tok := tokenize(xstring:substring-after($path, $wdb:edocBaseDB||'/'), '/') + let $tok := tokenize( + if (contains($path, $config:edocBaseDB || '/')) + then substring-after($path, $config:edocBaseDB || '/') + else $path, + '/' + ) let $pa := for $i in 1 to count($tok) - let $t := $wdb:edocBaseDB || '.*' || string-join ($tok[position() < $i+1], '/') + let $t := $config:edocBaseDB || '.*' || string-join ($tok[position() < $i+1], '/') return xmldb:match-collection($t) let $path := if (count($pa) = 0) @@ -671,7 +138,7 @@ declare function wdb:getEdFromPath($path as xs:string, $absolute as xs:boolean) return if ( $absolute ) then $path[1] - else substring-after($path[1], $wdb:edocBaseDB||'/') + else substring-after($path[1], $config:edocBaseDB||'/') }; (:~ : Try ro load project specific XQuery to import CSS and JS @@ -681,8 +148,8 @@ declare function wdb:getProjectFiles ( $node as node(), $model as map(*), $type let $files := if ( wdb:findProjectFunction($model, 'wdbPF:getProjectFiles', 1) ) then (wdb:getProjectFunction($model, "wdbPF:getProjectFiles", 1))($model) else - let $css := wdb:findProjectFile($model?pathToEd, "/scripts/project.css") - , $js := wdb:findProjectFile($model?pathToEd, "/scripts/project.js") + let $css := wdb:findProjectFile($model?projectResources, "/css/project.css") + , $js := wdb:findProjectFile($model?projectResources, "/js/project.js") return ( if ( $css != "" ) @@ -729,22 +196,6 @@ declare function wdb:getProjectFunction ( $model as map(*), $name as xs:string, else () }; -(:~ - : Lookup a project's project.xqm: if present in $model("pathToEd"), use it; else, ascend and look for project.xqm - : there. Use if present. Ulitmately, if even $wdb:data/project.xqm does not exist, panic. - : - : @param $project a string representation of the path to the project - : @returns the path to a project.xqm if one was found; false() otherwise - :) -declare function wdb:findProjectXQM ( $project as xs:string ) { - if ( util:binary-doc-available($project || "/project.xqm") ) then - $project || "/project.xqm" - else if (substring-after($project, $wdb:data) = '') then - $wdb:data || "/instance.xqm" - else - wdb:findProjectXQM(xstring:substring-before-last($project, '/')) -}; - (:~ : Generic finder for files in the project hierarchy (bottom up) : it is assumed that this is a binary file @@ -753,19 +204,24 @@ declare function wdb:findProjectXQM ( $project as xs:string ) { : @param $fileName name of the file to search : @returns the full path to the file in the lowest position; if the file cannot be found, an empty URI is returned :) -declare function wdb:findProjectFile ( $pathToEd as xs:string, $fileName as xs:string ) as xs:anyURI { - if ( util:binary-doc-available($pathToEd || "/" || $fileName) ) then - xs:anyURI($pathToEd || "/" || $fileName) - else if ( substring-after($pathToEd, $wdb:data) = '' ) then +declare function wdb:findProjectFile ( $path as xs:string, $fileName as xs:string ) as xs:anyURI { + if ( util:binary-doc-available($path || "/" || $fileName) ) then + xs:anyURI($path || "/" || $fileName) + else if ( substring-after($path, $config:data) = '' ) then xs:anyURI("") else - wdb:findProjectFile(xstring:substring-before-last($pathToEd, '/'), $fileName) + wdb:findProjectFile( + if (starts-with($path, '/')) + then '/' || string-join(tokenize(normalize-space($path), '/')[position() lt last()], '/') + else string-join(tokenize(normalize-space($path), '/')[position() lt last()], '/'), + $fileName + ) }; (: END FUNCTIONS DEALING WITH PROJECTS AND RESOURCES :) (: GENERAL HELPER FUNCTIONS :) declare function wdb:getUrl ( $path as xs:string ) as xs:string { - $wdb:edocBaseURL || substring-after($path, $wdb:edocBaseDB) + $config:edocBaseURL || substring-after($path, $config:edocBaseDB) }; (:~ @@ -782,117 +238,121 @@ declare function wdb:eval($function as xs:string) { declare function wdb:eval($function as xs:string, $cache-flag as xs:boolean, $external-variable as item()*) { util:eval($function, $cache-flag, $external-variable) }; - -(:~ - : Return the full path to the project collection by trying to find the meta file by the project ID - : - : @param $ed The ID of a project, to be found in meta:projectMD/@xml:id - : @return The path to the project - :) -declare function wdb:getProjectPathFromId ( $ed as xs:string ) as xs:string { - let $md := collection($wdb:data)/id($ed)[self::meta:projectMD] - - return xstring:substring-before-last(base-uri(($md)[1]), '/') -}; - -(:~ - : Get the meta data file from the ed path - :) -declare function wdb:getMetaFile($pathToEd) { - if ( doc-available($pathToEd||'/wdbmeta.xml') ) - then $pathToEd || '/wdbmeta.xml' - else fn:error(fn:QName('https://github.com/dariok/wdbErr', 'wdbErr:wdb0003')) -}; - -(:~ - : Get the meta data file by project ID - : - : @param $ed The project ID to be evaluated - :) -declare function wdb:getMetaElementFromEd ( $ed as xs:string ) as element() { - collection($wdb:data)/id($ed)[self::meta:projectMD] -}; (: END GENERAL HELPER FUNCTIONS :) (: LOCAL HELPER FUNCTIONS :) (:~ : Evaluate wdbmeta.xml to get the process used for transformation : - : @param $ed The (relative) path to the project : @param $id The ID of the file to be processed : @param $target The processing target to be used + : @param $infoFileLoc The location of the wdbmeta.xml file + : @param $view (optional) a view parameter for selecting the right process : - : @returns The path to the XSLT + : @returns A command (should be: a process with 1+ command) :) -declare function wdb:getXslFromWdbMeta ( $infoFileLoc as xs:string, $id as xs:string, $target as xs:string ) as xs:string { - let $metaFile := doc($infoFileLoc), - $process := ( - $metaFile//meta:process[@target = $target], - $metaFile//meta:process[1] - )[1] +(: TODO: rename to "getProcessFromWdbmeta" or simply "getProcess" :) +(: TODO: change to actually get a process with 1+ command, see comment below :) +declare function wdb:getXslFromWdbMeta ( $infoFileLoc as xs:string, $id as xs:string, $target as xs:string ) as element(process)? { + wdb:getXslFromWdbMeta($infoFileLoc, $id, $target, "") +}; +declare function wdb:getXslFromWdbMeta ( $infoFileLoc as xs:string, $id as xs:string, $target as xs:string, $view as xs:string? ) as element(process)? { + let $metaFile := doc($infoFileLoc) + , $process := if ( $view != '' ) + then $metaFile//meta:process[@target = $target and @view = $view] + else $metaFile//meta:process[@target = $target and not(@view)] + , $base := substring-before(base-uri($metaFile), 'wdbmeta.xml') - let $sel := for $c in $process/meta:command - return if ( $c/@refs ) then - (: if a list of IDREFS is given, this command matches if $id is part of that list :) - let $map := tokenize($c/@refs, ' ') - return if ( $map = $id ) then $c else () - else if ( $c/@regex and matches($id, $c/@regex) ) - (: if a regex is given and $id matches that regex, the command matches :) - then $c - else if ( $c/@group and $metaFile/id($id)/parent::meta:filegroup/@xml:id = $c/@group ) - then $c - else if ( not($c/@refs or $c/@regex or $c/@group) ) - (: if no selection method is given, the command is considered the default :) - then $c - else () (: neither refs nor regex match and no default given :) + let $sel := if ( $process/meta:command ) + then + (: A command contains 1+ steps; we check command/@* to find the correct command and return it :) + for $c in $process/meta:command + return if ( $c/@refs ) then + (: if a list of IDREFS is given, this command matches if $id is part of that list :) + let $map := tokenize($c/@refs, ' ') + return if ( $map = $id ) then $c else () + else if ( $c/@regex and matches($id, $c/@regex) ) + (: if a regex is given and $id matches that regex, the command matches :) + then $c + else if ( $c/@group and $metaFile/id($id)/parent::meta:filegroup/@xml:id = $c/@group ) + then $c + else if ( not($c/@refs or $c/@regex or $c/@group) ) + (: if no selection method is given, the command is considered the default :) + then $c + else () (: neither refs nor regex match and no default given :) + (: if no command is defined, traverse up the project ancestors :) + else if ( $metaFile/meta:projectMD/meta:struct/*[1][self::meta:import] ) then + let $path := if (starts-with($infoFileLoc, '/')) + then '/' || string-join(tokenize(normalize-space($infoFileLoc), '/')[position() lt last()], '/') + else string-join(tokenize(normalize-space($infoFileLoc), '/')[position() lt last()], '/') + , $parent := $metaFile/meta:projectMD/meta:struct/meta:import + return + wdb:getXslFromWdbMeta ($path || '/' || $parent/@path, $id, $target, $view) + else () - (: As we check from most specific to default, the first command in the sequence is the right one :) - return ($sel)[1]/text() + (: As we check from most specific to default, the first command in the sequence is the right one. + We add the base-uri as attribute to the command so the path can later be evaluated :) + return if ( $sel[1] instance of element(meta:command) ) + then + { + for $step in $sel[1]/* + return { $base || normalize-space($step) } + } + + else if ( $sel[1] instance of element(meta:process) ) + then $sel[1] + else + error( + QName('wdbRErr', 'wdb0002'), + "no process found for id " || $id || ", target '" || $target || "' and view '" || $view || "' in " || $infoFileLoc + ) }; -(: we need a lookup function for the templating system to work :) -declare variable $wdb:lookup := function($functionName as xs:string, $arity as xs:int) { - try { - function-lookup(xs:QName($functionName), $arity) - } catch * { - () - } +(:~ + : Apply a project specific XSLT to some XML + : + : @param $xml The XML to be transformed + : @param $edPath The path to the project + : @param $name The name of the XSLT file to be applied + : + : @returns The transformed XML + : + : The lookup order is: + : 1) project resources + : 2) instance resources + : 3) global resources + :) +declare function wdb:applySpecificXsl ( $xml as node(), $pathInfo as map(*), $name as xs:string ) as node() { + wdb:applySpecificXsl($xml, $pathInfo, $name, ()) }; -(: END LOCAL HELPER FUNCTIONS :) - -(: HELPERS FOR REST AND HTTP REQUESTS :) -declare function wdb:parseMultipart ( $data, $header ) { - let $boundary := $header => substring-after('boundary=') => translate('"', '') - return map:merge( - for $m in tokenize($data, "--" || $boundary) return - if (string-length($m) lt 6) - then () +(:~ + : Apply a project specific XSLT to some XML + : + : @param $xml The XML to be transformed + : @param $edPath The path to the project + : @param $name The name of the XSLT file to be applied + : @param $parameters (optional) parameters to be passed to the XSLT + : + : @returns The transformed XML + : + : The lookup order is: + : 1) project resources + : 2) instance resources + : 3) global resources + :) +declare function wdb:applySpecificXsl ( $xml as node(), $pathInfo as map(*), $name as xs:string, $parameters as element(parameters)? ) as node() { + let $xsl := if ( doc-available($pathInfo?mainProject || "resources/xsl/" || $name) ) then + doc($pathInfo?mainProject || "resources/xsl/" || $name) + else if ( doc-available("/db/apps/edoc/data/resources/xsl/" || $name) ) then + doc("/db/apps/edoc/data/resources/xsl/" || $name) else - let $parts := (tokenize($m, "(^\s*$){2}", "m"))[normalize-space() != ""] - let $header := map:merge( - for $line in tokenize($parts[1], "\n") return - if (normalize-space($line) eq "") - then () - else - let $val := $line => substring-after(': ') => normalize-space() - let $value := if (contains($val, '; ')) - then map:merge( - for $entry in tokenize($val, '; ') return - if (contains($entry, '=')) - then map:entry ( substring-before($entry, '='), translate(substring-after($entry, '='), '"', '') ) - else map:entry ( "text", $entry ) - ) - else $val - return map:entry(substring-before($line, ': '), $value) - ) - - (: empty lines in the body will also cause splitting; hence, recombine everything except the header :) - return map:entry(($header?Content-Disposition?name, 'name')[1], - map { "header" : $header, "body" : string-join($parts[position() > 1], '\n') } - ) - ) + doc("/db/apps/edoc/resources/xsl/" || $name) + + return transform:transform($xml, $xsl, $parameters) }; +(: END LOCAL HELPER FUNCTIONS :) +(: HELPERS FOR REST AND HTTP REQUESTS :) (:~ : Get a MIME type from an extension and an optional XML namespace : @@ -903,46 +363,34 @@ declare function wdb:parseMultipart ( $data, $header ) { declare function wdb:getContentTypeFromExt ( $extension as xs:string, $namespace as xs:anyURI? ) as xs:string { switch ( $extension ) case 'css' - return - 'text/css' + return 'text/css' case 'js' - return - 'application/javascript' + return 'application/javascript' case 'xql' case 'xqm' - return - 'application/xquery' + return 'application/xquery' case 'html' - return - 'text/html' + return 'text/html' case 'gif' - return - 'image/gif' + return 'image/gif' case 'png' - return - 'image/png' + return 'image/png' case 'json' - return - 'application/json' + return 'application/json' case 'zip' - return - 'application/zip' + return 'application/zip' case 'xml' - return - if ( $namespace = 'http://www.tei-c.org/ns/1.0' ) then - 'application/tei+xml' - else - 'application/xml' + return if ( $namespace = 'http://www.tei-c.org/ns/1.0' ) + then 'application/tei+xml' + else 'application/xml' case 'xsl' - return - 'application/xslt+xml' + return 'application/xslt+xml' default - return - 'application/octet-stream' + return 'application/octet-stream' }; declare function wdb:getBlob ( $node as node(), $model as map(*), $name as xs:string ) { - let $path := $wdb:configFile//config:source[@name = $name]/@path + let $path := $config:configFile//config:source[@name = $name]/@path return if ( ends-with($path, 'js') ) then diff --git a/edoc/modules/auth.xqm b/edoc/modules/auth.xqm index a102274f..2f282a4d 100644 --- a/edoc/modules/auth.xqm +++ b/edoc/modules/auth.xqm @@ -9,7 +9,7 @@ declare function wdba:getAuth ( $node as node(), $model as map(*) ) as element(d return if ( $current = 'guest' or $model?res = 'logout' ) then