xquery version "1.0";
(: $Id$ :)
(:
Module: display and browse collections.
:)
module namespace browse="http://exist-db.org/xquery/admin-interface/browse-projects";
declare namespace text="http://exist-db.org/xquery/text";
declare namespace request="http://exist-db.org/xquery/request";
declare namespace xdb="http://exist-db.org/xquery/xmldb";
declare namespace util="http://exist-db.org/xquery/util";
declare namespace v="http://exist-db.org/versioning";
declare namespace transform="http://exist-db.org/xquery/transform";
declare namespace edit="http://rebind.bgbm.org/code/correction-report";
declare namespace date="http://exist-db.org/xquery/datetime";
declare namespace httpclient= "http://exist-db.org/xquery/httpclient";
declare namespace http = "http://expath.org/ns/http-client";
declare namespace biocase="http://www.biocase.org/schemas/protocol/1.3";
import module namespace metadata="http://exist-db.org/xquery/rebind/edit-metadata" at "xform-eml.xqm";
(:
Main function: outputs the page.
:)
declare function browse:main() as element()
{
let $colName := request:get-parameter("collection", "/db")[1]
let $colName := if(not(starts-with($colName,"/db")))then(fn:concat("/db",$colName))else($colName)
let $projectRoot := rebind:getSetting('db-project-folder')
let $publicRoot := rebind:getSetting('db-public-folder')
let $protectedRoot := rebind:getSetting('db-protected-folder')
(: check if collections exist, if not: create them; they should however already be created :)
let $output1 := if(not(xmldb:collection-available($projectRoot))) then (xmldb:create-collection("", $projectRoot)) else ()
let $output2 := if(not(xmldb:collection-available($publicRoot))) then (xmldb:create-collection("", $publicRoot)) else ()
let $output3 := if(not(xmldb:collection-available($protectedRoot))) then (xmldb:create-collection("", $protectedRoot)) else ()
let $patternProjectRoot := fn:concat("^(",$publicRoot,"|",$protectedRoot,")/[^/]+/?$")
let $patternProject := fn:concat("^(",$publicRoot,"|",$protectedRoot,")/[^/]+(/.+)?$")
let $patternProtectedProject := fn:concat("^",$protectedRoot,"/[^/]+/?")
let $patternprojectName := fn:concat("^(",$publicRoot,"|",$protectedRoot,")/")
let $patternProjectPath := fn:concat("^(",$publicRoot,"|",$protectedRoot,")/[^/]+")
let $isProjectRoot := matches($colName,$patternProjectRoot)
let $isProject := matches($colName,$patternProject)
let $isProtectedProject := matches($colName,$patternProtectedProject)
let $projectName := replace(replace($colName,$patternprojectName,''),"/.*$","")
let $projectPath := text:filter($colName,$patternProjectPath)[1]
let $metadataFileName := rebind:getSetting('metadata-file')
return
if(empty($projectPath))then(
Could not find project in path: {$colName}
)else if(not(xmldb:collection-available($colName)))then(
Project '{$projectName}' does not exist at: {$colName}
)else(
Project: {$projectName}
{if($isProject and not($isProjectRoot))then(
Up)else()}
{browse:display-project($colName)}
{if(xdb:is-admin-user(xdb:get-current-user()) and $isProtectedProject) then (
)else()
}
)
};
declare option exist:serialize "indent=yes method=xhtml";
declare function browse:show-project-menu() as element()
{
let $colName := request:get-parameter("collection", "/db")
let $colName := if(not(starts-with($colName,"/db")))then(fn:concat("/db",$colName))else($colName)
let $panel := request:get-parameter("panel", "status")[1]
let $projectRoot := rebind:getSetting('db-project-folder')
let $publicRoot := rebind:getSetting('db-public-folder')
let $protectedRoot := rebind:getSetting('db-protected-folder')
(: check if collections exist, if not: create them :)
let $output1 := if(not(xmldb:collection-available($projectRoot))) then (xmldb:create-collection("", $projectRoot)) else ()
let $output2 := if(not(xmldb:collection-available($publicRoot))) then (xmldb:create-collection("", $publicRoot)) else ()
let $output3 := if(not(xmldb:collection-available($protectedRoot))) then (xmldb:create-collection("", $protectedRoot)) else ()
let $link := session:encode-url(request:get-uri())
let $editLogCollectionName := rebind:getSetting('edit-log-folder-name')
let $isEditLogCollection := matches($colName,concat(".*?",$editLogCollectionName,"/?$"))
return
};
(:
Process an action.
:)
declare function browse:process-action($colName as xs:string) as element()*
{
(: TODO #32: check for rights :)
let $action := request:get-parameter("action", ())[1]
let $protectedRoot := rebind:getSetting('db-protected-folder')
return
util:catch("java.lang.Exception",
if($action eq "createcollection") then
(
browse:create-collection($colName)
)
else if($action eq "createproject") then
(
browse:create-collection($protectedRoot)
)
else if($action eq "upload") then
(
browse:upload($colName)
)
else if($action eq "upload-biocase") then
(
browse:upload-biocase($colName)
)
else if($action eq "save-metadata") then
(
browse:save-metadata($colName)
)else if($action eq "publish") then
(
browse:publish()
)else(),
An error occurred while processing the action:
{$util:exception-message}
)
};
(:
Store uploaded content.
:)
declare function browse:upload($colName as xs:string) as element()
{
let $name := request:get-parameter("filename", ()),
$docName := if($name) then $name else request:get-uploaded-file-name("upload"),
$file := request:get-uploaded-file-data("upload")
return
Actions:
- Storing uploaded content to: {$docName}
{
xdb:decode-uri(xs:anyURI(xdb:store($colName, xdb:encode-uri($docName), $file)))
}
};
(: TODO This function only gets files with a maximum number of records set to 700, for files greater than this size we need to loop and merge all the XML files
retrieved to one single XML file. Need to check the totalSearchHits. :)
declare function browse:upload-biocase($colName as xs:string) as element()
{
let $name := request:get-parameter("filename", ()),
$url := request:get-parameter("url", ()),
$query_string := "query=%3C%3Fxml+version%3D%271.0%27+encoding%3D%27UTF-8%27%3F%3E%0D%0A%3Crequest+xmlns%3D%27http%3A%2F%2Fwww.biocase.org%2Fschemas%2Fprotocol%2F1.3%27%3E%0D%0A++%3Cheader%3E%3Ctype%3Esearch%3C%2Ftype%3E%3C%2Fheader%3E%0D%0A++%3Csearch%3E%0D%0A++++%3CrequestFormat%3Ehttp%3A%2F%2Fwww.tdwg.org%2Fschemas%2Fabcd%2F2.06%3C%2FrequestFormat%3E%0D%0A++++%3CresponseFormat+start%3D%270%27+limit%3D%275700%27%3Ehttp%3A%2F%2Fwww.tdwg.org%2Fschemas%2Fabcd%2F2.06%3C%2FresponseFormat%3E%0D%0A++++++%3Ccount%3Efalse%3C%2Fcount%3E%0D%0A++%3C%2Fsearch%3E%0D%0A%3C%2Frequest%3E",
$reqs :=
{$query_string}
,
$post := http:send-request($reqs),
$totalSearchHits := $post[2]//biocase:response/biocase:content/@totalSearchHits
(:doc("/db/test/abcd/biocase_response_example.xml")//biocase:response/biocase:content/*:)
(:return {$post//@status}
:)
(:Check for response code 200 from server:)
return
if ( $post[1]/@status eq '200' or $post[1]/@status eq '201' ) then
(:$abcd_data := $post[2]//biocase:response/biocase:content/* :)
(: the document is saved but this div content is not displayed :)
Actions:
- Storing uploaded content to: {$name}
{
xdb:decode-uri(xs:anyURI(xdb:store($colName, xdb:encode-uri($name), $post[2]//biocase:response/biocase:content/*)))
}
else
() (:TODO should indicate that the file has not been uploaded as there was a problem - please check the url and that a valid filename has been entered:)
};
(:
Save metadata file.
:)
declare function browse:save-metadata-old($colName as xs:string) as element()
{
let $data := request:get-data()
let $file-name := rebind:getSetting('metadata-file')
(: check to make sure we have valid post data :)
return
if (not($data))
then
- Problem saving the metadata xml. File is not valid.
else
(
Actions:
- Saved metadata file at: {$file-name}
{
xdb:decode-uri(xs:anyURI(xdb:store($colName, xdb:encode-uri($file-name), $data)))
}
)
};
declare function browse:save-metadata($colName as xs:string) as element()*
{
let $data := request:get-data()
let $file-name := rebind:getSetting('metadata-file')
let $action := request:get-parameter("action", ())[1]
let $save := xdb:store($colName, xdb:encode-uri($file-name), $data)
(: check to make sure we have valid post data :)
(:return if($action eq "save-form") then( :)
return if($data) then(
let $fileName := request:get-parameter("name", "test.xml")[1]
return ()
)else(
- Problem saving the metadata xml. File is not valid.
)
};
(:
publish a project
:)
declare function browse:publish() as element()
{
(: TODO #31: check if there is a project with the same name in the public collection. If so promt a warning and ask if the existing project should be overwritten :)
let $colName := request:get-parameter("project", ())
let $publicRoot := rebind:getSetting('db-public-folder')
let $protectedRoot := rebind:getSetting('db-protected-folder')
let $patternprojectName := fn:concat("^(",$publicRoot,"|",$protectedRoot,")/")
let $patternProjectRoot := fn:concat("^(",$publicRoot,"|",$protectedRoot,")/[^/]+/?$")
let $patternProtectedProject := fn:concat("^",$protectedRoot,"/[^/]+/?")
let $projectName := replace(replace($colName,$patternprojectName,''),"/.*$","")
let $isProjectRoot := matches($colName,$patternProjectRoot)
let $isProtectedProject := matches($colName,$patternProtectedProject)
(: TODO #28: do other integrity checks, give warning if any one fails, like no metadata file, validation fails, etc. :)
(: TODO #28: check if correction is running :)
return if(xdb:is-admin-user(xdb:get-current-user()) and $isProtectedProject and $isProjectRoot) then (
let $move := xdb:move(concat($protectedRoot,"/",$projectName), $publicRoot)
return
Actions:
- Published collection: {$projectName} to '{concat($publicRoot,"/",$projectName)}'
)else()
};
(:
Create a collection.
:)
declare function browse:create-collection($parentColName as xs:string) as element()
{
(: TODO #30: check if name is equal to the correction report folder, if so: do not create new folder :)
let $newcol := request:get-parameter("create", ())
return
Actions:
{
if($newcol) then
(
let $col := xdb:create-collection($parentColName, xdb:encode-uri($newcol)) return
- Created collection: {$col}.
)
else
(
- No name specified for new collection!
)
}
};
(:
Display a list with all the projects
:)
declare function browse:display-projects($colName as xs:string) as element()*
{
let $currentCollection := request:get-parameter("file", "/db")[1]
let $currentCollection := request:get-parameter("collection", $currentCollection)[1]
let $currentCollection := if(not(starts-with($currentCollection,"/db")))then(fn:concat("/db",$currentCollection))else($currentCollection)
return if(count(xdb:get-child-collections($colName)) > 0) then (
{
for $child in xdb:get-child-collections($colName)
let $path := concat($colName, '/', $child),
$created := xdb:created($path)
let $active := ($path eq $currentCollection or fn:starts-with($currentCollection, concat($path, '/')))
let $childName := xdb:decode-uri(xs:anyURI($child))
order by $child
return
-
{if($active)
then({$childName})
else({$childName})
}
}
)else()
};
declare function browse:display-project-collections($colName as xs:string) as element()*
{
let $editLogCollectionName := rebind:getSetting('edit-log-folder-name')
for $child in xdb:get-child-collections($colName)
let $path := concat($colName, '/', $child),
$created := xdb:created($path)
order by $child
return
{if($child eq $editLogCollectionName)then(
{xdb:decode-uri(xs:anyURI($child))}
)else(
{xdb:decode-uri(xs:anyURI($child))}
)}
};
declare function browse:display-project-files($colName as xs:string) as element()*
{
let $protectedRoot := rebind:getSetting('db-protected-folder')
let $patternProtectedProject := fn:concat("^",$protectedRoot,"/[^/]+/?")
let $isProtectedProject := matches($colName,$patternProtectedProject)
for $child at $count in xdb:get-child-resources($colName)
let $restUri := concat(request:get-context-path(), '/rest')
let $eXideUri := concat(request:get-context-path(), '/apps/eXide2/index.html?doc=')
let $extension := fn:replace(fn:lower-case(fn:replace($child, '.*\.','')),'7z','zip7')
let $lastRevision := browse:last-revision($colName, $child)//v:properties/v:revision/string()
let $isMetadata := browse:is-metadata-file($colName, $child)
let $metaTag := if($isMetadata)then(" metadata")else()
order by $child
return
{xdb:decode-uri(xs:anyURI($child))}
|
{if(not($isMetadata))then(
Actions
View
{if($isMetadata and $isProtectedProject)then( Edit)
else if(browse:is-filetype-editable($extension) and $isProtectedProject)then( Edit)else()}
{if(browse:is-filetype-validatable($extension) and not($isMetadata) and $isProtectedProject)then( Validate)else()}
{if(browse:is-filetype-validatable($extension) and $isProtectedProject)then( Start Correction)else()}
) else(
)}
{if($extension eq "xml" and not($isMetadata))then(
let $file-status := browse:get-file-status($colName,$child)
return if(not(empty($file-status)))then(
Status
| open | total |
Error: | {$file-status[1]} | {$file-status[2]} |
Warning: | {$file-status[3]} | {$file-status[4]} |
Info: | {$file-status[5]} | {$file-status[6]} |
)else()
)else()}
|
};
declare function browse:display-project($colName as xs:string) as element()*
{
{browse:display-project-collections($colName)}
{browse:display-project-files($colName)}
};
declare function browse:is-filetype-editable($fileExtension as xs:string) as xs:boolean{
let $editableFiletypes := tokenize(rebind:getSetting('editable-file-types'),",")
return not(empty(index-of($editableFiletypes,$fileExtension)))
};
declare function browse:is-filetype-validatable($fileExtension as xs:string) as xs:boolean{
(: TODO #34: decide if file is editable based on whether it is stored in the XML storage of eXist-db and not based on the file extension :)
let $editableFiletypes := tokenize(rebind:getSetting('validatable-file-types'),",")
return not(empty(index-of($editableFiletypes,$fileExtension)))
};
declare function browse:is-metadata-file($colName as xs:string, $fileName as xs:string) as xs:boolean{
let $metadataFileName := rebind:getSetting('metadata-file')
let $publicRoot := rebind:getSetting('db-public-folder')
let $protectedRoot := rebind:getSetting('db-protected-folder')
let $patternProjectRoot := fn:concat("^(",$publicRoot,"|",$protectedRoot,")/[^/]+/?$")
let $isProjectRoot := matches($colName,$patternProjectRoot)
return if($fileName eq $metadataFileName and $isProjectRoot)then(true())else(false())
};
declare function browse:contains-metadata-file($colName as xs:string) as xs:boolean{
let $metadataFileName := rebind:getSetting('metadata-file')
return not(empty(index-of(xdb:get-child-resources($colName),$metadataFileName)))
};
declare function browse:get-file-status($collectionName as xs:string, $filename as xs:string) as xs:int*{
let $editLogCollectionName := rebind:getSetting('edit-log-folder-name')
let $edit-log := doc(concat($collectionName,'/',$editLogCollectionName,'/',$filename))
return if(exists($edit-log))then(
let $info-unreviewed-count := count($edit-log//edit:edit[@severity="info" and @reviewed="false"])
let $info-total-count := count($edit-log//edit:edit[@severity="info"])
let $warning-unreviewed-count := count($edit-log//edit:edit[@severity="warning" and @reviewed="false"])
let $warning-total-count := count($edit-log//edit:edit[@severity="warning"])
let $error-unreviewed-count := count($edit-log//edit:edit[@severity="error" and @reviewed="false"])
let $error-total-count := count($edit-log//edit:edit[@severity="error"])
let $result := ($error-unreviewed-count,$error-total-count,$warning-unreviewed-count,$warning-total-count,$info-unreviewed-count,$info-total-count)
return $result
)else()
};
declare function browse:last-revision($collection as xs:string, $resource as xs:string) {
let $vCollection := concat("/db/system/versions", $collection)
let $versions :=
for $version in collection($vCollection)/v:version[
v:properties[v:document = $resource]
]
order by xs:long($version/v:properties/v:revision) descending
return $version
return
$versions[1]
};
(:
Get the name of the parent collection from a specified collection path.
:)
declare function browse:get-parent-collection($path as xs:string) as xs:string
{
if($path eq "/db") then
$path
else
replace($path, "/[^/]*$", "")
};