Add the missing XMLSchema constructor functions.

xquery version "3.1";
(:~
 : XPath and XQuery Functions and Operators: Constructor Functions
 :
 : @see https://www.w3.org/TR/2007/REC-xpath-functions-20070123/
 : @see https://www.w3.org/TR/2010/REC-xpath-functions-20101214/
 : @see https://www.w3.org/TR/2014/REC-xpath-functions-30-20140408/
 : @see https://www.w3.org/TR/2017/REC-xpath-functions-31-20170321/
 :)
module namespace xs = "http://www.w3.org/2001/XMLSchema";

declare namespace a = "http://reecedunn.co.uk/xquery/annotations";

(: 18.1 Constructor functions for XML Schema built-in atomic types :)

declare %a:since("xmlschema", "1.0-20010502") function xs:ENTITY($arg as xs:anyAtomicType?) as xs:ENTITY? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:ID($arg as xs:anyAtomicType?) as xs:ID? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:IDREF($arg as xs:anyAtomicType?) as xs:IDREF? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:NCName($arg as xs:anyAtomicType?) as xs:NCName? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:NMTOKEN($arg as xs:anyAtomicType?) as xs:NMTOKEN? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:Name($arg as xs:anyAtomicType?) as xs:Name? external;

declare %a:since("xmlschema", "1.0-20010502") function xs:anyURI($arg as xs:anyAtomicType?) as xs:anyURI? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:base64Binary($arg as xs:anyAtomicType?) as xs:base64Binary? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:boolean($arg as xs:anyAtomicType?) as xs:boolean? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:byte($arg as xs:anyAtomicType?) as xs:byte? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:date($arg as xs:anyAtomicType?) as xs:date? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:dateTime($arg as xs:anyAtomicType?) as xs:dateTime? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:dayTimeDuration($arg as xs:anyAtomicType?) as xs:dayTimeDuration? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:decimal($arg as xs:anyAtomicType?) as xs:decimal? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:double($arg as xs:anyAtomicType?) as xs:double? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:duration($arg as xs:anyAtomicType?) as xs:duration? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:float($arg as xs:anyAtomicType?) as xs:float? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:gDay($arg as xs:anyAtomicType?) as xs:gDay? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:gMonth($arg as xs:anyAtomicType?) as xs:gMonth? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:gMonthDay($arg as xs:anyAtomicType?) as xs:gMonthDay? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:gYear($arg as xs:anyAtomicType?) as xs:gYear? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:gYearMonth($arg as xs:anyAtomicType?) as xs:gYearMonth? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:hexBinary($arg as xs:anyAtomicType?) as xs:hexBinary? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:int($arg as xs:anyAtomicType?) as xs:int? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:integer($arg as xs:anyAtomicType?) as xs:integer? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:language($arg as xs:anyAtomicType?) as xs:language? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:long($arg as xs:anyAtomicType?) as xs:long? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:negativeInteger($arg as xs:anyAtomicType?) as xs:negativeInteger? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:nonNegativeInteger($arg as xs:anyAtomicType?) as xs:nonNegativeInteger? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:nonPositiveInteger($arg as xs:anyAtomicType?) as xs:nonPositiveInteger? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:normalizedString($arg as xs:anyAtomicType?) as xs:normalizedString? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:positiveInteger($arg as xs:anyAtomicType?) as xs:positiveInteger? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:short($arg as xs:anyAtomicType?) as xs:short? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:string($arg as xs:anyAtomicType?) as xs:string? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:time($arg as xs:anyAtomicType?) as xs:time? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:token($arg as xs:anyAtomicType?) as xs:token? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:unsignedByte($arg as xs:anyAtomicType?) as xs:unsignedByte? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:unsignedInt($arg as xs:anyAtomicType?) as xs:unsignedInt? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:unsignedLong($arg as xs:anyAtomicType?) as xs:unsignedLong? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:unsignedShort($arg as xs:anyAtomicType?) as xs:unsignedShort? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:untypedAtomic($arg as xs:anyAtomicType?) as xs:untypedAtomic? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:yearMonthDuration($arg as xs:anyAtomicType?) as xs:yearMonthDuration? external;
declare %a:since("xmlschema", "1.1-20120405") function xs:dateTimeStamp($arg as xs:anyAtomicType?) as xs:dateTimeStamp? external;

(: 18.2 Constructor functions for xs:QName and xs:NOTATION :)

declare %a:restrict-until("$arg", "xmlschema", "1.1-20120405", "xs:anyAtomicType")
        %a:since("xmlschema", "1.0-20010502") function xs:QName($arg as xs:anyAtomicType?) as xs:QName? external;

(: 18.3 Constructor functions for XML Schema built-in list types :)

declare %a:since("xmlschema", "1.0-20010502") function xs:NMTOKENS($arg as xs:anyAtomicType?) as xs:NMTOKEN* external;
declare %a:since("xmlschema", "1.0-20010502") function xs:ENTITIES($arg as xs:anyAtomicType?) as xs:ENTITY* external;
declare %a:since("xmlschema", "1.0-20010502") function xs:IDREFS($arg as xs:anyAtomicType?) as xs:IDREF* external;

(: 18.4 Constructor functions for XML Schema built-in union types :)

declare %a:since("xmlschema", "1.0-20010502") function xs:numeric($arg as xs:anyAtomicType?) as xs:numeric? external;

xquery version "3.1";
(:~
 : XPath and XQuery Functions and Operators: Constructor Functions
 :
 : @see https://www.w3.org/TR/2007/REC-xpath-functions-20070123/
 : @see https://www.w3.org/TR/2010/REC-xpath-functions-20101214/
 : @see https://www.w3.org/TR/2014/REC-xpath-functions-30-20140408/
 : @see https://www.w3.org/TR/2017/REC-xpath-functions-31-20170321/
 :)
module namespace xs = "http://www.w3.org/2001/XMLSchema";

declare namespace a = "http://reecedunn.co.uk/xquery/annotations";

declare %a:since("xmlschema", "1.0-20010502") function xs:ENTITY($arg as xs:anyAtomicType?) as xs:ENTITY? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:ID($arg as xs:anyAtomicType?) as xs:ID? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:IDREF($arg as xs:anyAtomicType?) as xs:IDREF? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:NCName($arg as xs:anyAtomicType?) as xs:NCName? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:NMTOKEN($arg as xs:anyAtomicType?) as xs:NMTOKEN? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:Name($arg as xs:anyAtomicType?) as xs:Name? external;
declare %a:restrict-until("$arg", "xmlschema", "1.1-20120405", "xs:anyAtomicType")
        %a:since("xmlschema", "1.0-20010502") function xs:QName($arg as xs:anyAtomicType?) as xs:QName? external;

