xquery version "3.1";
(:
    ART-DECOR® STANDARD COPYRIGHT AND LICENSE NOTE
    Copyright © ART-DECOR Expert Group and ART-DECOR Open Tools GmbH
    see https://docs.art-decor.org/copyright and https://docs.art-decor.org/licenses

    This file is part of the ART-DECOR® tools suite.
:)
module namespace adserver       = "http://art-decor.org/ns/art-decor-server";
import module namespace get     = "http://art-decor.org/ns/art-decor-settings" at "../modules/art-decor-settings.xqm";
import module namespace art     = "http://art-decor.org/ns/art" at "../modules/art-decor.xqm";
import module namespace adpfix  = "http://art-decor.org/ns/art-decor-permissions" at "api-permissions.xqm";
declare namespace http              = "http://expath.org/ns/http-client";
declare option exist:serialize "method=xml media-type=text/xml";

(:~ The path to the install-data server info file :)
declare variable $adserver:strServerInfoDefault         := concat($get:strArt,'/install-data/server-info.xml');
(:~ The document contents of the server info :)
declare variable $adserver:docServerInfoDefault         := doc($adserver:strServerInfoDefault);
(:~ The path to the server info file :)
declare variable $adserver:strServerInfo                := concat($get:strArtData,'/server-info.xml');
(:~ The document contents of the server info :)
declare variable $adserver:docServerInfo                := doc($adserver:strServerInfo);
(:~ The server default language :)
declare variable $adserver:strDefaultServerLanguage     := 'en-US';
(:~ The collection holding valid stylesheets for ART in its various forms (default, terminology, qualification server, ...) :)
declare variable $adserver:strServerXSLPath             := concat($get:strArtResources,'/stylesheets');
(:~ The default art do-it-all XSL on an ART-DECOR instance unless configured otherwise :)
declare variable $adserver:strDefaultServerXSL          := 'apply-rules.xsl';
(:~ The collection holding valid menu-structures for ART :)
declare variable $adserver:strServerMenuPath            := concat($get:strArtData,'/resources');
(:~ The default art menu template an ART-DECOR instance unless configured otherwise :)
declare variable $adserver:strDefaultServerMenu         := 'art-menu-template.xml';
(:~ The default logo name for an ART-DECOR instance unless configured otherwise :)
declare variable $adserver:strDefaultServerLogo         := 'art-decor-logo40.png';
(:~ The default logo url for an ART-DECOR instance unless configured otherwise :)
declare variable $adserver:strDefaultServerLogoUrl      := 'http://art-decor.org';
(:~ The list of users that may be regarded as 'system-level' users :)
declare variable $adserver:arrSystemLevelUsers          := ('xis-webservice');

(:~ Return all settings
@return server-info element with contents
@since 2014-03-27
:)
declare function adserver:getServerSettings() as element()? {
    if (adserver:checkPermissions()) then (
        doc($adserver:strServerInfo)/server-info
    ) else ()
};

(:~ Return all settings from default settings copy

@return server-info element with contents
@since 2014-09-11
:)
declare function adserver:getServerSettingsDefault() as element() {
    $adserver:docServerInfoDefault/server-info
};

(:~ Save setting

@return nothing or error
@since 2014-03-27
:)
declare function adserver:saveServerSetting($settings as element()) {
    if (adserver:checkPermissions()) then (
        let $action := $settings/@action
        return 
        switch ($action)
        case 'save-server-ids' return (
            let $currentids     := adserver:getServerAllIds()
            let $delete         :=
                for $baseId in $currentids/baseId
                return adserver:deleteServerId($baseId/@type, $baseId/@id)
            let $delete         :=
                for $type in $currentids/type
                return adserver:deleteServerIdType($type/@code)
            let $add            :=
                for $type in $settings/ids/type
                return adserver:setServerIdType($type/@code, $type/@displayName)
            let $add            :=
                for $baseId in $settings/ids/baseId
                return adserver:setServerId($baseId/@type, $baseId/@id, $baseId/@default='true')
            
            return ()
        )
        case 'save-language' return
            adserver:setServerLanguage($settings/defaultLanguage)
        case 'save-server-api-url' return
            adserver:setServerURLArtApi($settings/url-art-decor-api)
        case 'save-server-url' return
            adserver:setServerURLArt($settings/url-art-decor-deeplinkprefix)
        case 'save-server-url3' return
            adserver:setServerURLArt3($settings/url-art-decor3-deeplinkprefix)
        case 'save-services-url' return
            adserver:setServerURLServices($settings/url-art-decor-services)
        case 'save-fhir-url' return
            adserver:setServerURLFhirServices($settings/url-fhir-services)
        case 'save-fhir-canonical-base' return
            adserver:setServerURLFhirCanonicalBase($settings/url-fhir-canonical-base)
        case 'save-fhir-default-version' return
            adserver:setServerFhirDefaultVersion($settings/default-fhir-version)
        case 'save-server-xsl' return
            adserver:setServerXSLArt($settings/xformStylesheet)
        case 'save-server-menu-template' return
            adserver:setServerMenuTemplate($settings/art-menu-template)
        case 'save-server-logo-and-url' return
            adserver:setServerLogoAndUrl($settings/art-server-logo, $settings/art-server-logo/@href)
        case 'save-repository-servers' return (
            let $currentsvrs := adserver:getServerRepositoryServers()
            let $delete      := 
                for $svr in $currentsvrs/buildingBlockServer 
                return adserver:deleteServerRepositoryServer($svr/@url)
            return
                try {
                    for $svr in $settings/externalBuildingBlockRepositoryServers/buildingBlockServer 
                    return adserver:setServerRepositoryServer($svr)
                }
                catch * {
                    (: one of the new servers returned an error. restore what we had and rethrow our error :)
                    let $delete     :=
                        for $svr in adserver:getServerRepositoryServers()/buildingBlockServer
                        return adserver:deleteServerRepositoryServer($svr/@url)
                    let $add        :=
                        for $svr in $currentsvrs/buildingBlockServer
                        return adserver:setServerRepositoryServer($svr)
                    return
                    error(QName($err:module,$err:code),$err:description)
                }
        )
        case 'save-repositories' return (
            let $currentbbrs := adserver:getServerExternalRepositories()
            let $delete      := 
                for $bbr in $currentbbrs/buildingBlockRepository 
                return adserver:deleteServerExternalRepository($bbr/@url, $bbr/@ident)
            return
                try {
                    for $bbr in $settings/externalBuildingBlockRepositories/buildingBlockRepository 
                    return adserver:setServerExternalRepository($bbr)
                }
                catch * {
                    (: one of the new bbrs returned an error. restore what we had and rethrow our error :)
                    let $delete     :=
                        for $bbr in adserver:getServerExternalRepositories()/buildingBlockRepository
                        return adserver:deleteServerExternalRepository($bbr/@url, $bbr/@ident)
                    let $add        :=
                        for $bbr in $currentbbrs/buildingBlockRepository
                        return adserver:setServerExternalRepository($bbr)
                    return
                    error(QName($err:module,$err:code),$err:description)
                }
        )
        case 'save-server-orbeon-version' return (
            adserver:setServerOrbeonVersion($settings/orbeon-version), adpfix:updateXForms('update')
        )
        default return
            error(QName('http://art-decor.org/ns/error', 'UnsupportedAction'), concat('Don''t know what to save. Unsupported action in @action: ',$action,' Supported actions are ''save-language'',''save-server-url'',''save-services-url'',''save-server-xsl'',''save-repository-servers'',''save-repositories'''))
    ) else ()
};

