(:~ : Taxonomies functions. : : @author Rave Technologies, https://www.rave-tech.com/, 2017 :) (:~ : Update History : : Modified on 16/03/21: Resolve ticket CMS-236 :) module namespace bltaxonomy = 'http://www.rave-tech.com/bloomsbury/taxonomy'; import module namespace config = 'http://www.rave-tech.com/bloomsbury/config' at './module/config.xqm'; import module namespace audit = 'http://www.rave-tech.com/bloomsbury/audit' at './module/manage-audit.xqm'; import module namespace schematron = "http://github.com/Schematron/schematron-basex"; (:~ : Add Taxonomy into the system. : @param $body Taxonomy XML as document node (ACH-exportD:\2017\BLOOMSBURRY\taxnomy\T003.xml) : @header $authorization Authorization key : @return element(result) :) declare %updating %rest:path("/taxonomies") %rest:POST("{$body}") %rest:header-param("Authorization", "{$authorization}", "none") %rest:consumes("application/xml", "text/xml") function bltaxonomy:add($body as document-node(), $authorization as xs:string) { config:session-check($authorization), try { if(fetch:xml($body/taxonomy/file-path/string(),map { 'xinclude': false() })/*[fn:local-name()='taxonomy']) then if(fetch:xml($body/taxonomy/file-path/string())/*:taxonomy/@id) then update:output(FailureAttribute id not required) else if(fn:doc-available($body/taxonomy/file-path/string())) then let $taxonomyXml := fn:doc($body/taxonomy/file-path/string()) let $taxonomyID := if($taxonomyXml/taxonomy/@id/string()) then $taxonomyXml/taxonomy/@id/string() else fn:concat($config:TaxonomyIDPrefix,fn:string(convert:dateTime-to-integer(fn:adjust-dateTime-to-timezone(convert:integer-to-dateTime(prof:current-ms()))))) let $taxonomyName := $taxonomyXml/taxonomy/@name/string() let $updatedName := $body/taxonomy/name/string() let $targetUri := fn:concat($config:TaxonomyDir,$taxonomyID,'.xml') let $taxonomyXml := if($taxonomyXml/taxonomy/@id/string()) then () else copy $tax := $taxonomyXml modify insert node (attribute { 'id' } { $taxonomyID }) into $tax/taxonomy return $tax return (:Step 1: Check if taxonomy is already exist :) if(fn:doc-available(fn:concat($config:CoreDatabase,$targetUri))) then ( update:output(FailureTaxonomy is already available), config:update-message("[Taxonomy Add][Taxonomy is already available : " || $taxonomyID || "]") ) else bltaxonomy:validate-and-add-taxonomy($taxonomyXml, $taxonomyID, $taxonomyName, $targetUri, 'Taxonomy Add', config:session-value($authorization), $updatedName) else ( update:output(FailureTaxonomy XML is unrechable on this location), config:update-message("[Taxonomy Add][Taxonomy XML is unrechable on this location]") ) else update:output(FailurePlease ingest the correct XML) } catch * { admin:write-log("[Taxonomy Add][Error: " || $err:description || "]"), admin:write-log("[Taxonomy Add][Error: " || $err:additional || "]"), update:output(ErrorError generated. Please check system log) } }; (:~ : Update Taxonomy. : @param $body Taxonomy XML as document node (ACH-exportD:\2017\BLOOMSBURRY\taxnomy\T003.xml) : @header $authorization Authorization key : @return element(result) :) declare %updating %rest:path("/taxonomies/{$taxonomyID=.+}") %rest:PUT("{$body}") %rest:header-param("Authorization", "{$authorization}", "none") %rest:consumes("application/xml", "text/xml") function bltaxonomy:update( $body as document-node(), $taxonomyID as xs:string, $authorization as xs:string ) { config:session-check($authorization), try { if(fn:doc-available($body/taxonomy/file-path/string())) then let $fileLocation := $body/taxonomy/file-path/string() let $taxonomyXml := fn:doc($fileLocation) let $taxonomyXml := if($taxonomyXml/taxonomy/@id/string()) then () else copy $tax := $taxonomyXml modify insert node (attribute { 'id' } { $taxonomyID }) into $tax/taxonomy return $tax return if($taxonomyXml/taxonomy/@id/string() != $taxonomyID) then ( update:output(FailureTaxonomy ID is invalid), config:update-message("[Taxonomy Update][Taxonomy ID is invalid]") ) else let $taxonomyName := $taxonomyXml/taxonomy/@name/string() let $updatedName := $body/taxonomy/name/string() let $targetUri := fn:concat($config:TaxonomyDir,$taxonomyID,'.xml') return if(fn:doc-available(fn:concat($config:CoreDatabase,$targetUri))) then bltaxonomy:validate-and-add-taxonomy($taxonomyXml,$taxonomyID,$taxonomyName,$targetUri,'Taxonomy Update',config:session-value($authorization),$updatedName) else ( update:output(FailureTaxonomy is not available to update), config:update-message("[Taxonomy Update][Taxonomy is not available to update : " || $taxonomyID || "]") ) else if($body/taxonomy/file-path='') then let $taxonomyXml := db:open($config:CoreDatabase,$config:TaxonomyDir)/taxonomy[@id=$taxonomyID] return if($taxonomyXml) then let $taxonomyName := $taxonomyXml/@name/string() let $updatedName := $body/taxonomy/name/string() let $targetUri := fn:concat($config:TaxonomyDir,$taxonomyID,'.xml') return bltaxonomy:validate-and-add-taxonomy(document{$taxonomyXml},$taxonomyID,$taxonomyName,$targetUri,'Taxonomy Update',config:session-value($authorization),$updatedName) else ( update:output(FailureTaxonomy is not available to update), config:update-message("[Taxonomy Update][Taxonomy is not available to update : " || $taxonomyID || "]") ) else ( update:output(FailureTaxonomy XML is unrechable on this location), config:update-message("[Taxonomy Update][Taxonomy XML is unrechable on this location]") ) } catch * { admin:write-log("[Taxonomy Update][Error: " || $err:description || "]"), admin:write-log("[Taxonomy Update][Error: " || $err:additional || "]"), update:output(ErrorError generated. Please check system log) } }; (:~ : Display Taxonomy specific detail. : @param $taxonomyID ID of the taxonomy : @header $authorization Authorization key : @return element(result) :) declare %rest:path("/taxonomies/{$taxonomyID=.+}") %rest:GET %rest:header-param("Authorization", "{$authorization}", "none") function bltaxonomy:info( $taxonomyID as xs:string, $authorization as xs:string ) { config:session-check($authorization), try { let $targetUri := fn:concat($config:TaxonomyDir,$taxonomyID,'.xml') let $taxonomyXml := db:open($config:CoreDatabase,$targetUri) return if($taxonomyXml) then ( SuccessTaxonomy is available{$taxonomyXml}, config:non-update-message("[Taxonomy Info][Taxonomy information has been sent successfully : " || $taxonomyID || "]") ) else ( FailureTaxonomy is unavailable, config:non-update-message("[Taxonomy Info][Taxonomy is unavailable : " || $taxonomyID || "]") ) } catch * { admin:write-log("[Taxonomy Info][Error: " || $err:description || "]"), admin:write-log("[Taxonomy Info][Error: " || $err:additional || "]"), ErrorError generated. Please check system log } }; (:~ : To get specific or list of available taxonomies. : @param $query Name of the taxonomy to filter : @param $page Page number of the list optional : @param $size Total number of records to display in a page optional : @header $authorization Authorization key : @return element(result) :) declare %rest:path("/taxonomies") %rest:GET %rest:query-param("q", "{$query}") %rest:query-param("page", "{$page}") %rest:query-param("size", "{$size}") %rest:header-param("Authorization", "{$authorization}", "none") function bltaxonomy:list( $query as xs:string?, $page as xs:integer?, $size as xs:integer?, $authorization as xs:string ) { config:session-check($authorization), try { let $page := if($page) then $page else $config:page let $size := if($size) then $size else $config:size let $taxonomyRecords := { for $eachTaxonomy in db:open($config:CoreDatabase,$config:TaxonomyDir)/taxonomy[if($query) then (matches(@name,$query,'i')) else .] let $id := {$eachTaxonomy/@id/string()} let $name := {$eachTaxonomy/@name/string()} order by $name return {$id,$name} } let $countRecord := count($taxonomyRecords/taxonomy) let $start := if($page eq 1) then $page else if($page gt 1) then fn:sum(($page * $size)+1) - $size else fn:sum(($page * $size)) - $size let $end := if($page eq 1) then $size else if($page gt 1) then fn:sum(($start + $size)-1) else fn:sum($start + $size) return if($taxonomyRecords/taxonomy) then ( Success{$countRecord}{$taxonomyRecords/taxonomy[position() = $start to $end]}, config:non-update-message("[Taxonomy List][Taxonomy list has been sent successfully]") ) else ( SuccessTaxonomy is unavailable, config:non-update-message("[Taxonomy List][Taxonomy is unavailable]") ) } catch * { admin:write-log("[Taxonomy List][Error: " || $err:description || "]"), admin:write-log("[Taxonomy List][Error: " || $err:additional || "]"), ErrorError generated. Please check system log } }; (:~ : Delete specific taxonomy. : @param $taxonomyID ID of the taxonomy to delete : @header $authorization Authorization key : @return element(result) :) declare %updating %rest:path("/taxonomies/{$taxonomyID=.+}") %rest:DELETE %rest:header-param("Authorization", "{$authorization}") function bltaxonomy:delete( $taxonomyID as xs:string, $authorization as xs:string ) { config:session-check($authorization), try { let $targetUri := fn:concat($config:TaxonomyDir,$taxonomyID,'.xml') let $producttaxonomy := db:open($config:CoreDatabase,$config:ProductDir)/*:product/@taxonomyRef/string() return if($taxonomyID=$producttaxonomy) then update:output(Failuretaxonomy {$taxonomyID} is in used) else if(fn:doc-available(fn:concat($config:CoreDatabase,$targetUri))) then ( db:delete($config:CoreDatabase,fn:concat($config:TaxonomyDir,$taxonomyID,'.xml')), update:output(SuccessTaxonomy {$taxonomyID} deleted successfully), config:update-message("[Taxonomy Delete][TaxonomyID deleted successfully : " || $taxonomyID || "]") ) else update:output(SuccessTaxonomy {$taxonomyID} not available to delete) } catch * { admin:write-log("[Taxonomy Delete][Error: " || $err:description || "]"), admin:write-log("[Taxonomy Delete][Error: " || $err:additional || "]"), update:output(ErrorError generated. Please check system log) } }; (:~ : Add or update taxonomies. : @param $taxonomyXml Taxonomy XML content : @param $taxonomyID ID of the taxonomy : @param $name Name of the taxonomy : @param $targetUri The saving path of the taxonomy : @param $messageFlag The action of taxonomy (add or update) : @param $sessionValue Session Value : @param $title Updated title of the taxonomy : @return element(result) :) declare %private %updating function bltaxonomy:validate-and-add-taxonomy( $taxonomyXml as document-node(), $taxonomyID as xs:string?, $taxonomyName as xs:string, $targetUri as xs:string, $messageFlag as xs:string, $sessionValue as xs:string, $title as xs:string? ) { (:Step 1: Validate as per Relax NG :) let $taxonomyXml := if($title) then ( copy $c := $taxonomyXml modify ( replace value of node $c/taxonomy/@name with $title ) return $c ) else $taxonomyXml let $reportChunk := {$taxonomyID} {$title} {fn:adjust-dateTime-to-timezone(convert:integer-to-dateTime(prof:current-ms()))} {fn:substring-before($sessionValue,'$$$$')} {fn:substring-after($sessionValue,'$$$$')} let $startTime := fn:adjust-dateTime-to-timezone(convert:integer-to-dateTime(prof:current-ms())) let $validate := validate:rng-report($taxonomyXml, bin:decode-string(db:retrieve($config:CoreDatabase, fn:concat($config:ValidationDir,$config:TaxonomyRelaxNG)),'UTF-8'), fn:true()) return if($validate/status='valid') then ( config:update-message("[" || $messageFlag || "][Taxonomy is valid as per Relax NG : " || $taxonomyID || "]") , let $appendReport := let $updateReport := RELAX NG Validation {$startTime} {fn:adjust-dateTime-to-timezone(convert:integer-to-dateTime(prof:current-ms()))} Pass return copy $target := $reportChunk modify insert node $updateReport as last into $target/ingestion-report/steps return $target return (:Step 2: Validate as per Schematron :) let $startTime := fn:adjust-dateTime-to-timezone(convert:integer-to-dateTime(prof:current-ms())) let $schematron := schematron:compile(db:open($config:CoreDatabase, fn:concat($config:ValidationDir,$config:TaxonomySchematron))) let $validate := schematron:validate($taxonomyXml, $schematron) return if(schematron:is-valid($validate)) then ( db:replace($config:CoreDatabase,$targetUri,$taxonomyXml), audit:taxonomy($taxonomyID,$messageFlag,$sessionValue) , let $appendReport := let $updateReport := Schematron Validation {$startTime} {fn:adjust-dateTime-to-timezone(convert:integer-to-dateTime(prof:current-ms()))} Pass return copy $target := $appendReport modify ( insert node $updateReport as last into $target/ingestion-report/steps, insert node {fn:adjust-dateTime-to-timezone(convert:integer-to-dateTime(prof:current-ms()))} as last into $target/ingestion-report ) return $target let $reportUri := fn:concat($config:TaxonomyDir,$config:ReportDir,$taxonomyID,'_report.xml') return db:replace($config:CoreDatabase,$reportUri,$appendReport) , config:update-message("[" || $messageFlag || "][Taxonomy is valid as per schematron : " || $taxonomyID || "]"), config:update-message("[" || $messageFlag || "][A new Taxonomy added into the system : " || $taxonomyID || "]"), update:output(Success{$messageFlag}) ) else ( let $appendReport := let $updateReport := Schematron Validation {$startTime} {fn:adjust-dateTime-to-timezone(convert:integer-to-dateTime(prof:current-ms()))} Fail {$validate} return copy $target := $appendReport modify ( insert node $updateReport as last into $target/ingestion-report/steps, insert node {fn:adjust-dateTime-to-timezone(convert:integer-to-dateTime(prof:current-ms()))} as last into $target/ingestion-report ) return $target let $reportUri := fn:concat($config:TaxonomyDir,$config:ReportDir,if($taxonomyID!='') then $taxonomyID else fn:format-dateTime(fn:current-dateTime(), "[Y1,4][M01][D01][H01][m01][s01][f01]"),'_report.xml') return ( db:replace($config:CoreDatabase,$reportUri,$appendReport), update:output(Failure{if($taxonomyID!='') then $taxonomyID else fn:replace(fn:tokenize($reportUri,'/')[fn:last()],'.xml','')}Taxonomy is invalid as per schematron validation. Error report generated ), config:update-message("["|| $messageFlag || "][Taxonomy is invalid as per schematron : " || $taxonomyID || "]") ) ) ) else ( let $appendReport := let $updateReport := RELAX NG Validation {$startTime} {fn:adjust-dateTime-to-timezone(convert:integer-to-dateTime(prof:current-ms()))} Fail {$validate} return copy $target := $reportChunk modify ( insert node $updateReport as last into $target/ingestion-report/steps, insert node {fn:adjust-dateTime-to-timezone(convert:integer-to-dateTime(prof:current-ms()))} as last into $target/ingestion-report ) return $target (:let $reportUri := fn:concat($config:TaxonomyDir,$config:ReportDir,$taxonomyID,'_report.xml'):) let $reportUri := fn:concat($config:TaxonomyDir,$config:ReportDir,if($taxonomyID!='') then $taxonomyID else fn:format-dateTime(fn:current-dateTime(), "[Y1,4][M01][D01][H01][m01][s01][f01]"),'_report.xml') return ( db:replace($config:CoreDatabase,$reportUri,$appendReport) , config:update-message("[" || $messageFlag || "][Taxonomy is invalid as per Relax NG : " || $taxonomyID || "]"), update:output(Failure{if($taxonomyID!='') then $taxonomyID else fn:replace(fn:tokenize($reportUri,'/')[fn:last()],'_report.xml','')}Taxonomy is invalid as per Relax NG. Error report generated) ) ) }; (:~ : To Download Taxonomy error report : @param $taxonomyID ID of the taxonomy : @header $authorization Authorization key : @return element(result) :) declare %rest:path("/taxonomyreport/{$taxonomyID=.+}") %rest:GET %rest:header-param("Authorization", "{$authorization}", "none") function bltaxonomy:taxonomyreport( $taxonomyID as xs:string?, $authorization as xs:string ) { config:session-check($authorization), try { let $taxonomyErrordoc := db:open($config:CoreDatabase, fn:concat($config:TaxonomyDir,$config:ReportDir,$taxonomyID,'_report','.xml')) return if($taxonomyErrordoc) then let $uri := base-uri($taxonomyErrordoc) let $filename := fn:tokenize($uri,'/')[fn:last()] return ( if(file:is-dir($config:PublishReportDir)) then file:write(fn:concat($config:PublishReportDir,$filename),$taxonomyErrordoc) else ( file:create-dir($config:PublishReportDir), file:write(fn:concat($config:PublishReportDir,$filename),$taxonomyErrordoc)) , let $zipName := fn:concat($taxonomyID,'_',fn:format-dateTime(fn:current-dateTime(), "[Y1,4][M01][D01][H01][m01][s01][f01]")) let $filelist := file:list($config:PublishReportDir, true(),fn:concat($taxonomyID,'_report','.xml')) let $archive := archive:create($filelist ! element archive:entry { . }, $filelist ! file:read-binary($config:PublishReportDir || .)) let $ziplocation := fn:concat($config:OutDir,$zipName,'.zip') return ( file:write-binary(fn:concat($config:OutDir,$zipName,'.zip'),$archive), Success {$ziplocation} ) ) else FailureJob information is not available } catch * { admin:write-log("[Job Details][Error: " || $err:description || "]"), admin:write-log("[Job Details][Error: " || $err:additional || "]"), ErrorError generated. Please check system log } }; declare %rest:path("/contenttypefacet/{$taxonomyid=.+}") %rest:GET %rest:header-param("Authorization", "{$authorization}", "none") function bltaxonomy:get-taxonomies-contenttypefacet( $taxonomyid as xs:string, $authorization as xs:string ) { config:session-check($authorization), try { if($taxonomyid!='') then let $records := for $tyaxonomydoc in fn:doc(fn:concat($config:CoreDatabase,$config:TaxonomyDir,$taxonomyid,'.xml')) return if($tyaxonomydoc) then {$tyaxonomydoc/taxonomy/*[(descendant-or-self::*:facet[@role='contentType'])] } else return if($records[fn:local-name()='error']) then SuccessRelated taxonomies is not available. else Success{$records} else FailurePlease supply the content-id and component-id } catch * { admin:write-log("[Content Search][Error: " || $err:description || "]"), admin:write-log("[Content Search][Error: " || $err:additional || "]"), ErrorError generated. Please check system log } };