declare %a:since("xmlschema", "1.0-20010502") function xs:anyURI($arg as xs:anyAtomicType?) as xs:anyURI? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:base64Binary($arg as xs:anyAtomicType?) as xs:base64Binary? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:boolean($arg as xs:anyAtomicType?) as xs:boolean? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:byte($arg as xs:anyAtomicType?) as xs:byte? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:date($arg as xs:anyAtomicType?) as xs:date? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:dateTime($arg as xs:anyAtomicType?) as xs:dateTime? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:dayTimeDuration($arg as xs:anyAtomicType?) as xs:dayTimeDuration? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:decimal($arg as xs:anyAtomicType?) as xs:decimal? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:double($arg as xs:anyAtomicType?) as xs:double? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:duration($arg as xs:anyAtomicType?) as xs:duration? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:float($arg as xs:anyAtomicType?) as xs:float? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:gDay($arg as xs:anyAtomicType?) as xs:gDay? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:gMonth($arg as xs:anyAtomicType?) as xs:gMonth? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:gMonthDay($arg as xs:anyAtomicType?) as xs:gMonthDay? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:gYear($arg as xs:anyAtomicType?) as xs:gYear? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:gYearMonth($arg as xs:anyAtomicType?) as xs:gYearMonth? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:hexBinary($arg as xs:anyAtomicType?) as xs:hexBinary? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:int($arg as xs:anyAtomicType?) as xs:int? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:integer($arg as xs:anyAtomicType?) as xs:integer? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:language($arg as xs:anyAtomicType?) as xs:language? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:long($arg as xs:anyAtomicType?) as xs:long? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:negativeInteger($arg as xs:anyAtomicType?) as xs:negativeInteger? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:nonNegativeInteger($arg as xs:anyAtomicType?) as xs:nonNegativeInteger? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:nonPositiveInteger($arg as xs:anyAtomicType?) as xs:nonPositiveInteger? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:normalizedString($arg as xs:anyAtomicType?) as xs:normalizedString? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:positiveInteger($arg as xs:anyAtomicType?) as xs:positiveInteger? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:short($arg as xs:anyAtomicType?) as xs:short? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:string($arg as xs:anyAtomicType?) as xs:string? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:time($arg as xs:anyAtomicType?) as xs:time? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:token($arg as xs:anyAtomicType?) as xs:token? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:unsignedByte($arg as xs:anyAtomicType?) as xs:unsignedByte? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:unsignedInt($arg as xs:anyAtomicType?) as xs:unsignedInt? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:unsignedLong($arg as xs:anyAtomicType?) as xs:unsignedLong? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:unsignedShort($arg as xs:anyAtomicType?) as xs:unsignedShort? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:untypedAtomic($arg as xs:anyAtomicType?) as xs:untypedAtomic? external;
declare %a:since("xmlschema", "1.0-20010502") function xs:yearMonthDuration($arg as xs:anyAtomicType?) as xs:yearMonthDuration? external;
declare %a:since("xmlschema", "1.1-20120405") function xs:dateTimeStamp($arg as xs:anyAtomicType?) as xs:dateTimeStamp? external;


adding a tag to track updated records

adding a tag to track updated records

module namespace page = 'http://basex.org/modules/web-page';
import module namespace csd_bl = "https://github.com/openhie/openinfoman/csd_bl";
import module namespace functx = 'http://www.functx.com';
import module namespace csr_proc = "https://github.com/openhie/openinfoman/csr_proc";
import module namespace csd_webui =  "https://github.com/openhie/openinfoman/csd_webui";
import module namespace csd_dm = "https://github.com/openhie/openinfoman/csd_dm";
declare namespace fhir = "http://hl7.org/fhir";
declare namespace csd =  "urn:ihe:iti:csd:2013";
declare default element  namespace   "urn:ihe:iti:csd:2013";