(:~ Return the configured server-baseIds or empty
@return ids as ids
@since 2015-01-14
:)
declare function adserver:getServerAllIds() as element(ids)? {
    $adserver:docServerInfo/server-info/ids
};

(:~ Return the configured server-baseId types or empty

@return types as xs:string*
@since 2015-01-14
:)
declare function adserver:getServerIdTypes() as xs:string* {
    $adserver:docServerInfo/server-info/ids/baseId/@type[string-length()>0]
};

(:~ Return the configured server-baseId for a type. Get types through adserver:getServerIdTypes()

@param $type server base id type
@return types as xs:string*
@since 2015-01-14
:)
declare function adserver:getServerId($type as xs:string) as xs:string* {
    $adserver:docServerInfo/server-info/ids/baseId[@type=$type]/@id[string-length()>0]
};

(:~ Return the default configured server-baseId for a type. Get types through adserver:getServerIdTypes()
@return types as xs:string?
@since 2015-01-14
:)
declare function adserver:getServerDefaultId($type as xs:string) as xs:string? {
    $adserver:docServerInfo/server-info/ids/baseId[@type=$type][@default='true']/@id[string-length()>0]
};

(:~ Delete an existing server baseId. The match is done based on @id + @type, the rest is irrelevant.

@param $type server base id type
@param $id server base id
@return nothing or error you are not dba
@since 2014-03-27
:)
declare function adserver:deleteServerId($type as xs:string, $id as xs:string) {
    if (adserver:checkPermissions()) then (
        let $currentids := adserver:getServerAllIds()
        return
            update delete $currentids/baseId[@id=$id][@type=$type]
    ) else ()
};

(:~ Delete an existing server id type if not in use. The match is done based on attributes id + type, the rest is irrelevant.

@param $type server base id type
@return nothing or error you are not dba
@since 2014-03-27
:)
declare function adserver:deleteServerIdType($type as xs:string) {
    if (adserver:checkPermissions()) then (
        if (empty(adserver:getServerId($type))) then (
            let $currentids := adserver:getServerAllIds()
            return
                update delete $currentids/type[@code=$type]
        ) else (
            error(QName('http://art-decor.org/ns/error','TypeInUse'), 'Cannot delete type. This type ' || $type || ' is still in use')
        )
    ) else ()
};

(:~ Set the configured server-baseId for a type. Get types through adserver:getServerIdTypes().

Updates attribute default if both attributes id + type already exist, or adds it if it does not.

Updates attribute default as 'false' for other ids of the same type if parameter $default=true().

@param $type server base id type
@param $id server base id
@return nothing or error if you are not dba, if the type does not exist yet or if the id was already assigned to a different type.
@since 2015-01-14
:)
declare function adserver:setServerId($type as xs:string, $id as xs:string, $default as xs:boolean) {
    if (adserver:checkPermissions()) then (
        let $currentids := adserver:getServerAllIds()
        
        return
        if (not($currentids/type[@code=$type])) then (
            error(QName('http://art-decor.org/ns/error', 'InvalidType'), 'Type ' || $type || ' must exist before an id can be assigned to it')
        ) else if ($currentids/baseId[@id=$id][not(@type=$type)][string-length($id)>0]) then (
            error(QName('http://art-decor.org/ns/error','InvalidBaseId'), 'This id ' || $id || ' has already been assigned to a different type')
        ) else (
            if ($currentids/baseId[@type=$type][@id=$id]) then
                update value $currentids/baseId[@type=$type][@id=$id]/@default with $default
            else (
                update insert <baseId id="{$id}" type="{$type}" default="{$default}"/> into $currentids
            )
            ,
            if ($default) then (
                update value $currentids/baseId[@type=$type][not(@id=$id)]/@default with 'false'
            ) else ()
        )
    ) else ()
};

(:~ Set the configured server-id type. Get existing types through adserver:getServerIdTypes().

Updates if attribute code on type already exists, or adds it if it does not

@param $type server base id type
@param $displayName server base id display name
@return nothing or error if you are not dba
@since 2015-01-14
:)
declare function adserver:setServerIdType($type as xs:string, $displayName as xs:string) {
    if (adserver:checkPermissions()) then (
        let $currentids := adserver:getServerAllIds()
        
        return
        if ($currentids/type[@code=$type]) then
            update value $currentids/type[@code=$type]/@displayName with $displayName
        else if ($currentids/id) then
            update insert <type code="{$type}" displayName="{$displayName}"/> preceding $currentids/id[1]
        else (
            update insert <type code="{$type}" displayName="{$displayName}"/> into $currentids
        )
    ) else ()
};

(:~ Return the configured server-language or default value 'en-US'

@return server-language as xs:string('ll-CC')
@since 2014-03-27
:)
declare function adserver:getServerLanguage() as xs:string {
    let $tmp    := $adserver:docServerInfo/server-info/defaultLanguage
    return
        if ($tmp) then $tmp else ($adserver:strDefaultServerLanguage)
};