declare function page:get_location ($doc_name,$_id,$page,$_count,$_since)
{
  <CSD xmlns:csd="urn:ihe:iti:csd:2013"  >
    {
      let $search_collection :=
      <collection>
        <search directory="facilityDirectory">urn:ihe:iti:csd:2014:stored-function:facility-search</search>
        <search directory="organizationDirectory">urn:ihe:iti:csd:2014:stored-function:organization-search</search>
      </collection>
      for $search in $search_collection/search
      let $search_name := $search/text()
      return
      (
        let $careServicesSubRequest :=
        <csd:careServicesRequest>
          <csd:function urn="{$search_name}" resource="{$doc_name}" base_url="{csd_webui:generateURL('')}">
            <csd:requestParams>
              {
                let $id := $_id
                return if (functx:all-whitespace($id)) then () else <csd:id entityID="{$id}"/>
              }

              {
                let $t_start := $page
                return if (functx:is-a-number($t_start))
                  then
                    let $start := max((xs:int($t_start),1))
                    let $t_count := $_count
                    let $count := if(functx:is-a-number($t_count)) then  max((xs:int($t_count),1)) else 50
                    let $startIndex := ($start - 1)*$count + 1
                    return <csd:start>{$startIndex}</csd:start>
                  else ()
              }
         {
           let $count := $_count
           return
              if(functx:is-a-number($count))
              then  <csd:max>{max((xs:int($count),1))} </csd:max>
              else ()
         }
         {
          let $since := $_since
          return if (functx:all-whitespace($since)) then () else <csd:record updated="{$since}"/>
         }
            </csd:requestParams>
          </csd:function>
        </csd:careServicesRequest>

        let $doc :=  csd_dm:open_document($doc_name)
        let $contents := csr_proc:process_CSR_stored_results( $doc , $careServicesSubRequest)
        let $directory := $search/@directory/string()
        return $contents/*[name() = $directory]
      )
    }
  </CSD>
};

declare
  %rest:path("/FHIR/{$doc_name}/Location/{$id}")
  %rest:query-param("page", "{$page}")
  %rest:query-param("_count", "{$_count}")
  %rest:query-param("_since", "{$_since}")
  %rest:GET
  function page:FHIRID($id,$page,$_count,$_since,$doc_name)
{
  page:FHIR($id,$page,$_count,$_since,$doc_name)
};

declare
  %rest:path("/FHIR/{$doc_name}/Location/_history")
  %rest:query-param("_id", "{$_id}")
  %rest:query-param("page", "{$page}")
  %rest:query-param("_count", "{$_count}")
  %rest:query-param("_since", "{$_since}")
  %rest:GET
  function page:FHIR($_id,$page,$_count,$_since,$doc_name)
{
let $contents := page:get_location ($doc_name,$_id,$page,$_count,$_since)

let $location :=
<json type='object'>
<resourceType>Bundle</resourceType>
<total>{count($contents/facilityDirectory/facility) + count($contents/organizationDirectory/organization)}</total>
<type>history</type>
<entry type="array">
{
for $content in ($contents/facilityDirectory/facility,$contents/organizationDirectory/organization)
return
<_ type="object">
{
  <fullURL>{csd_webui:generateURL("FHIR/" || $doc_name || "/Location/" || $content/@entityID)}</fullURL>,
  <resource type="object">
    <resourceType>Location</resourceType>
    {
      if($content/record/@created/string() != $content/record/@updated/string())
      then
      <request type="object">
        <method>PUT</method>
        <url>Location/{$content/@entityID/string()}</url>
      </request>
      else()
    }
    <id>{$content/@entityID/string()}</id>
    {
     if(exists($content/otherID))
     then
     <identifier type="array">
      {
      for $otherid in $content/otherID
      return
      <_ type="object">
        <system>{$otherid/@assigningAuthorityName/string()}/{$otherid/@code/string()}</system>
        <value>{$otherid/text()}</value>
      </_>
      }
     </identifier>
     else ()
    }
    {
      let $search_name := "urn:ihe:iti:csd:2014:stored-function:organization-search"
      let $parent :=
      if(exists($content/organizations/organization))
      then
      $content/organizations/organization/@entityID/string()
      else
      if (exists($content/parent))
      then $content/parent/@entityID/string()
      else ()

      return if($parent)
      then
      let $careServicesSubRequest :=
      <csd:careServicesRequest>
        <csd:function urn="{$search_name}" resource="{$doc_name}" base_url="{csd_webui:generateURL()}">
          <csd:requestParams>
            <csd:id entityID="{$parent}"/>
          </csd:requestParams>
        </csd:function>
      </csd:careServicesRequest>
      let $doc :=  csd_dm:open_document($doc_name)
      let $organization := csr_proc:process_CSR_stored_results( $doc , $careServicesSubRequest)
      return if(exists($organization/organizationDirectory/organization))
      then
      <partOf type="object">
        <reference>{csd_webui:generateURL("FHIR/" || $doc_name || "/Location/" || $organization/organizationDirectory/organization/@entityID/string())}</reference>
        <display>{$organization/organizationDirectory/organization/primaryName/text()}</display>
      </partOf>
      else ()
      else ()
    }
    {
    if(exists($content/contactPoint))
    then
    <telecom type="array">
     {
     for $contactPoint in $content/contactPoint
     return ()
     }
    </telecom>
    else ()
    }
    {
      if(exists($content/geocode))
      then
      <position type="object">
        <longitude>{$content/geocode/longitude/text()}</longitude>
        <latitude>{$content/geocode/latitude/text()}</latitude>
      </position>
      else ()
    }
    <meta type="object">
     <lastUpdated>{$content/record/@updated/string()}</lastUpdated>
    <tag type="array">
      <_ type="object">
        {$content/record/@sourceDirectory/string()}
        <system>https://github.com/openhie/openinfoman/tags/fhir/sourceDirectory</system>
      </_>
    </tag>
    </meta>
    {
      if(exists($content/codedType))
      then
        <type type="object">
          <coding type="array">
            {
              for $codedType in $content/codedType
                return
                <_ type="object">
                  {$codedType/@code/string()}
                  <system>{$codedType/@codingScheme/string()}</system>
                  {
                  if(functx:all-whitespace($codedType/text()))
                  then ()
                  else
                  <display>{$codedType/text()}</display>
                  }
                </_>
            }
          </coding>
        </type>
      else ()
    }
  </resource>,
  <status>{$content/record/@status/string()}</status>,
  <name>{$content/primaryName/text()}</name>,
  <mode>instance</mode>
}
</_>
}
</entry>
</json>

return (
  <rest:response>
    <output:serialization-parameters>
      <output:media-type value='application/json'/>
    </output:serialization-parameters>
  </rest:response>,
  json:serialize($location,map{"format":"direct",'escape': 'no'})
  )

};

declare
  %rest:path("/test")
  %rest:query-param("_id", "{$_id}")
  %rest:query-param("page", "{$page}")
  %rest:query-param("_count", "{$_count}")
  %rest:query-param("_since", "{$_since}")
  %rest:query-param("doc_name", "{$doc_name}")
  %rest:GET
  function page:test($_id,$page,$_count,$_since,$doc_name)
{
let $contents := page:get_location ($doc_name,$_id,$page,$_count,$_since)
return $contents/organizationDirectory/organization
};

module namespace page = 'http://basex.org/modules/web-page';
import module namespace csd_bl = "https://github.com/openhie/openinfoman/csd_bl";
import module namespace functx = 'http://www.functx.com';
import module namespace csr_proc = "https://github.com/openhie/openinfoman/csr_proc";
import module namespace csd_webui =  "https://github.com/openhie/openinfoman/csd_webui";
import module namespace csd_dm = "https://github.com/openhie/openinfoman/csd_dm";
declare namespace fhir = "http://hl7.org/fhir";
declare namespace csd =  "urn:ihe:iti:csd:2013";
declare default element  namespace   "urn:ihe:iti:csd:2013";

declare function page:get_location ($doc_name,$_id,$page,$_count,$_since)
{
  <CSD xmlns:csd="urn:ihe:iti:csd:2013"  >
    {
      let $search_collection :=
      <collection>
        <search directory="facilityDirectory">urn:ihe:iti:csd:2014:stored-function:facility-search</search>
        <search directory="organizationDirectory">urn:ihe:iti:csd:2014:stored-function:organization-search</search>
      </collection>
      for $search in $search_collection/search
      let $search_name := $search/text()
      return
      (
        let $careServicesSubRequest :=
        <csd:careServicesRequest>
          <csd:function urn="{$search_name}" resource="{$doc_name}" base_url="{csd_webui:generateURL('')}">
            <csd:requestParams>
              {
                let $id := $_id
                return if (functx:all-whitespace($id)) then () else <csd:id entityID="{$id}"/>
              }

              {
                let $t_start := $page
                return if (functx:is-a-number($t_start))
                  then
                    let $start := max((xs:int($t_start),1))
                    let $t_count := $_count
                    let $count := if(functx:is-a-number($t_count)) then  max((xs:int($t_count),1)) else 50
                    let $startIndex := ($start - 1)*$count + 1
                    return <csd:start>{$startIndex}</csd:start>
                  else ()
              }
         {
           let $count := $_count
           return
              if(functx:is-a-number($count))
              then  <csd:max>{max((xs:int($count),1))} </csd:max>
              else ()
         }
         {
          let $since := $_since
          return if (functx:all-whitespace($since)) then () else <csd:record updated="{$since}"/>
         }
            </csd:requestParams>
          </csd:function>
        </csd:careServicesRequest>

        let $doc :=  csd_dm:open_document($doc_name)
        let $contents := csr_proc:process_CSR_stored_results( $doc , $careServicesSubRequest)
        let $directory := $search/@directory/string()
        return $contents/*[name() = $directory]
      )
    }
  </CSD>
};

declare
  %rest:path("/FHIR/{$doc_name}/Location/_history/{$id}")
  %rest:query-param("page", "{$page}")
  %rest:query-param("_count", "{$_count}")
  %rest:query-param("_since", "{$_since}")
  %rest:GET
  function page:FHIRID($id,$page,$_count,$_since,$doc_name)
{
  page:FHIR($id,$page,$_count,$_since,$doc_name)
};

declare
  %rest:path("/FHIR/{$doc_name}/Location/_history")
  %rest:query-param("_id", "{$_id}")
  %rest:query-param("page", "{$page}")
  %rest:query-param("_count", "{$_count}")
  %rest:query-param("_since", "{$_since}")
  %rest:GET
  function page:FHIR($_id,$page,$_count,$_since,$doc_name)
{
let $contents := page:get_location ($doc_name,$_id,$page,$_count,$_since)

let $location :=
<json type='object'>
<resourceType>Bundle</resourceType>
<total>{count($contents/facilityDirectory/facility) + count($contents/organizationDirectory/organization)}</total>
<type>history</type>
<entry type="array">
{
for $content in ($contents/facilityDirectory/facility,$contents/organizationDirectory/organization)
return
<_ type="object">
{
  <fullURL>{csd_webui:generateURL("FHIR/" || $doc_name || "/Location/_history/" || $content/@entityID)}</fullURL>,
  <resource type="object">
    <resourceType>Location</resourceType>
    <id>{$content/@entityID/string()}</id>
    {
     if(exists($content/otherID))
     then
     <identifier type="array">
      {
      for $otherid in $content/otherID
      return
      <_ type="object">
        <system>{$otherid/@assigningAuthorityName/string()}/{$otherid/@code/string()}</system>
        <value>{$otherid/text()}</value>
      </_>
      }
     </identifier>
     else ()
    }
    {
      let $search_name := "urn:ihe:iti:csd:2014:stored-function:organization-search"
      let $parent :=
      if(exists($content/organizations/organization))
      then
      $content/organizations/organization/@entityID/string()
      else
      if (exists($content/parent))
      then $content/parent/@entityID/string()
      else ()

      return if($parent)
      then
      let $careServicesSubRequest :=
      <csd:careServicesRequest>
        <csd:function urn="{$search_name}" resource="{$doc_name}" base_url="{csd_webui:generateURL()}">
          <csd:requestParams>
            <csd:id entityID="{$parent}"/>
          </csd:requestParams>
        </csd:function>
      </csd:careServicesRequest>
      let $doc :=  csd_dm:open_document($doc_name)
      let $organization := csr_proc:process_CSR_stored_results( $doc , $careServicesSubRequest)
      return if(exists($organization/organizationDirectory/organization))
      then
      <partOf type="object">
        <reference>{csd_webui:generateURL("FHIR/" || $doc_name || "/Location/_history/" || $organization/organizationDirectory/organization/@entityID/string())}</reference>
        <display>{$organization/organizationDirectory/organization/primaryName/text()}</display>
      </partOf>
      else ()
      else ()
    }
    {
    if(exists($content/contactPoint))
    then
    <telecom type="array">
     {
     for $contactPoint in $content/contactPoint
     return ()
     }
    </telecom>
    else ()
    }
    {
      if(exists($content/geocode))
      then
      <position type="object">
        <longitude>{$content/geocode/longitude/text()}</longitude>
        <latitude>{$content/geocode/latitude/text()}</latitude>
      </position>
      else ()
    }
    <meta type="object">
     <lastUpdated>{$content/record/@updated/string()}</lastUpdated>
    <tag type="array">
      <_ type="object">
        {$content/record/@sourceDirectory/string()}
        <system>https://github.com/openhie/openinfoman/tags/fhir/sourceDirectory</system>
      </_>
    </tag>
    </meta>
    {
      if(exists($content/codedType))
      then
        <type type="object">
          <coding type="array">
            {
              for $codedType in $content/codedType
                return
                <_ type="object">
                  {$codedType/@code/string()}
                  <system>{$codedType/@codingScheme/string()}</system>
                  {
                  if(functx:all-whitespace($codedType/text()))
                  then ()
                  else
                  <display>{$codedType/text()}</display>
                  }
                </_>
            }
          </coding>
        </type>
      else ()
    }
  </resource>,
  <status>{$content/record/@status/string()}</status>,
  <name>{$content/primaryName/text()}</name>,
  <mode>instance</mode>
}
</_>
}
</entry>
</json>

return (
  <rest:response>
    <output:serialization-parameters>
      <output:media-type value='application/json'/>
    </output:serialization-parameters>
  </rest:response>,
  json:serialize($location,map{"format":"direct",'escape': 'no'})
  )

};

declare
  %rest:path("/test")
  %rest:query-param("_id", "{$_id}")
  %rest:query-param("page", "{$page}")
  %rest:query-param("_count", "{$_count}")
  %rest:query-param("_since", "{$_since}")
  %rest:query-param("doc_name", "{$doc_name}")
  %rest:GET
  function page:test($_id,$page,$_count,$_since,$doc_name)
{
let $contents := page:get_location ($doc_name,$_id,$page,$_count,$_since)
return $contents/organizationDirectory/organization
};


add proper namespace declaration

add proper namespace declaration

xquery version "3.1";

(:~
 : these tests were created because of
 : https://github.com/eXist-db/exist/issues/1379
~:)

module namespace ct="http://exist-db.org/xquery/test/question-marks-in-contains-function";

declare namespace tei="http://www.tei-c.org/ns/1.0";
declare namespace test="http://exist-db.org/xquery/xqsuite";
declare namespace xmldb="http://exist-db.org/xquery/xmldb";

declare variable $ct:test :=
    <root>
        <persName xmlns="http://www.tei-c.org/ns/1.0">
            <surname>Hering</surname>, <forename>S(amuel?)</forename>
        </persName>
        <persName xmlns="http://www.tei-c.org/ns/1.0">
            <surname>Hering</surname>, <forename>Samuel</forename>
        </persName>
    </root>;

declare variable $ct:xconf :=
    <collection xmlns="http://exist-db.org/collection-config/1.0">
        <index xmlns:tei="http://www.tei-c.org/ns/1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
            <range>
                <create qname="tei:surname" type="xs:string"/>
                <create qname="tei:forename" type="xs:string"/>
                <create qname="tei:persName" type="xs:string"/>
            </range>
        </index>
    </collection>;

declare
        %test:setUp
function ct:setup() {
    xmldb:create-collection("/db/system/config/db", "test"),
    xmldb:store("/db/system/config/db/test", "collection.xconf", $ct:xconf),
    xmldb:create-collection("/db", "test"),
    xmldb:store("/db/test", "test.xml", $ct:test)
};

declare
        %test:tearDown
function ct:teardown() {
    xmldb:remove("/db/test"),
    xmldb:remove("/db/system/config/db/test")
};

declare
        %test:pending("https://github.com/eXist-db/exist/issues/1379")
        %test:assertEquals(1)
function ct:element-contains-question-mark() {
    let $hits := doc("/db/test/test.xml")//tei:forename[fn:contains(., "?")]
    return
        count($hits)
};

declare
        %test:pending("https://github.com/eXist-db/exist/issues/1379")
        %test:assertEquals(0)
function ct:element-contains-escaped-question-mark() {
    let $hits := doc("/db/test/test.xml")//tei:forename[fn:contains(., "\?")]
    return
        count($hits)
};

declare
        %test:pending("https://github.com/eXist-db/exist/issues/1379")
        %test:assertEquals(1)
function ct:parent-element-contains-question-mark() {
    let $hits := doc("/db/test/test.xml")//tei:persName[fn:contains(., "?")]
    return
        count($hits)
};

declare
        %test:assertEquals(0)
function ct:parent-element-contains-escaped-question-mark() {
    let $hits := doc("/db/test/test.xml")//tei:persName[fn:contains(., "\?")]
    return
        count($hits)
};

xquery version "3.1";

(:~
 : these tests were created because of
 : https://github.com/eXist-db/exist/issues/1379
~:)

module namespace ct="http://exist-db.org/xquery/test/question-marks-in-contains-function";

declare namespace tei="http://www.tei-c.org/ns/1.0";
declare namespace test="http://exist-db.org/xquery/xqsuite";

declare variable $ct:test :=
    <root>
        <persName xmlns="http://www.tei-c.org/ns/1.0">
            <surname>Hering</surname>, <forename>S(amuel?)</forename>
        </persName>
        <persName xmlns="http://www.tei-c.org/ns/1.0">
            <surname>Hering</surname>, <forename>Samuel</forename>
        </persName>
    </root>;

declare variable $ct:xconf :=
    <collection xmlns="http://exist-db.org/collection-config/1.0">
        <index xmlns:tei="http://www.tei-c.org/ns/1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
            <range>
                <create qname="tei:surname" type="xs:string"/>
                <create qname="tei:forename" type="xs:string"/>
                <create qname="tei:persName" type="xs:string"/>
            </range>
        </index>
    </collection>;

declare
        %test:setUp
function ct:setup() {
    xmldb:create-collection("/db/system/config/db", "test"),
    xmldb:store("/db/system/config/db/test", "collection.xconf", $ct:xconf),
    xmldb:create-collection("/db", "test"),
    xmldb:store("/db/test", "test.xml", $ct:test)
};

declare
        %test:tearDown
function ct:teardown() {
    xmldb:remove("/db/test"),
    xmldb:remove("/db/system/config/db/test")
};

declare
        %test:pending("https://github.com/eXist-db/exist/issues/1379")
        %test:assertEquals(1)
function ct:element-contains-question-mark() {
    let $hits := doc("/db/test/test.xml")//tei:forename[fn:contains(., "?")]
    return
        count($hits)
};

declare
        %test:pending("https://github.com/eXist-db/exist/issues/1379")
        %test:assertEquals(0)
function ct:element-contains-escaped-question-mark() {
    let $hits := doc("/db/test/test.xml")//tei:forename[fn:contains(., "\?")]
    return
        count($hits)
};

declare
        %test:pending("https://github.com/eXist-db/exist/issues/1379")
        %test:assertEquals(1)
function ct:parent-element-contains-question-mark() {
    let $hits := doc("/db/test/test.xml")//tei:persName[fn:contains(., "?")]
    return
        count($hits)
};

declare
        %test:assertEquals(0)
function ct:parent-element-contains-escaped-question-mark() {
    let $hits := doc("/db/test/test.xml")//tei:persName[fn:contains(., "\?")]
    return
        count($hits)
};


Futher collection permissions checks

Futher collection permissions checks

svn path=/trunk/eXist/; revision=12874

xquery version "1.0";

module namespace security="http://exist-db.org/mods/security";

import module namespace config="http://exist-db.org/mods/config" at "config.xqm";
declare namespace session="http://exist-db.org/xquery/session";
declare namespace xmldb="http://exist-db.org/xquery/xmldb";

declare variable $security:GUEST_CREDENTIALS := ("guest", "guest");
declare variable $security:SESSION_USER_ATTRIBUTE := "biblio.user";
declare variable $security:SESSION_PASSWORD_ATTRIBUTE := "biblio.password";

declare variable $security:biblio-users-group := "biblio.users";
declare variable $security:users-collection := fn:concat($config:mods-root, "/users");

(:~
: Authenticates a user and creates their mods home collection if it does not exist
:
: @param user The username of the user
: @param password The password of the user
:)
declare function security:login($user as xs:string, $password as xs:string?) as xs:boolean
{
    (: authenticate against eXist-db :)
    if(xmldb:login("/db", $user, $password))then
    (
        (: check if the users mods home collectin exists, if not create it (i.e. first login) :)
        if(security:home-collection-exists($user))then
            true()
        else
        (
            let $users-collection-uri := security:create-home-collection($user) return
                true()
        )
    ) else
        (: authentication failed:)
        false()
};

(:~
: Stores a users credentials for the mods app into the http session
:
: @param user The username
: @param password The password
:)
declare function security:store-user-credential-in-session($user as xs:string, $password as xs:string?) as empty()
{
    session:set-attribute($security:SESSION_USER_ATTRIBUTE, $user),
    session:set-attribute($security:SESSION_PASSWORD_ATTRIBUTE, $password)
};

(:~
: Retrieves a users credentials for the mods app from the http session
:
: @return The sequence (username as xs:string, password as xs:string)
: If there is no entry in the session, then the guest account credentials are returned
:)
declare function security:get-user-credential-from-session() as xs:string+
{
    let $user := session:get-attribute($security:SESSION_USER_ATTRIBUTE) return
        if($user)then
        (
            $user,
            session:get-attribute($security:SESSION_PASSWORD_ATTRIBUTE)
        )
        else
            $security:GUEST_CREDENTIALS
};

(:~
: Checks whether a users mods home collection exists
:
: @param user The username
:)
declare function security:home-collection-exists($user as xs:string) as xs:boolean
{
   xmldb:collection-available(security:get-home-collection-uri($user))
};

(:~
: Get the URI of a users mods home collection
:)
declare function security:get-home-collection-uri($user as xs:string) as xs:string
{
    fn:concat($security:users-collection, "/", $user)
};

(:~
: Creates a users mods home collection and sets permissions
:
: @return The uri of the users home collection or an empty sequence if it could not be created
:)
declare function security:create-home-collection($user as xs:string) as xs:string?
{
    if(xmldb:collection-available($security:users-collection))then
    (
        let $collection-uri := xmldb:create-collection($security:users-collection, $user) return
            if($collection-uri) then
            (
                let $null := xmldb:set-collection-permissions($collection-uri, $user, xmldb:get-user-primary-group($user), xmldb:string-to-permissions("rwu------")) return
                    $collection-uri
            ) else (
                $collection-uri
            )
    )else()
};

(:~
: Determines if a user has read access to a collection
:
: @param user The username
: @param collection The path of the collection
:)
declare function security:can-read-collection($user as xs:string, $collection as xs:string) as xs:boolean
{
    if(xmldb:collection-available($collection))then
    (
        let $permissions := xmldb:permissions-to-string(xmldb:get-permissions($collection))
        let $owner := xmldb:get-owner($collection)
        let $group := xmldb:get-group($collection)
        let $users-groups := xmldb:get-user-groups($user)
        return
            if ($owner eq $user) then
                fn:substring($permissions, 1, 1) eq 'r'
            else if ($group = $users-groups) then
                fn:substring($permissions, 4, 1) eq 'r'
            else
                fn:substring($permissions, 7, 1) eq 'r'
    )
    else
    (
        false()
    )
};

(:~
: Determines if a user has write access to a collection
:
: @param user The username
: @param collection The path of the collection
:)
declare function security:can-write-collection($user as xs:string, $collection as xs:string) as xs:boolean
{
    if(xmldb:collection-available($collection))then
    (
        let $permissions := xmldb:permissions-to-string(xmldb:get-permissions($collection))
        let $owner := xmldb:get-owner($collection)
        let $group := xmldb:get-group($collection)
        let $users-groups := xmldb:get-user-groups($user)
        return
            if ($owner eq $user) then
                fn:substring($permissions, 2, 1) eq 'w'
            else if ($group = $users-groups) then
                fn:substring($permissions, 5, 1) eq 'w'
            else
                fn:substring($permissions, 8, 1) eq 'w'
    )
    else
    (
        false()
    )
};

(:~
: Determines if a group has read access to a collection
:
: @param group The group name
: @param collection The path of the collection
:)
declare function security:group-can-read-collection($group as xs:string, $collection as xs:string) as xs:boolean
{
    if(xmldb:collection-available($collection))then
    (
        let $permissions := xmldb:permissions-to-string(xmldb:get-permissions($collection))
        let $owner-group := xmldb:get-group($collection)
        return
            ($group eq $owner-group and fn:substring($permissions, 4, 1) eq 'r')
    )
    else
    (
        false()
    )
};

(:~
: Determines if a group has write access to a collection
:
: @param group The group name
: @param collection The path of the collection
:)
declare function security:group-can-write-collection($group as xs:string, $collection as xs:string) as xs:boolean
{
    if(xmldb:collection-available($collection))then
    (
        let $permissions := xmldb:permissions-to-string(xmldb:get-permissions($collection))
        let $owner-group := xmldb:get-group($collection)
        return
         ($group eq $owner-group and fn:substring($permissions, 5, 1) eq 'w')
    )
    else
    (
        false()
    )
};

(:~
: Determines if everyone has read access to a collection
:
: @param collection The path of the collection
:)
declare function security:other-can-read-collection($collection as xs:string) as xs:boolean
{
    if(xmldb:collection-available($collection))then
    (
        let $permissions := xmldb:permissions-to-string(xmldb:get-permissions($collection))
        return
            fn:substring($permissions, 7, 1) eq 'r'
    )
    else
    (
        false()
    )
};

(:~
: Determines if everyone has write access to a collection
:
: @param collection The path of the collection
:)
declare function security:other-can-write-collection($collection as xs:string) as xs:boolean
{
    if(xmldb:collection-available($collection))then
    (
        let $permissions := xmldb:permissions-to-string(xmldb:get-permissions($collection))
        return
            fn:substring($permissions, 8, 1) eq 'w'
    )
    else
    (
        false()
    )
};

(:~
: Determines if the user is the collection owner
:
: @param user The username
: @param collection The path of the collection
:)
declare function security:is-collection-owner($user as xs:string, $collection as xs:string) as xs:boolean
{
    if(xmldb:collection-available($collection))then
    (
        let $owner := xmldb:get-owner($collection) return
            $user eq $owner
    )
    else
    (
        false()
    )
};

(:~
: Gets the users for a group
:
: @param the group name
: @return The list of users in the group
:)
declare function security:get-group-members($group as xs:string) as xs:string*
{
    xmldb:get-users($group)
};

(:~
: Gets a list of other biblio users
:)
declare function security:get-other-biblio-users() as xs:string*
{
    security:get-group-members($security:biblio-users-group)[. ne security:get-user-credential-from-session()[1]]
};

declare function security:get-group($collection as xs:string) as xs:string?
{
    if(xmldb:collection-available($collection))then
    (
        xmldb:get-group($collection)
    ) else()
};

declare function security:set-other-can-read-collection($collection, $read as xs:boolean) as xs:boolean
{
    let $permissions := xmldb:permissions-to-string(xmldb:get-permissions($collection)) return
        let $new-permissions := if($read)then(
            fn:replace($permissions, "(......)(.)(..)", "$1r$3")
        ) else (
           fn:replace($permissions, "(......)(.)(..)", "$1-$3")
        )
        return
            xmldb:set-collection-permissions($collection, xmldb:get-owner($collection), xmldb:get-group($collection), xmldb:string-to-permissions($new-permissions)),

            true()
};

declare function security:set-other-can-write-collection($collection, $write as xs:boolean) as xs:boolean
{
    let $permissions := xmldb:permissions-to-string(xmldb:get-permissions($collection)) return
        let $new-permissions := if($write)then(
            fn:replace($permissions, "(.......)(.)(.)", "$1w$3")
        ) else (
           fn:replace($permissions, "(.......)(.)(.)", "$1-$3")
        )
        return
            xmldb:set-collection-permissions($collection, xmldb:get-owner($collection), xmldb:get-group($collection), xmldb:string-to-permissions($new-permissions)),

            true()
};

declare function security:set-group-can-read-collection($collection, $read as xs:boolean) as xs:boolean
{
    security:set-group-can-write-collection($collection, xmldb:get-group($collection), $read)
};

declare function security:set-group-can-write-collection($collection, $write as xs:boolean) as xs:boolean
{
    security:set-group-can-write-collection($collection, xmldb:get-group($collection), $write)
};

declare function security:set-group-can-read-collection($collection, $group as xs:string, $read as xs:boolean) as xs:boolean
{
    let $permissions := xmldb:permissions-to-string(xmldb:get-permissions($collection)) return
        let $new-permissions := if($read)then(
            fn:replace($permissions, "(...)(.)(.....)", "$1r$3")
        ) else (
           fn:replace($permissions, "(...)(.)(.....)", "$1-$3")
        )
        return
            xmldb:set-collection-permissions($collection, xmldb:get-owner($collection), $group, xmldb:string-to-permissions($new-permissions)),

            true()
};

declare function security:set-group-can-write-collection($collection, $group as xs:string, $write as xs:boolean) as xs:boolean
{
    let $permissions := xmldb:permissions-to-string(xmldb:get-permissions($collection)) return
        let $new-permissions := if($write)then(
            fn:replace($permissions, "(....)(.)(....)", "$1w$3")
        ) else (
           fn:replace($permissions, "(....)(.)(....)", "$1-$3")
        )
        return
            xmldb:set-collection-permissions($collection, xmldb:get-owner($collection), $group, xmldb:string-to-permissions($new-permissions)),

            true()
};

declare function security:create-group($group-name as xs:string, $group-member as xs:string*) as xs:boolean
{
    xmldb:create-group($group-name, $group-member)
};

declare function security:set-group-can-read-resource($group-name as xs:string, $resource as xs:string, $read as xs:boolean) as xs:boolean
{
    let $collection-uri := fn:replace($resource, "(.*)/.*", "$1"),
    $resource-uri := fn:replace($resource, ".*/", ""),
    $permissions := xmldb:permissions-to-string(xmldb:get-permissions($collection-uri, $resource-uri)) return
        let $new-permissions := if($read)then(
            fn:replace($permissions, "(...)(.)(.....)", "$1r$3")
        ) else (
           fn:replace($permissions, "(...)(.)(.....)", "$1-$3")
        )
        return
            xmldb:set-resource-permissions($collection-uri, $resource-uri, xmldb:get-owner($collection-uri, $resource-uri), $group-name, xmldb:string-to-permissions($new-permissions)),

            true()
};

declare function security:set-resource-permissions($resource as xs:string, $owner as xs:string, $group as xs:string, $owner-read as xs:boolean, $owner-write as xs:boolean, $group-read as xs:boolean, $group-write as xs:boolean, $other-read as xs:boolean, $other-write as xs:boolean) as empty() {
    let $permissions := fn:concat(
        if($owner-read)then("r")else("-"),
        if($owner-write)then("w")else("-"),
        if($owner-write)then("u")else("-"),

        if($group-read)then("r")else("-"),
        if($group-write)then("w")else("-"),
        if($group-write)then("u")else("-"),

        if($other-read)then("r")else("-"),
        if($other-write)then("w")else("-"),
        if($other-write)then("u")else("-")
    ) return
        let $collection-uri := fn:replace($resource, "(.*)/.*", "$1"),
        $resource-uri := fn:replace($resource, ".*/", "") return
            xmldb:set-resource-permissions($collection-uri, $resource-uri, $owner, $group, xmldb:string-to-permissions($permissions))
};

declare function security:get-groups($user as xs:string) as xs:string*
{
    xmldb:get-user-groups($user)
};

xquery version "1.0";

module namespace security="http://exist-db.org/mods/security";

import module namespace config="http://exist-db.org/mods/config" at "config.xqm";
declare namespace session="http://exist-db.org/xquery/session";
declare namespace xmldb="http://exist-db.org/xquery/xmldb";

declare variable $security:GUEST_CREDENTIALS := ("guest", "guest");
declare variable $security:SESSION_USER_ATTRIBUTE := "biblio.user";
declare variable $security:SESSION_PASSWORD_ATTRIBUTE := "biblio.password";

declare variable $security:biblio-users-group := "biblio.users";
declare variable $security:users-collection := fn:concat($config:mods-root, "/users");

(:~
: Authenticates a user and creates their mods home collection if it does not exist
:
: @param user The username of the user
: @param password The password of the user
:)
declare function security:login($user as xs:string, $password as xs:string?) as xs:boolean
{
    (: authenticate against eXist-db :)
    if(xmldb:login("/db", $user, $password))then
    (
        (: check if the users mods home collectin exists, if not create it (i.e. first login) :)
        if(security:home-collection-exists($user))then
            true()
        else
        (
            let $users-collection-uri := security:create-home-collection($user) return
                true()
        )
    ) else
        (: authentication failed:)
        false()
};

(:~
: Stores a users credentials for the mods app into the http session
:
: @param user The username
: @param password The password
:)
declare function security:store-user-credential-in-session($user as xs:string, $password as xs:string?) as empty()
{
    session:set-attribute($security:SESSION_USER_ATTRIBUTE, $user),
    session:set-attribute($security:SESSION_PASSWORD_ATTRIBUTE, $password)
};

(:~
: Retrieves a users credentials for the mods app from the http session
:
: @return The sequence (username as xs:string, password as xs:string)
: If there is no entry in the session, then the guest account credentials are returned
:)
declare function security:get-user-credential-from-session() as xs:string+
{
    let $user := session:get-attribute($security:SESSION_USER_ATTRIBUTE) return
        if($user)then
        (
            $user,
            session:get-attribute($security:SESSION_PASSWORD_ATTRIBUTE)
        )
        else
            $security:GUEST_CREDENTIALS
};

(:~
: Checks whether a users mods home collection exists
:
: @param user The username
:)
declare function security:home-collection-exists($user as xs:string) as xs:boolean
{
   xmldb:collection-available(security:get-home-collection-uri($user))
};

(:~
: Get the URI of a users mods home collection
:)
declare function security:get-home-collection-uri($user as xs:string) as xs:string
{
    fn:concat($security:users-collection, "/", $user)
};

(:~
: Creates a users mods home collection and sets permissions
:
: @return The uri of the users home collection or an empty sequence if it could not be created
:)
declare function security:create-home-collection($user as xs:string) as xs:string?
{
    if(xmldb:collection-available($security:users-collection))then
    (
        let $collection-uri := xmldb:create-collection($security:users-collection, $user) return
            if($collection-uri) then
            (
                let $null := xmldb:set-collection-permissions($collection-uri, $user, xmldb:get-user-primary-group($user), xmldb:string-to-permissions("rwu------")) return
                    $collection-uri
            ) else (
                $collection-uri
            )
    )else()
};

(:~
: Determines if a user has read access to a collection
:
: @param user The username
: @param collection The path of the collection
:)
declare function security:can-read-collection($user as xs:string, $collection as xs:string) as xs:boolean
{
    let $permissions := xmldb:permissions-to-string(xmldb:get-permissions($collection))
    let $owner := xmldb:get-owner($collection)
    let $group := xmldb:get-group($collection)
    let $users-groups := xmldb:get-user-groups($user)
    return
        if ($owner eq $user) then
            fn:substring($permissions, 1, 1) eq 'r'
        else if ($group = $users-groups) then
            fn:substring($permissions, 4, 1) eq 'r'
        else
            fn:substring($permissions, 7, 1) eq 'r'
};

(:~
: Determines if a user has write access to a collection
:
: @param user The username
: @param collection The path of the collection
:)
declare function security:can-write-collection($user as xs:string, $collection as xs:string) as xs:boolean
{
    let $permissions := xmldb:permissions-to-string(xmldb:get-permissions($collection))
    let $owner := xmldb:get-owner($collection)
    let $group := xmldb:get-group($collection)
    let $users-groups := xmldb:get-user-groups($user)
    return
        if ($owner eq $user) then
            fn:substring($permissions, 2, 1) eq 'w'
        else if ($group = $users-groups) then
            fn:substring($permissions, 5, 1) eq 'w'
        else
            fn:substring($permissions, 8, 1) eq 'w'
};

(:~
: Determines if a group has read access to a collection
:
: @param group The group name
: @param collection The path of the collection
:)
declare function security:group-can-read-collection($group as xs:string, $collection as xs:string) as xs:boolean
{
    let $permissions := xmldb:permissions-to-string(xmldb:get-permissions($collection))
    let $owner-group := xmldb:get-group($collection)
    return
        ($group eq $owner-group and fn:substring($permissions, 4, 1) eq 'r')
};

(:~
: Determines if a group has write access to a collection
:
: @param group The group name
: @param collection The path of the collection
:)
declare function security:group-can-write-collection($group as xs:string, $collection as xs:string) as xs:boolean
{
    let $permissions := xmldb:permissions-to-string(xmldb:get-permissions($collection))
    let $owner-group := xmldb:get-group($collection)
    return
        ($group eq $owner-group and fn:substring($permissions, 5, 1) eq 'w')
};

(:~
: Determines if everyone has read access to a collection
:
: @param collection The path of the collection
:)
declare function security:other-can-read-collection($collection as xs:string) as xs:boolean
{
    let $permissions := xmldb:permissions-to-string(xmldb:get-permissions($collection))
    return
        fn:substring($permissions, 7, 1) eq 'r'
};

(:~
: Determines if everyone has write access to a collection
:
: @param collection The path of the collection
:)
declare function security:other-can-write-collection($collection as xs:string) as xs:boolean
{
    let $permissions := xmldb:permissions-to-string(xmldb:get-permissions($collection))
    return
        fn:substring($permissions, 8, 1) eq 'w'
};

(:~
: Determines if the user is the collection owner
:
: @param user The username
: @param collection The path of the collection
:)
declare function security:is-collection-owner($user as xs:string, $collection as xs:string) as xs:boolean
{
    let $owner := xmldb:get-owner($collection) return
        $user eq $owner
};

(:~
: Gets the users for a group
:
: @param the group name
: @return The list of users in the group
:)
declare function security:get-group-members($group as xs:string) as xs:string*
{
    xmldb:get-users($group)
};

(:~
: Gets a list of other biblio users
:)
declare function security:get-other-biblio-users() as xs:string*
{
    security:get-group-members($security:biblio-users-group)[. ne security:get-user-credential-from-session()[1]]
};

declare function security:get-group($collection as xs:string) as xs:string?
{
    if(xmldb:collection-available($collection))then
    (
        xmldb:get-group($collection)
    ) else()
};

declare function security:set-other-can-read-collection($collection, $read as xs:boolean) as xs:boolean
{
    let $permissions := xmldb:permissions-to-string(xmldb:get-permissions($collection)) return
        let $new-permissions := if($read)then(
            fn:replace($permissions, "(......)(.)(..)", "$1r$3")
        ) else (
           fn:replace($permissions, "(......)(.)(..)", "$1-$3")
        )
        return
            xmldb:set-collection-permissions($collection, xmldb:get-owner($collection), xmldb:get-group($collection), xmldb:string-to-permissions($new-permissions)),

            true()
};

declare function security:set-other-can-write-collection($collection, $write as xs:boolean) as xs:boolean
{
    let $permissions := xmldb:permissions-to-string(xmldb:get-permissions($collection)) return
        let $new-permissions := if($write)then(
            fn:replace($permissions, "(.......)(.)(.)", "$1w$3")
        ) else (
           fn:replace($permissions, "(.......)(.)(.)", "$1-$3")
        )
        return
            xmldb:set-collection-permissions($collection, xmldb:get-owner($collection), xmldb:get-group($collection), xmldb:string-to-permissions($new-permissions)),

            true()
};

declare function security:set-group-can-read-collection($collection, $read as xs:boolean) as xs:boolean
{
    security:set-group-can-write-collection($collection, xmldb:get-group($collection), $read)
};

declare function security:set-group-can-write-collection($collection, $write as xs:boolean) as xs:boolean
{
    security:set-group-can-write-collection($collection, xmldb:get-group($collection), $write)
};

declare function security:set-group-can-read-collection($collection, $group as xs:string, $read as xs:boolean) as xs:boolean
{
    let $permissions := xmldb:permissions-to-string(xmldb:get-permissions($collection)) return
        let $new-permissions := if($read)then(
            fn:replace($permissions, "(...)(.)(.....)", "$1r$3")
        ) else (
           fn:replace($permissions, "(...)(.)(.....)", "$1-$3")
        )
        return
            xmldb:set-collection-permissions($collection, xmldb:get-owner($collection), $group, xmldb:string-to-permissions($new-permissions)),

            true()
};

declare function security:set-group-can-write-collection($collection, $group as xs:string, $write as xs:boolean) as xs:boolean
{
    let $permissions := xmldb:permissions-to-string(xmldb:get-permissions($collection)) return
        let $new-permissions := if($write)then(
            fn:replace($permissions, "(....)(.)(....)", "$1w$3")
        ) else (
           fn:replace($permissions, "(....)(.)(....)", "$1-$3")
        )
        return
            xmldb:set-collection-permissions($collection, xmldb:get-owner($collection), $group, xmldb:string-to-permissions($new-permissions)),

            true()
};

declare function security:create-group($group-name as xs:string, $group-member as xs:string*) as xs:boolean
{
    xmldb:create-group($group-name, $group-member)
};

declare function security:set-group-can-read-resource($group-name as xs:string, $resource as xs:string, $read as xs:boolean) as xs:boolean
{
    let $collection-uri := fn:replace($resource, "(.*)/.*", "$1"),
    $resource-uri := fn:replace($resource, ".*/", ""),
    $permissions := xmldb:permissions-to-string(xmldb:get-permissions($collection-uri, $resource-uri)) return
        let $new-permissions := if($read)then(
            fn:replace($permissions, "(...)(.)(.....)", "$1r$3")
        ) else (
           fn:replace($permissions, "(...)(.)(.....)", "$1-$3")
        )
        return
            xmldb:set-resource-permissions($collection-uri, $resource-uri, xmldb:get-owner($collection-uri, $resource-uri), $group-name, xmldb:string-to-permissions($new-permissions)),

            true()
};

declare function security:set-resource-permissions($resource as xs:string, $owner as xs:string, $group as xs:string, $owner-read as xs:boolean, $owner-write as xs:boolean, $group-read as xs:boolean, $group-write as xs:boolean, $other-read as xs:boolean, $other-write as xs:boolean) as empty() {
    let $permissions := fn:concat(
        if($owner-read)then("r")else("-"),
        if($owner-write)then("w")else("-"),
        if($owner-write)then("u")else("-"),

        if($group-read)then("r")else("-"),
        if($group-write)then("w")else("-"),
        if($group-write)then("u")else("-"),

        if($other-read)then("r")else("-"),
        if($other-write)then("w")else("-"),
        if($other-write)then("u")else("-")
    ) return
        let $collection-uri := fn:replace($resource, "(.*)/.*", "$1"),
        $resource-uri := fn:replace($resource, ".*/", "") return
            xmldb:set-resource-permissions($collection-uri, $resource-uri, $owner, $group, xmldb:string-to-permissions($permissions))
};

declare function security:get-groups($user as xs:string) as xs:string*
{
    xmldb:get-user-groups($user)
};