(:~ Set the server-language. Example: en-US

@param $language string value. Must have format ll-CC where ll is lower-case language and CC is uppercase country/region
@return nothing or error if you are not dba or if the supplied $language does not match the pattern
@since 2014-03-27
:)
declare function adserver:setServerLanguage($language as xs:string) {
    if (adserver:checkPermissions()) then (
        if (matches($language,'[a-z]{2}-[A-Z]{2}')) then (
            if ($adserver:docServerInfo/server-info/defaultLanguage) then
                update value $adserver:docServerInfo/server-info/defaultLanguage with $language
            else (
                update insert <defaultLanguage>{$language}</defaultLanguage> into $adserver:docServerInfo/server-info
            )
        ) else (
            error(QName('http://art-decor.org/ns/error', 'InvalidFormat'), 'Cannot set server language ''' || $language || '''. Language must match pattern ll-CC where ll is lower-case language and CC is uppercase country/region')
        )
    ) else ()
};

(:~ Return the configured server-url http or https for ART-DECOR API or empty string. Example: https://art-decor.org/art-decor/

@return xs:anyURI('https://.../exist/apps/api')
@since 2021-03-10
:)
declare function adserver:getServerURLArtApi() as xs:string? {
    $adserver:docServerInfo/server-info/url-art-decor-api/string()
};

(:~ Set the server-url http or https for ART-DECOR API server. Example: https://art-decor.org/exist/apps/api

@param $url string value. Must have format ^https?://host:port(/path)?.*/api
@return nothing or error if you are not dba or if the supplied $url does not match the pattern
@since 2014-03-27
:)
declare function adserver:setServerURLArtApi($url as xs:string) {
    if (adserver:checkPermissions()) then (
        if ($url castable as xs:anyURI and matches($url,'^https?://.*/api$')) then (
            if ($adserver:docServerInfo/server-info/url-art-decor-api) then
                update value $adserver:docServerInfo/server-info/url-art-decor-api with $url
            else (
                update insert <url-art-decor-api>{$url}</url-art-decor-api> into $adserver:docServerInfo/server-info
            )
        ) else (
            error(QName('http://art-decor.org/ns/error', 'InvalidFormat'), 'Cannot set ART-DECOR API server url ''' || $url || '''. Url must be castable as xs:anyURI and match pattern ''https?://host:port(/path)?/api''.')
        )
    ) else ()
};

(:~ Return the configured server-url http or https for ART-DECOR or empty string. Example: https://art-decor.org/art-decor/

@return xs:anyURI('http://.../art-decor/')
@since 2014-03-27
:)
declare function adserver:getServerURLArt() as xs:string? {
    $adserver:docServerInfo/server-info/url-art-decor-deeplinkprefix/string()
};

(:~ Set the server-url http or https for ART-DECOR server. Example: https://art-decor.org/art-decor/

@param $url string value. Must have format ^https?://host:port(/path)?/art-decor/
@return nothing or error if you are not dba or if the supplied $url does not match the pattern
@since 2014-03-27
:)
declare function adserver:setServerURLArt($url as xs:string) {
    if (adserver:checkPermissions()) then (
        if ($url castable as xs:anyURI and matches($url,'^https?://.*/art-decor/$')) then (
            if ($adserver:docServerInfo/server-info/url-art-decor-deeplinkprefix) then
                update value $adserver:docServerInfo/server-info/url-art-decor-deeplinkprefix with $url
            else (
                update insert <url-art-decor-deeplinkprefix>{$url}</url-art-decor-deeplinkprefix> into $adserver:docServerInfo/server-info
            )
        ) else (
            error(QName('http://art-decor.org/ns/error', 'InvalidFormat'), 'Cannot set ART server url ''' || $url || '''. URL must be castable as xs:anyURI and match pattern ''https?://host:port(/path)?/art-decor/''.')
        )
    ) else ()
};

(:~ Return the configured server-url http or https for ART-DECOR 3 Vue or empty string. Example: https://art-decor.org/ad/

@return xs:anyURI('http://.../ad/')
@since 2020-12-31
:)
declare function adserver:getServerURLArt3() as xs:string? {
    ($adserver:docServerInfo/server-info/url-art-decor3-deeplinkprefix, replace(adserver:getServerURLArt(), '/art-decor.*$', '/ad/#/'))[not(. = '')][1]
};

(:~ Set the server-url http or https for ART-DECOR 3 Vue server. Example: https://art-decor.org/ad/

@param $url string value. Must have format ^https?://host:port(/path)?/ad/
@return nothing or error if you are not dba or if the supplied $url does not match the pattern
@since 2020-12-31
:)
declare function adserver:setServerURLArt3($url as xs:string) {
    if (adserver:checkPermissions()) then (
        if ($url castable as xs:anyURI and matches($url,'^https?://.*/ad/$')) then (
            if ($adserver:docServerInfo/server-info/url-art-decor3-deeplinkprefix) then
                update value $adserver:docServerInfo/server-info/url-art-decor3-deeplinkprefix with $url
            else (
                update insert <url-art-decor3-deeplinkprefix>{$url}</url-art-decor3-deeplinkprefix> into $adserver:docServerInfo/server-info
            )
        ) else (
            error(QName('http://art-decor.org/ns/error', 'InvalidFormat'), 'Cannot set ART server url ''' || $url || '''. URL must be castable as xs:anyURI and match pattern ''https?://host:port(/path)?/ad/''.')
        )
    ) else ()
};

(:~ Return the configured server-url http or https for ART-DECOR services or empty string. Example: http://art-decor.org/decor/services/

@return xs:anyURI('http://.../services/')
@since 2014-03-27
:)
declare function adserver:getServerURLServices() as xs:string? {
    $adserver:docServerInfo/server-info/url-art-decor-services/string()
};

(:~ Set the server-url http or https for ART-DECOR services. Example: http://art-decor.org/decor/services/

@param $url string value. Must have format ^https?://host:port(/path)?/services/
@return nothing or error if you are not dba or if the supplied $url does not match the pattern
@since 2014-03-27
:)
declare function adserver:setServerURLServices($url as xs:string) {
    if (adserver:checkPermissions()) then (
        if ($url castable as xs:anyURI and matches($url,'^https?://.*/services/$')) then (
            if ($adserver:docServerInfo/server-info/url-art-decor-services) then
                update value $adserver:docServerInfo/server-info/url-art-decor-services with $url
            else (
                update insert <url-art-decor-services>{$url}</url-art-decor-services> into $adserver:docServerInfo/server-info
            )
        ) else (
            error(QName('http://art-decor.org/ns/error', 'InvalidFormat'), 'Cannot set services server url ''' || $url || '''. URL must be castable as xs:anyURI and match pattern ''^https?://host:port(/path)?/services/''.')
        )
    ) else ()
};

(:~ Return the configured server-url http or https for ART-DECOR FHIR services or empty string. Example: https://art-decor.org/fhir/

@return xs:anyURI('http://.../services/')
@since 2015-02-27
:)
declare function adserver:getServerURLFhirServices() as xs:string? {
    $adserver:docServerInfo/server-info/url-fhir-services
};

(:~ Return the configured server-url http or https for ART-DECOR FHIR services or empty string.
    Example: http://art-decor.org/fhir/
    
    @return 'http://.../services/' as xs:string
    @since 2015-02-27
:)
declare function adserver:getServerURLFhirCanonicalBase() as xs:string? {
    let $d  := $adserver:docServerInfo/server-info

    return
        if ($d/url-fhir-canonical-base) then $d/url-fhir-canonical-base else $d/url-fhir-services
};

(:~ Return the installed FHIR server versions. The result of adserver:getServerURLFhirServices() concatenated with each of the installed FHIR server versions is expected as endpoint. E.g.

let $endpoints  :=
   for $endpoint in adserver:getInstalledFhirServices() 
   return concat(adserver:getServerURLFhirServices(), $endpoint, '/')

Example endpoints: dstu2, stu3, release4.
Any collection under $get:strFhir that holds an expath-pkg.xml as a sign of an installed package is returned.

@return sequence of strings
@since 2015-03-27
:)
declare function adserver:getInstalledFhirServices() as xs:string* {
    if (xmldb:collection-available($get:strFhir)) then (
        for $child-collection in xmldb:get-child-collections($get:strFhir)
        return
            if (xmldb:get-child-resources(concat($get:strFhir,'/',$child-collection))[. = 'expath-pkg.xml']) then
                $child-collection
            else ()
    ) else ()
};

(:~ Set the server-url http or https for ART-DECOR FHIR services. Example: https://art-decor.org/fhir/

@param $url string value. Must have format ^https?://host:port(/path)?/services/
@return nothing or error if you are not dba or if the supplied $url does not match the pattern
@since 2015-02-27
:)
declare function adserver:setServerURLFhirServices($url as xs:string) {
    if (adserver:checkPermissions()) then (
        if ($url castable as xs:anyURI and matches($url,'^https?://.*/fhir/$')) then (
            let $canonicalBase  := $adserver:docServerInfo/server-info/url-fhir-canonical-base
            let $currentService := string(adserver:getServerURLFhirServices())
            return (
                if ($adserver:docServerInfo/server-info/url-fhir-services) then
                    update value $adserver:docServerInfo/server-info/url-fhir-services with $url
                else (
                    update insert <url-fhir-services>{$url}</url-fhir-services> into $adserver:docServerInfo/server-info
                ),
                (: The FHIR canonicalUris are being built from the ServerURLFhirServices, if ServerURLFhirCanonicalBase is empty
                  So, when we update the ServerURLFhirServices, we should retain the previous value of ServerURLFhirServices
                  as ServerURLFhirCanonicalBase to keep those stable.
                :)
                if (string-length($canonicalBase) = 0) then 
                    if (string-length($currentService) gt 0) then
                        adserver:setServerURLFhirCanonicalBase($currentService)
                    else (
                        adserver:setServerURLFhirCanonicalBase($url)
                    )
                else ()
            )
        ) else (
            error(QName('http://art-decor.org/ns/error', 'InvalidFormat'), 'Cannot set FHIR server url ''' || $url || '''. URL must be castable as xs:anyURI and match pattern ''^https?://host:port(/path)?/fhir/''.')
        )
    ) else ()
};

(:~ Set the server-url http or https for ART-DECOR FHIR canonical urls
    Example: http://art-decor.org/fhir/
    
    @param $url string value. Must have format ^https?://host:port(/path)?/services/
    @return nothing or error if you are not dba or if the supplied $url does not match the pattern
    @since 2015-02-27
:)
declare function adserver:setServerURLFhirCanonicalBase($url as xs:string) {
    if (adserver:checkPermissions()) then (
        if ($url castable as xs:anyURI and matches($url,'^https?://.*/fhir/$')) then (
            if ($adserver:docServerInfo/server-info/url-fhir-canonical-base) then
                update value $adserver:docServerInfo/server-info/url-fhir-canonical-base with $url
            else (
                update insert <url-fhir-canonical-base>{$url}</url-fhir-canonical-base> into $adserver:docServerInfo/server-info
            )
        ) else (
            error(QName('http://art-decor.org/ns/error', 'InvalidFormat'), 'URL must be castable as xs:anyURI and match pattern ''^https?://host:port(/path)?/fhir/''.')
        )
    ) else ()
};

(:~ Get default-fhir-version for ART-DECOR FHIR services. Example: 1.0 (dstu2) or 3.0 (stu3)

@return nothing or string
@since 2017-09-25
:)
declare function adserver:getServerFhirDefaultVersion() as xs:string? {
    let $fhirVersion    := $adserver:docServerInfo/server-info/default-fhir-version

    return (
        switch ($fhirVersion) 
        case 'dstu2' return '1.0'
        case 'stu3' return '3.0'
        default return $fhirVersion
    )
};

(:~ Set the default-fhir-version for ART-DECOR FHIR services. Example: dstu2 or stu3

@param $version string value. Must be one of adserver:getInstalledFhirServices()
@return nothing or error if you are not dba or if the supplied $version is not in the installed versions
@since 2017-09-25
:)
declare function adserver:setServerFhirDefaultVersion($version as xs:string) {
    if (adserver:checkPermissions()) then (
        if ($version = '' or $version = adserver:getInstalledFhirServices()) then (
            if ($adserver:docServerInfo/server-info/default-fhir-version) then
                update value $adserver:docServerInfo/server-info/default-fhir-version with $version
            else (
                update insert <default-fhir-version>{$version}</default-fhir-version> into $adserver:docServerInfo/server-info
            )
        ) else (
            error(QName('http://art-decor.org/ns/error', 'InvalidFormat'), 'Cannot set FHIR default version ''' || $version || '''. This version is not installed. Please select one of: ', string-join(adserver:getInstalledFhirServices(), ' '))
        )
    ) else ()
};

(:~ Return the configured server-xsl that constitutes the interface for ART or default value apply-rules.xsl. Example: apply-rules.xsl

@return xs:string('apply.rules.xsl')
@since 2014-03-27
:)
declare function adserver:getServerXSLArt() as xs:string {
let $xsl    :=  $adserver:docServerInfo/server-info/xformStylesheet/string()
return
    if ($xsl=adserver:getServerXSLsArt()) then 
        $xsl
    else (
        $adserver:strDefaultServerXSL
    )
};

(:~ Return the available server-xsls that constitutes the interface for ART. Example: apply-rules-artdecororg.xsl apply-rules.xsl

@return list of available xsls
@since 2014-03-27
:)
declare function adserver:getServerXSLsArt() as xs:string* {
    for $xsl in xmldb:get-child-resources($adserver:strServerXSLPath)[ends-with(.,'.xsl')]
    return $xsl
};

(:~ Set the server-xsl that constitutes the interface for ART. Example: apply-rules.xsl

@param $xsl-resource-name string value of the xsl. Name only!
@return nothing or error if you are not dba or if the supplied $xsl-resource-name does not exist
@since 2014-03-27
:)
declare function adserver:setServerXSLArt($xsl-resource-name as xs:string) {
    if (adserver:checkPermissions()) then (
        let $xsl-resource-name-full := concat($adserver:strServerXSLPath,'/',tokenize($xsl-resource-name,'/')[last()])
        return
        if (doc-available($xsl-resource-name-full)) then (
            if ($adserver:docServerInfo/server-info/xformStylesheet) then
                update value $adserver:docServerInfo/server-info/xformStylesheet with $xsl-resource-name
            else (
                update insert <xformStylesheet>{$xsl-resource-name}</xformStylesheet> into $adserver:docServerInfo/server-info
            )
        ) else (
            error(QName('http://art-decor.org/ns/error', 'InvalidXSL'), 'Cannot set XSL ''' || $xsl-resource-name-full || '''. This XSL does not exist. Call adserver:getServerXSLs for valid values.')
        )
    ) else ()
};

(:~ Return the configured server-menu-template. Example: art-menu-template.xml

@return string
@since 2014-09-10
:)
declare function adserver:getServerMenuTemplate() as xs:string {
    let $tmp    := $adserver:docServerInfo/server-info/art-menu-template
    return
    if ($tmp) then $tmp else ($adserver:strDefaultServerMenu)
};

(:~ Set the server-menu-template that constitutes the interface for ART. Example: art-menu-template.xml

@param string name of the logo. Name only!
@return nothing or error if you are not dba
@since 2014-09-10
:)
declare function adserver:setServerMenuTemplate($menu-template as xs:string) {
    let $newdata    := <art-menu-template>{$menu-template}</art-menu-template>
    return
    if (adserver:checkPermissions()) then (
        if ($adserver:docServerInfo/server-info/art-menu-template) then (
            update replace $adserver:docServerInfo/server-info/art-menu-template with $newdata
        )
        else (
            update insert $newdata into $adserver:docServerInfo/server-info
        )
    ) else ()
};

(:~ Return the available server-menu-templates that constitutes the interface for ART. Example: art-menu-template.xml art-menu-template-nictiz.xml

@return list of available xsls
@since 2014-09-11
:)
declare function adserver:getServerMenuTemplates() as xs:string* {
    for $xml in collection($adserver:strServerMenuPath)/menu[section]
    return util:document-name($xml)
};

(:~ Return the available server-logo for display top right in ART. Example: art-decor-logo40.png

@return string
@since 2014-09-10
:)
declare function adserver:getServerLogo() as xs:string {
    let $tmp    := $adserver:docServerInfo/server-info/art-server-logo
    return
        if ($tmp) then $tmp else ($adserver:strDefaultServerLogo)
};

(:~ Return the available server-logo-url for linking the logo top right in ART. Example: https://art-decor.org

@return string
@since 2014-09-10
:)
declare function adserver:getServerLogoUrl() as xs:string {
    let $tmp    := $adserver:docServerInfo/server-info/art-server-logo/@href
    return
        if ($tmp) then $tmp else ($adserver:strDefaultServerLogoUrl)
};

(:~ Set the server-logo that constitutes the interface for ART. Example: art-decor-logo40.png

@param string name of the logo. Name only!
@return nothing or error if you are not dba
@since 2014-09-10
:)
declare function adserver:setServerLogoAndUrl($logo-name as xs:string, $logo-url as xs:string?) {
    if (adserver:checkPermissions()) then (
        if ($adserver:docServerInfo/server-info/art-server-logo) then (
            update replace $adserver:docServerInfo/server-info/art-server-logo with <art-server-logo href="{$logo-url}">{$logo-name}</art-server-logo>
        )
        else (
            update insert <art-server-logo href="{$logo-url}">{$logo-name}</art-server-logo> into $adserver:docServerInfo/server-info
        )
    ) else ()
};

(:~ Return the configured external building block repository servers as XML element. Example: 

<externalBuildingBlockRepositoryServers>
    <buildingBlockServer url="https://art-decor.org/decor/services/"/>
</externalBuildingBlockRepositoryServers>

@return list of configured external building block repository servers
@since 2014-03-27
:)
declare function adserver:getServerRepositoryServers() as element()? {
    $adserver:docServerInfo/server-info/externalBuildingBlockRepositoryServers
};

(:~ Save/update the provided external building block repository server. Example input: 

<externalBuildingBlockRepositoryServers>
    <buildingBlockServer url="https://art-decor.org/decor/services/"/>
</externalBuildingBlockRepositoryServers>

@param $buildingBlockServer MUST contain the new buildingBlockServer info
@return nothing or error you are not dba, or if the buildingBlockServer element does not have attributes @url
@since 2014-03-27
:)
declare function adserver:setServerRepositoryServer($buildingBlockServer as element()) as element()? {
    if (adserver:checkPermissions()) then (
        if ($buildingBlockServer[name()='buildingBlockServer'][@url] and $buildingBlockServer/@url castable as xs:anyURI and matches($buildingBlockServer/@url,'^https?://.*/services/$')) then (
            let $existingRepositoryServers  := $adserver:docServerInfo/server-info/externalBuildingBlockRepositoryServers
            let $existingRepositoryServer   := $existingRepositoryServers/buildingBlockServer[@url=$buildingBlockServer/@url]
            return
            if ($existingRepositoryServer) then (
                (: BBR already exist. Delete and write new :)
                update replace $existingRepositoryServer with $buildingBlockServer
            )
            else if ($existingRepositoryServers) then
                update insert $buildingBlockServer into $existingRepositoryServers
            else (
                update insert <externalBuildingBlockRepositoryServers>{$buildingBlockServer}</externalBuildingBlockRepositoryServers> into $adserver:docServerInfo/server-info
            )
        ) else (
            error(QName('http://art-decor.org/ns/error', 'InvalidFormat'), 'Element <buildingBlockServer> must have attribute @url and @url must be castable as xs:anyURI and match pattern ''^https?://host:port(/path)?/services/''.')
        )
    ) else ()
};

(:~ Delete an existing external building block repository server. The match is done based on attribute url, the rest is irrelevant.

@param $url url of the repository server to-be-deleted
@param $ident ident of the repository server to-be-deleted
@return nothing or error you are not dba
@since 2014-03-27
:)
declare function adserver:deleteServerRepositoryServer($url as xs:string) {
    if (adserver:checkPermissions()) then (
        let $existingRepositoryServers  := adserver:getServerRepositoryServers()
        return
            update delete $existingRepositoryServers/buildingBlockServer[@url=$url]
    ) else ()
};

(:~ Return the configured internal building block repositories as XML element. Example: 
<internalBuildingBlockRepositories>
    <buildingBlockRepository url="https://art-decor.org/decor/services/" ident="ad1bbr-" type="local">
        <name language="en-US">CDA Release 2</name>
        <name language="nl-NL">CDA Release 2</name>
        <name language="de-DE">CDA Release 2</name>
    </buildingBlockRepository>
    <buildingBlockRepository url="https://art-decor.org/decor/services/" ident="ad2bbr-" type="local">
        <name language="en-US">HL7 V3 Value Sets</name>
        <name language="nl-NL">HL7v3-waardenlijsten</name>
        <name language="de-DE">HL7 V3 Value Sets</name>
    </buildingBlockRepository>
    <buildingBlockRepository url="https://art-decor.org/decor/services/" ident="ccda-" type="local">
        <name language="en-US">Consolidated CDA 1.1</name>
        <name language="nl-NL">Consolidated CDA 1.1</name>
        <name language="de-DE">Consolidated CDA 1.1</name>
    </buildingBlockRepository>
</internalBuildingBlockRepositories>

@return list of configured external building block repositories
@since 2014-03-27
:)
declare function adserver:getServerInternalRepositories() as element() {
    let $thisServer := adserver:getServerURLServices()
    
    return
    <internalBuildingBlockRepositories>
    {
        for $bbr in $get:colDecorData//decor[@repository='true'][not(@private='true')]
        let $ident      := $bbr/project/@prefix
        return
            <buildingBlockRepository url="{$thisServer}" ident="{$ident}" type="local" format="decor">
            {
                for $lang in art:getArtLanguages()
                return
                    if ($bbr/project/name[@language=$lang]) then
                        $bbr/project/name[@language=$lang]
                    else if ($bbr/project/name[@language='en-US']) then
                        <name language="{$lang}">{$bbr/project/name[@language='en-US']/node()}</name>
                    else (
                        <name language="{$lang}">{$bbr/project/name[@language=$bbr/project/@defaultLanguage]/node()}</name>
                    )
            }
            </buildingBlockRepository>
    }
    </internalBuildingBlockRepositories>
};

(:~ Return the configured external building block repositories as XML element. Example: 
<externalBuildingBlockRepositories>
    <buildingBlockRepository url="https://art-decor.org/decor/services/" ident="ad1bbr-" type="external" format="decor">
        <name language="en-US">CDA Release 2</name>
        <name language="nl-NL">CDA Release 2</name>
        <name language="de-DE">CDA Release 2</name>
    </buildingBlockRepository>
    <buildingBlockRepository url="https://art-decor.org/decor/services/" ident="ad2bbr-" type="external" format="decor">
        <name language="en-US">HL7 V3 Value Sets</name>
        <name language="nl-NL">HL7v3-waardenlijsten</name>
        <name language="de-DE">HL7 V3 Value Sets</name>
    </buildingBlockRepository>
    <buildingBlockRepository url="https://art-decor.org/decor/services/" ident="ccda-" type="external" format="decor">
        <name language="en-US">Consolidated CDA 1.1</name>
        <name language="nl-NL">Consolidated CDA 1.1</name>
        <name language="de-DE">Consolidated CDA 1.1</name>
    </buildingBlockRepository>
</externalBuildingBlockRepositories>

@return list of configured external building block repositories
@since 2014-03-27
:)
declare function adserver:getServerExternalRepositories() as element()? {
let $config         := $adserver:docServerInfo/server-info/externalBuildingBlockRepositories
let $art-language   := art:getArtLanguages()
return
    <externalBuildingBlockRepositories>
    {
        for $bbr in $config/buildingBlockRepository
        return
        <buildingBlockRepository>
        {
            $bbr/@*,
            if ($bbr/@format) then () else (attribute format {'decor'}),
            $bbr/name,
            for $lang in $art-language[not(.=$bbr/name/@language)]
            return
                <name language="{$lang}">{$bbr/name[@language='en-US']/node()}</name>
        }
        </buildingBlockRepository>
    }
    </externalBuildingBlockRepositories>
};

(:~ Return the configured internal and external building block repositories as XML element. Example: 
<buildingBlockRepositories>
    <buildingBlockRepository url="https://art-decor.org/decor/services/" ident="ad1bbr-" type="external" format="decor">
        <name language="en-US">CDA Release 2</name>
        <name language="nl-NL">CDA Release 2</name>
        <name language="de-DE">CDA Release 2</name>
    </buildingBlockRepository>
    <buildingBlockRepository url="https://art-decor.org/decor/services/" ident="ad2bbr-" type="external" format="decor">
        <name language="en-US">HL7 V3 Value Sets</name>
        <name language="nl-NL">HL7v3-waardenlijsten</name>
        <name language="de-DE">HL7 V3 Value Sets</name>
    </buildingBlockRepository>
    <buildingBlockRepository url="https://art-decor.org/decor/services/" ident="ccda-" type="external" format="decor">
        <name language="en-US">Consolidated CDA 1.1</name>
        <name language="nl-NL">Consolidated CDA 1.1</name>
        <name language="de-DE">Consolidated CDA 1.1</name>
    </buildingBlockRepository>
    <buildingBlockRepository url="http://myserver.org/decor/services/" ident="bbr1-" type="local" format="decor">
        <name language="en-US">My BBR 1</name>
        <name language="nl-NL">Mijn BBR 1</name>
        <name language="de-DE">Mein BBR 1</name>
    </buildingBlockRepository>
    <buildingBlockRepository url="http://myserver.org/decor/services/" ident="bbr2-" type="local" format="decor">
        <name language="en-US">My BBR 2</name>
        <name language="nl-NL">Mijn BBR 2</name>
        <name language="de-DE">Mein BBR 2</name>
    </buildingBlockRepository>
</buildingBlockRepositories>

@return list of configured external building block repositories
@since 2014-03-27
:)
declare function adserver:getServerAllRepositories() as element() {
    <buildingBlockRepositories>
    {
        adserver:getServerExternalRepositories()/buildingBlockRepository
        ,
        adserver:getServerInternalRepositories()/buildingBlockRepository
    }
    </buildingBlockRepositories>
};

(:~ Return the repositories as available at the given server URL as external building block repositories as XML element
Example input:
    https://art-decor.org/decor/services/
Example output: 
<externalBuildingBlockRepositories used-url="uri-that-was-built-and-used">
    <buildingBlockRepository url="$external-server-services-url" ident="ad1bbr-" type="external">
        <name language="en-US">CDA Release 2</name>
        <name language="nl-NL">CDA Release 2</name>
        <name language="de-DE">CDA Release 2</name>
    </buildingBlockRepository>
    <buildingBlockRepository url="$external-server-services-url" ident="ad2bbr-" type="external">
        <name language="en-US">HL7 V3 Value Sets</name>
        <name language="nl-NL">HL7v3-waardenlijsten</name>
        <name language="de-DE">HL7 V3 Value Sets</name>
    </buildingBlockRepository>
    <buildingBlockRepository url="$external-server-services-url" ident="ccda-" type="external">
        <name language="en-US">Consolidated CDA 1.1</name>
        <name language="nl-NL">Consolidated CDA 1.1</name>
        <name language="de-DE">Consolidated CDA 1.1</name>
    </buildingBlockRepository>
</externalBuildingBlockRepositories>

@param $external-server-services-url the full url to the services including the trailing slash, e.g. https://art-decor.org/decor/services/
@return list of available external building block repositories
@since 2014-03-27
:)
declare function adserver:getRepositoriesFromServer($external-server-services-url as xs:string) as element() {
    let $external-server-services-url   := 
        if (ends-with($external-server-services-url, '/')) then 
            $external-server-services-url 
        else (
            $external-server-services-url || '/'
        )
    let $service-uri     := $external-server-services-url || 'ProjectIndex?format=xml'
    return
    try {
        let $requestHeaders := 
            <http:request method="GET" href="{$service-uri}">
                <http:header name="Content-Type" value="text/xml"/>
                <http:header name="Cache-Control" value="no-cache"/>
                <http:header name="Max-Forwards" value="1"/>
            </http:request>
        let $server-response := http:send-request($requestHeaders)
        let $server-check    :=
            if ($server-response[1]/@status='200') then () else (
                error(QName('http://art-decor.org/ns/error', 'RetrieveError'), concat('Server returned HTTP status: ',$server-response[1]/@status, ' for URI ''',$service-uri,''' with body ''',string-join($server-response[2], ' '),''''))
            )
        return
        <externalBuildingBlockRepositories used-url="{$service-uri}">
        {
            for $repository in doc($service-uri)/return/project[@repository='true']
            return
                <buildingBlockRepository url="{$external-server-services-url}" ident="{$repository/@prefix}" type="external" format="decor">
                {
                    for $lang in art:getArtLanguages()
                    return
                    <name language="{$lang}">{$repository/@name/string()}</name>
                }
                </buildingBlockRepository>
        }
        </externalBuildingBlockRepositories>
    }
    catch * {
        error(QName('http://art-decor.org/ns/error', 'RetrieveError'), concat('ERROR ',$err:code,'. Could not retrieve building block repositories from ''',$service-uri,'''. ',$err:description,' module: ',$err:module,' (',$err:line-number,' ',$err:column-number,')'))
    }
};

(:~ Set a new or update an existing external building block repositories
Example input: 
    <buildingBlockRepository url="https://art-decor.org/decor/services/" ident="ad1bbr-" type="external">
        <name language="en-US">CDA Release 2</name>
        <name language="nl-NL">CDA Release 2</name>
        <name language="de-DE">CDA Release 2</name>
    </buildingBlockRepository>

@param $buildingBlockRepository MUST contain the new buildingBlockRepository info
@return nothing or error you are not dba, or if the buildingBlockRepository element does not have attributes @url, @ident or @type=''external'' and at least one element <name language="ll-CC">
@since 2014-03-27
:)
declare function adserver:setServerExternalRepository($buildingBlockRepository as element()) {
    if (adserver:checkPermissions()) then (
        let $buildingBlockRepository    :=
            element {$buildingBlockRepository/name()} {
                $buildingBlockRepository/@url[. castable as xs:anyURI],
                $buildingBlockRepository/@ident[not(.='')],
                $buildingBlockRepository/@type,
                $buildingBlockRepository/@format[not(.=('','decor'))],
                $buildingBlockRepository/node()
            }
            
        return
        if ($buildingBlockRepository[name()='buildingBlockRepository'][@url][@ident][empty(@format)][@type='external'][name/@language] |
            $buildingBlockRepository[name()='buildingBlockRepository'][@url][@format[not(.='decor')]][@type='external'][name/@language]) then (
            let $existingBuildingBlockRepositories  := $adserver:docServerInfo/server-info/externalBuildingBlockRepositories
            let $existingBuildingBlockRepository    := 
                if ($buildingBlockRepository[@ident]) then
                    $existingBuildingBlockRepositories/buildingBlockRepository[@url=$buildingBlockRepository/@url][@ident=$buildingBlockRepository/@ident]
                else (
                    $existingBuildingBlockRepositories/buildingBlockRepository[@url=$buildingBlockRepository/@url]
                )
            return
            if ($existingBuildingBlockRepository) then (
                (: BBR already exists. Delete and write new :)
                update replace $existingBuildingBlockRepository with $buildingBlockRepository
            )
            else if ($existingBuildingBlockRepositories) then
                update insert $buildingBlockRepository into $existingBuildingBlockRepositories
            else (
                update insert <externalBuildingBlockRepositories>{$buildingBlockRepository}</externalBuildingBlockRepositories> into $adserver:docServerInfo/server-info
            )
        ) else (
            error(QName('http://art-decor.org/ns/error', 'InvalidFormat'), 'Element <buildingBlockRepository> must have attributes @url, @ident (when @format=''decor'') and @type=''external'' and at least one element <name language="ll-CC">')
        )
    ) else ()
};

(:~ Get the orbeon version so we know what to load in some cases like CSS

@return orbeonVersion, defaults to 3.9
@since 2018-09-04
:)
declare function adserver:getServerOrbeonVersion() as xs:string {
    let $orbeon-version    := $adserver:docServerInfo/server-info/orbeon-version
    
    return
        if (empty($orbeon-version)) then '3.9' else $orbeon-version
};

(:~ Get the orbeon version so we know what to load in some cases like CSS

@return orbeonVersion, defaults to 3.9
@since 2018-09-04
:)
declare function adserver:getServerOrbeonVersions() as element()* {
    <orbeon version="3.9" displayName="Orbeon 3.9"/> |
    <orbeon version="2018" displayName="Orbeon 2018.x"/> |
    <orbeon version="2019" displayName="Orbeon 2019.x"/>
};

(:~ Set the orbeon version so we know what to load in some cases like CSS

@param $orbeonVersion required string, e.g. 3.9 or 2017 or 2018. Check 
@return nothing or error if you are not dba
@since 2018-09-04
:)
declare function adserver:setServerOrbeonVersion($orbeonVersion as xs:string) {
    if (adserver:checkPermissions()) then (
        let $server-settings    := $adserver:docServerInfo/server-info
        
        return
        if ($server-settings/orbeon-version) then
            update value $server-settings/orbeon-version with $orbeonVersion
        else
            update insert <orbeon-version>{$orbeonVersion}</orbeon-version> into $server-settings
    ) else ()
};

(:~ Delete an existing external building block repository. The match is done based on @url and optionally on @ident, the rest is irrelevant.
If you omit $ident then all BBRs for the given $url are deleted

@param $url url of the bbr to-be-deleted
@param $ident ident of the bbr to-be-deleted
@return nothing or error you are not dba
@since 2014-03-27
:)
declare function adserver:deleteServerExternalRepository($url as xs:string, $ident as xs:string?) {
    if (adserver:checkPermissions()) then (
        let $existingBuildingBlockRepositories  := $adserver:docServerInfo/server-info/externalBuildingBlockRepositories
        return
            update delete $existingBuildingBlockRepositories/buildingBlockRepository[@url=$url][empty($ident) or @ident=$ident]
    ) else ()
};

(:~ Return the configured password for the requested user

@param $user username
@return password as xs:string?
@since 2015-05-06
:)
declare %private function adserver:getPassword($user as xs:string) as xs:string? {
    $adserver:docServerInfo//user[@user=$user][ancestor::system-users]/@pass
};

(:~ Return usernames that we have saved passwords for

@return $username as xs:string*
@since 2015-05-06
:)
declare function adserver:getSavedUsernames() as xs:string* {
    $adserver:docServerInfo/server-info/system-users/user/@user
};

(:~ Set the password for the requested user.

@param $user username
@param $pass password
@return nothing or error if you are not dba
@since 2015-05-06
:)
declare function adserver:setPassword($user as xs:string, $pass as xs:string) {
    if (adserver:checkPermissions()) then (
        let $server-settings    := $adserver:docServerInfo/server-info
        
        return
        if ($server-settings/system-users/user[@user=$user]) then
            update value $server-settings/system-users/user[@user=$user]/@pass with $pass
        else if ($server-settings/system-users) then
            update insert <user user="{$user}" pass="{$pass}"/> into $server-settings/system-users
        else (
            update insert <system-users><user user="{$user}" pass="{$pass}"/></system-users> into $server-settings
        )
    ) else ()
};

(:~ Logs in for the requested user at the requested path. Only possible for server/system level users like "xis-webservice"

@param $user username
@param $path database path
@return true|false or error
@since 2015-05-06
:)
declare function adserver:login($user as xs:string, $path as xs:string?) as xs:boolean {
    let $path   := if (string-length($path)=0) then '/db' else $path
    return xmldb:login($path, $user, adserver:getPassword($user))
};

(:~ Authenticates the requested user at the requested path. Only possible for server/system level users like "xis-webservice".
Check if the user, $user-id, can authenticate against the database collection $collection-uri. The function simply tries to 
read the collection $collection-uri, using the credentials $user-id and $password. Collection URIs can be specified either 
as a simple collection path or an XMLDB URI. It returns true if the authentication succeeds, false otherwise.

@param $user username
@param $path database path
@return true|false or error
@since 2015-05-06
:)
declare function adserver:authenticate($user as xs:string, $path as xs:string?) as xs:boolean {
    let $path   := if (string-length($path)=0) then '/db' else $path
    return xmldb:authenticate($path, $user, adserver:getPassword($user))
};

(:~ Facilitates getting new properties in art/install-data/server-info.xml into the live art-data/server-info.xml copy

@return nothing or error you are not dba or if the install-data/server-info.xml file is missing
@since 2014-03-27
:)
declare function adserver:mergeServerSettings() {
    if (adserver:checkPermissions()) then (
        let $strServerInfoName := concat(repo:get-root(),'art/install-data/server-info.xml')
        return
        if (doc-available($strServerInfoName)) then ( 
            let $installServerInfo := doc($strServerInfoName)/server-info
            return
                for $setting in $installServerInfo/*
                let $ns := $setting/namespace-uri()
                let $nm := $setting/local-name()
                return
                if ($adserver:docServerInfo/server-info/*[local-name()=$nm][namespace-uri()=$ns]) then (
                    (:already exists:)
                )
                else if ($nm='defaultLanguage') then (
                    adserver:setServerLanguage($setting)
                )
                else if ($nm='url-art-decor-api') then (
                    adserver:setServerURLArtApi($setting)
                )
                else if ($nm='url-art-decor-deeplinkprefix') then (
                    adserver:setServerURLArt($setting)
                )
                else if ($nm='url-art-decor-services') then (
                    adserver:setServerURLServices($setting)
                )
                else if ($nm='xformStylesheet') then (
                    adserver:setServerXSLArt($setting)
                )
                else if ($nm='orbeon-version') then (
                    adserver:setServerOrbeonVersion($setting)
                )
                else (
                    update insert $setting into $adserver:docServerInfo/server-info
                )
        ) else (
            error(QName('http://art-decor.org/ns/error', 'ServerInfoMissing'), concat('Cannot merge when server-info.xml is missing: ',$strServerInfoName))
        )
    ) else ()
};

(:~ Consolidated local function for checking if you are dba when you are writing info.

@return nothing or error you are not dba
@since 2014-03-27
:)
declare %private function adserver:checkPermissions() as xs:boolean {
    if (sm:is-dba(get:strCurrentUserName())) then (true()) else (
        error(QName('http://art-decor.org/ns/error', 'InsufficientPermissions'), 'Must be in group dba for full access')
    )
};