Files
svc-api-x/v1/resources/instance_operation_cfs_param.cfc
2026-04-20 20:53:01 +03:00

973 lines
54 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<cfcomponent extends="taffy.core.resource" taffy:uri="/instanceOperationCfsParams/{instanceOperationCfsParamUid}">
<!--- Вот здесь мы могли бы строить URI /instances/{instanceUid}/instanceOperations/{instanceOperationUid}/CfsParams, но это создает избыточность, у нас простые суррогатные первичные ключи. С другой стороны, контекст инстанса и операции у клиента всегда имеется. Но стоит ли передавать избыточную информацию? Это иногда провоцирует путаницу. Для POST мы можем передать необходимый контекст в теле запроса, а можем в URL.
В данном случае никакого смысла смотреть на все CFS параметры нет, только в рамках операции
Но: мы не хотели бы менять положение сущности в дереве. Либо она в корне, либо она ниже. И получится, когда мы выбираем один параметр, нам ни к чему контекст - мы к нему однозначно адресуемся.
Проголосуем против избыточности?
--->
<!--- Все методы неявно получают
arguments.usrId
arguments.contragentId
arguments.contractId
arguments.specificationId
arguments.requestArguments.usrId=usrCustomerInfo.usrId; //Integer!
arguments.requestArguments.contragentId=usrCustomerInfo.contragentId; //Integer
arguments.requestArguments.contractId=usrCustomerInfo.contractId; //Integer
arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //Integer
--->
<cfsilent>
<cfimport prefix="m" taglib="../lib"/>
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/><!---*** странно, почему мы его видим?---><!---вынести в апп?--->
</cfsilent>
<!--- cfproperty использовать не надо, это для веб сервисов --->
<cffunction name="init">
<!--- *** ---------------- !!! note camelCase in keys naming!!! ----------------- --->
<!--- для нового инстанса нам нужно знать хотя бы его класс (сервис) --->
<cfargument name="keys" type="struct" required=true/>
<cfargument name="params" type="struct" required=true/>
<!--- *** возможно, заранее разрешать все ключи - лишнее --->
<cfset this.keys = arguments.keys/>
<cfset this.params = arguments.params/>
<cfset this.instance_operation_cfs_param_uid = "00000000-0000-0000-0000-000000000000"/><!--- *** костыль default=--->
<cfset this.instance_operation_uid = "00000000-0000-0000-0000-000000000000"/><!--- *** костыль default=--->
<cfset this.instance_uid = "00000000-0000-0000-0000-000000000000"/><!--- *** костыль default=--->
<cfif structKeyExists(arguments.keys,"instanceOperationCfsParamUid") AND isValid("guid", arguments.keys.instanceOperationCfsParamUid)>
<cfset this.instance_operation_cfs_param_uid=arguments.keys.instanceOperationCfsParamUid/>
<cfquery name="local.qResolve">
select p.instance_operation_uid, o.instance_uid, p.svc_operation_cfs_param_id
from instance_operation_cfs_param p
join instance_operation o on (p.instance_operation_uid=o.instance_operation_uid)
where p.instance_operation_cfs_param_uid=<cfqueryparam cfsqltype="cf_sql_other" value=#arguments.keys.instanceOperationCfsParamUid# null=#!isValid("guid", arguments.keys.instanceOperationCfsParamUid)#/>
</cfquery>
<cfset this.instance_operation_uid=toString(local.qResolve.instance_operation_uid)/><!--- toString, чтобы не засорять вывод cfdump классами --->
<cfset this.instance_uid=toString(local.qResolve.instance_uid)/>
<cfset this.svc_operation_cfs_param_id = local.qResolve.svc_operation_cfs_param_id/>
</cfif>
<!--- *** обратить внимание, тут возможны конфликты противоречивых ключей, мы никак не контролируем. но если ресолвить в обратном порядке, они хотя бы будут согласованными (хотя могут отличаться от аргументов... пойми что лучше... или проверять и бросать исключение --->
<cfif structKeyExists(arguments.keys,"instanceOperationUid") AND isValid("guid", arguments.keys.instanceOperationUid)>
<cfset this.instance_operation_uid=arguments.keys.instanceOperationUid/>
<cfquery name="local.qResolve">
select o.instance_uid
from instance_operation o
where o.instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value=#arguments.keys.instanceOperationUid# null=#!isValid("guid", arguments.keys.instanceOperationUid)#/>
</cfquery>
<cfset this.instance_uid=toString(local.qResolve.instance_uid)/>
</cfif>
<cfif structKeyExists(arguments.keys,"instanceUid") AND isValid("guid",arguments.keys.instanceUid)>
<cfset this.instance_uid=arguments.keys.instanceUid/>
</cfif>
<cfif structKeyExists(arguments.keys,"svcOperationCfsParamId")><!--- хотя вот этот ключ известен всегда... но для известного параметра мы же можем его не передавать--->
<cfset this.svc_operation_cfs_param_id=arguments.keys.svcOperationCfsParamId/>
</cfif>
<cfif structKeyExists(arguments.params,"resourceRealm")>
<cfset this.resourceRealm=arguments.params.resourceRealm/>
</cfif>
<!--- <cfdump var=#this# abort=true/> --->
<!--- <cfdump var=#this#/> --->
<cfreturn this>
</cffunction>
<!--- ---------------------------------------------------------------------- --->
<!--- Прикладные функции, которые можно использовать в составе выражений. Аргументами им могут служить параметры, от которых мы зависим --->
<!--- Добавить обработку исключений --->
<cffunction name="dummy" returntype="any" access="public">
<cfargument name="arg" type="any"/>
<cfreturn arg/>
</cffunction>
<cffunction name="concat" returntype="string" access="public">
<cfset var local={}/>
<cfset var s=""/>
<cfloop array=#arguments# item="local.chunk">
<cfset s&="#local.chunk#"/>
</cfloop>
<cfreturn s/>
</cffunction>
<cffunction name="getValue"><!--- используем пока только для параметров, в принципе может видеть больше, чем положено --->
<cfargument name="token" type="string"/>
<!--- тут такой странный синтаксис: для скоупа params подставляем getCfsParam --->
<cfset var scope = trim(listGetAt(arguments.token,1,'.'))/>
<cfset var name = trim(listGetAt(arguments.token,2,'.'))/>
<cfif scope EQ "params">
<cfif listLen(arguments.token,'.') GT 2><!--- *** неуклюже. ради субпараметров --->
<cfreturn getCfsParam(name, trim(listGetAt(arguments.token,3,'.')))/>
<cfelse>
<cfreturn getCfsParam(name)/>
</cfif>
</cfif>
<cfreturn variables[scope][name]/><!--- *** вряд ли это отработает для субпараметров --->
</cffunction>
<!--- может быть, обобщить для наследуемых параметров... или для всех вообще --->
<cffunction name="getResourceRealm">
<!--- нужна отдельная функция, потому что resourceRealm может браться из параметров операции, а может наследоваться от родительского инстанса --->
<!--- *** отдельный вопрос - как мы получим предка, если у нас операция еще не сохранена? На фронте мы хотим в один прием сохранить и операцию и параметры (на самом деле для операции create - даже инстанс, операцию и параметры) --->
<!--- если операция не сохранена - мы как узнаем, есть у нее параметр resourceRealm, или нет? наверно, простой джойн тут не поможет
но никто не мешает спросить отдельно--->
<!--- *** тут возникает определенная путаница из-за того, что часть данных берется из параметров операции, а часть из параметров инстанса (кумулятивных) --->
<!--- <cfdump var=#this#/> --->
<cfif structKeyExists(this,"resourceRealm") AND len(this.resourceRealm)><!--- может быть, понятнее было бы брать прямо из параметров --->
<cfreturn this.resourceRealm/>
</cfif>
<!--- ищем у даннной операции CFS параметр resourceRealm ---><!--- <cfdump var=#this#/><cfabort/> --->
<cfquery name="local.qCfsParam">
select p.param_value
from svc_operation_cfs_param s
join instance_operation_cfs_param p on (s.svc_operation_cfs_param_id = p.svc_operation_cfs_param_id)
where s.svc_operation_cfs_param = 'resourceRealm'
AND p.instance_operation_uid = <cfqueryparam cfsqltype="cf_sql_other" value=#this.instance_operation_uid# null=#!isValid('guid',this.instance_operation_uid)#/>
</cfquery>
<!--- <cfdump var=#local.qCfsParam#/> --->
<!--- --->
<cfif local.qCfsParam.recordCount>
<!--- параметр определен в операции сервиса. Если его не нашли - значит, не судьба --->
<cfreturn local.qCfsParam.param_value/>
<cfelse>
<!--- у операции сервиса нет такого параметра - тогда по соглашению он определен в инстансе-предке. Тут нам надо знать хотя бы родительский инстанс --->
<!--- внимание, сложность. Для получения resourceRealm для параметра вновь создаваемого инстанса нам нужно ориентироваться на параметр - ссылку на родительский инстанс (пример - vdc), потому что текущего инстанса еще нет! --->
<!--- напоминание:
не путать родительский инстанс (связан параметром с инстансом - владельцем операции - владельцем данного параметра)
и инстанс-операцию-параметр (регулярная реляционная иерархия)
хотя инстанс и операция есть в параметрах (некоторое дублирование, потому что оркестратору все передается через параметры)
--->
<cfset local.instance_uid = this.instance_uid/>
<cfif !isValid("guid", local.instance_uid) OR local.instance_uid EQ "00000000-0000-0000-0000-000000000000">
<!--- тогда нам нужно найти параметр-референс и взять его значение --->
<!--- тот случай, когда нужно знать класс параметра и операции --->
<cfquery name="local.qRefParam">
select r.svc_operation_cfs_param
from svc_operation_cfs_param r
join svc_operation o on (r.svc_operation_id=o.svc_operation_id)
join svc_operation_cfs_param p on (o.svc_operation_id=p.svc_operation_id)
where p.svc_operation_cfs_param_id = <cfqueryparam cfsqltype="cf_sql_integer" value=#this.svc_operation_cfs_param_id# null=#!isValid('integer',this.svc_operation_cfs_param_id)#/>
AND r.ref_svc_id > 0
</cfquery>
<!--- <cfdump var=#local.qRefParam#/> --->
<cfloop query="local.qRefParam">
<cfif structKeyExists(this.params, local.qRefParam.svc_operation_cfs_param) AND isValid('guid', this.params[local.qRefParam.svc_operation_cfs_param])>
<cfset local.instance_uid = this.params[local.qRefParam.svc_operation_cfs_param]/>
</cfif>
</cfloop>
<!--- можно и более изощренно поступать, вызывая в этом цикле функцию рекурсивного поиска resourceRealm для каждого из референсных параметров, пока не найдем.
но пока если видим находим в параметрах ссылку на родителя - ищем там платформу, и все --->
<!--- вообще идея наследования платформы кажется не очень корректной - мы же можем ссылаться на нескольких предков... и реализация тяжеловесная
*** может быть, нужно метод получения платформы сделать всем инстансам, пусть сам знает, из какого параметра брать... это можно сделать конфигурируемым.
в обычной жизни брать из параметра
Можно сделать дополнительную фильтрацию по типу справочника (resourceRealm)
--->
</cfif>
<!--- внимание! мы тут опрашиваем параметры инстанса, а не операции! --->
<!--- *** тут возникает непонятная ссылка на себя, впрочем, она не мешает --->
<cfquery name="local.qCfsParam">
WITH RECURSIVE r AS (
SELECT
1 AS i
,e.display_name
,s.svc
,p.param
,p.param_value
,p.instance_uid::text
FROM instance e
JOIN instance_cfs_param p on (e.instance_uid=p.instance_uid)
JOIN svc s on (e.service_id=s.svc_id)
JOIN instance_operation_cfs_param op on (p.instance_operation_cfs_param_uid=op.instance_operation_cfs_param_uid)
LEFT JOIN svc_operation_cfs_param sp on (op.svc_operation_cfs_param_id=sp.svc_operation_cfs_param_id)
LEFT JOIN instance_cfs_param rp on (e.instance_uid=rp.instance_uid )
LEFT JOIN instance ri on (rp.instance_uid=ri.instance_uid)
WHERE e.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value=#local.instance_uid# null=#!isValid('guid',local.instance_uid)#/>
UNION
SELECT
i+1 AS i
,e.display_name
,s.svc
,p.param
,p.param_value
,p.instance_uid::text
FROM instance_cfs_param p
JOIN instance e on (p.instance_uid=e.instance_uid)
JOIN svc s on (e.service_id=s.svc_id)
JOIN r on (r.param_value=p.instance_uid::text)
WHERE r.i < 10
)
select param, param_value from r
order by r.i desc
</cfquery>
<cfif local.qCfsParam.recordCount EQ 0>
<!--- тогда зайдем от параметров операции (только в данном экземпляре, зависимости все должны быть уже созданы) --->
<cfquery name="local.qCfsParam">
WITH RECURSIVE r AS (
SELECT
1 AS i
,e.display_name
,s.svc
,sp.svc_operation_cfs_param as param
,p.param_value::text
,o.instance_uid::text
FROM instance e
JOIN instance_operation o ON (e.instance_uid=o.instance_uid AND o.operation='create')
JOIN instance_operation_cfs_param p on (o.instance_operation_uid=p.instance_operation_uid)
JOIN svc s on (e.service_id=s.svc_id)
--JOIN instance_operation_cfs_param op on (p.instance_operation_cfs_param_uid=op.instance_operation_cfs_param_uid)
JOIN svc_operation_cfs_param sp on (p.svc_operation_cfs_param_id=sp.svc_operation_cfs_param_id AND sp.ref_svc_id > 0)
--LEFT JOIN instance_cfs_param rp on (e.instance_uid=rp.instance_uid )
--LEFT JOIN instance ri on (rp.instance_uid=ri.instance_uid)
WHERE e.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value=#local.instance_uid# null=#!isValid('guid',local.instance_uid)#/>
UNION
SELECT
i+1 AS i
,e.display_name
,s.svc
,p.param
,p.param_value
,p.instance_uid::text
FROM instance_cfs_param p
JOIN instance e on (p.instance_uid=e.instance_uid)
JOIN svc s on (e.service_id=s.svc_id)
JOIN r on (r.param_value=p.instance_uid::text)
WHERE r.i < 10
)
select param, param_value from r
order by r.i desc
</cfquery>
</cfif>
<!--- <cfdump var=#local.qCfsParam#/>--->
<cfloop query="local.qCfsParam">
<cfif local.qCfsParam.param EQ "resourceRealm">
<cfreturn local.qCfsParam.param_value/>
</cfif>
</cfloop>
<cfreturn "Resource Realm Not Found"/>
</cfif>
</cffunction>
<cffunction name="getCfsParam">
<cfargument name="param" type="string"/>
<cfargument name="subparam" type="string" required=false/>
<!--- Секретность игнорируется. Все секреты доступны, как есть --->
<!--- правда, мы тут можем работать только с сохраненными параметрами. Можем попробовать полагаться на правило: зависимые параметры всегда позже (не факт, что это получится при конкурентном сохранении) --->
<!--- проблема: нам нужен тут instance_operation_uid, но таскать его в аргументах по всей цепочке вызовов неудобно. Если бы это у нас был метод CFS параметра, все было бы просто - это у нас поле параметра --->
<!--- ошибка: в строке параметров у нас ключ param.subparam, а в аргументах он разобран по частям
при этом мы ожидаем в параметрах структуру paramName:{subparamName:subparamValue}
но почему не находим в сохраненных? возможно такое совпадение, что в сценарии у нас как раз надо выбрать svcId а они не --->
<!--- {"startupConfiguration":{"vdcUid":"ea81db31-2197-407d-b32b-e60577c2671c"}} --->
<!--- this.params <cfdump var=#this.params#/>
arguments <cfdump var=#arguments# /> --->
<cfif structKeyExists(this.params,arguments.param)><!--- AND len(this.params[arguments.param]) --->
<cfif structKeyExists(arguments,"subparam")><!--- *** не изящно, но просто и понятно --->
<cfreturn (this.params[arguments.param])[arguments.subparam]/>
<cfelse>this.params[arguments.param] <!--- <cfdump var=#this.params[arguments.param]#/> --->
<cfreturn this.params[arguments.param]/>
</cfif>
</cfif>
<!--- не нашли параметра в запросе, ищем в сохраненных --->
<cfquery name="local.qCfsParam">
select p.param_value
from instance_operation_cfs_param p
join svc_operation_cfs_param s on (p.svc_operation_cfs_param_id = s.svc_operation_cfs_param_id)
where p.instance_operation_uid = <cfqueryparam cfsqltype="cf_sql_other" value=#this.instance_operation_uid# null=#!isValid('guid',this.instance_operation_uid)#/>
AND s.svc_operation_cfs_param = <cfqueryparam cfsqltype="cf_sql_varchar" value=#arguments.param#/>
</cfquery>
<!--- <cfdump var=#this.keys#/> --->
<cfif structKeyExists(arguments,"subparam")><!--- *** не изящно, но просто и понятно --->
<cfset var value = deserializeJson(local.qCfsParam.param_value)/>
<cfif isStruct(value) AND structKeyExists(value, arguments.subparam)>
<cfreturn value[arguments.subparam]/>
<cfelse>
<cfreturn ""/><!--- *** а надо выбросить 404 --->
</cfif>
<cfelse>
<cfreturn local.qCfsParam.param_value/>
</cfif>
</cffunction>
<!--- <cffunction name="getValueFromStruct" returntype="string" hint="returns scalar">
<cfargument name="struct" type="struct" required="true"/>
<cfargument name="path" type="string" required="true"/>
<cftry>
<cfreturn structGet("arguments.struct.#arguments.path#")/>
<cfcatch type="any">
<!--- можно ожидать ошибки, если по указанному пути расположена не структура --->
<cfreturn cfcatch.message/><!--- халява, для упрощения диагностики --->
</cfcatch>
</cftry>
</cffunction> --->
<cffunction name="getValueFromStruct" returntype="any">
<cfargument name="struct" type="struct" required="true"/>
<cfargument name="path" type="string" required="true"/>
<cftry>
<cfreturn structGet("arguments.struct.#arguments.path#")/>
<cfcatch type="any">
<!--- можно ожидать ошибки, если по указанному пути расположена не структура --->
<cfreturn cfcatch.message/><!--- халява, для упрощения диагностики --->
</cfcatch>
</cftry>
</cffunction>
<cffunction name="getStringFromStruct" returntype="string" hint="returns scalar">
<cfargument name="struct" type="struct" required="true"/>
<cfargument name="path" type="string" required="true"/>
<cfset var value = getValueFromStruct(arguments.struct,arguments.path)/>
<cfif isStruct(value) OR isArray(value)>
<cfreturn serializeJson(value)/>
</cfif>
<cfreturn toString(value)/>
</cffunction>
<cffunction name="getKeyListFromStruct" returntype="string" hint="returns list">
<cfargument name="struct" type="struct" required="true"/>
<cfargument name="path" type="string" required="true"/>
<cftry>
<cfreturn structKeyList(structGet("arguments.struct.#arguments.path#"))/>
<cfcatch type="any">
<!--- можно ожидать ошибки, если по указанному пути расположена не структура --->
<cfrethrow/>
<cfreturn "#cfcatch.message# #cfcatch.detail#"/><!--- халява, для упрощения диагностики --->
</cfcatch>
</cftry>
</cffunction>
<cffunction name="getArrayAsListFromStruct" returntype="string" hint="returns list">
<cfargument name="struct" type="struct" required="true"/>
<cfargument name="path" type="string" required="true"/>
<cftry>
<cfreturn arrayToList(structGet("arguments.struct.#arguments.path#"))/>
<cfcatch type="any">
<!--- можно ожидать ошибки, если по указанному пути расположена не структура --->
<cfrethrow/>
<cfreturn "#cfcatch.message# #cfcatch.detail#"/><!--- халява, для упрощения диагностики --->
</cfcatch>
</cftry>
</cffunction>
<!--- <cffunction name="getInstanceState" returntype="struct">
<cfargument name="instanceUid" type="guid" required="true"/>
<cfset var local={}/>
<cfquery name="local.qInstance" datasource="cmdb">
select g.instance_state_uid, g.version, g.dt_state, g.instance_data, g.is_test, g.instance_uid
from instance_state g
where g.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value=#arguments.instanceUid#/>
order by g.version desc
limit 1
</cfquery>
<cfreturn deserializeJson(local.qInstance.instance_data)/>
<cftry>
<cfset var structConfig = deserializeJson(local.qInstance.instance_data)/>
<cfcatch type="ANY">
<cfreturn {"error":"error parsing state"}/>
</cfcatch>
</cftry>
<cfif len(structConfig)>
<cfreturn structConfig/>
</cfif>
<cfreturn {}/>
</cffunction> --->
<cffunction name="getInstanceState" returntype="struct">
<cfargument name="instanceUid" default=#this.instance_uid#/><!--- type="guid" --->
<cfif !isValid("guid",arguments.instanceUid)>
<cfreturn {}/><!--- иначе при неопределенном параметре мы получаем исключение --->
</cfif>
<cfset var local={}/>
<cfquery name="local.qInstance" datasource="cmdb">
select g.instance_state_uid, g.version, g.dt_state, g.instance_data, g.is_test, g.instance_uid
from instance_state g
where g.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value=#arguments.instanceUid#/>
order by g.version desc
limit 1
</cfquery>
<!--- <cfreturn deserializeJson(local.qInstance.instance_data)/><cfabort/> --->
<cftry>
<cfset var structConfig = deserializeJson(local.qInstance.instance_data)/>
<cfcatch type="ANY">
<cfreturn {"error":"error parsing state"}/>
</cfcatch>
</cftry>
<cfif isEmpty(structConfig)>
<cfreturn {}/>
</cfif>
<cfreturn structConfig/>
</cffunction>
<cffunction name="getResourceRealmConfig" returntype="struct">
<cfargument name="resourceRealm" type="string" default=#getResourceRealm()#/><!--- платформа может быть определена для родительского инстанса где то в иерархии --->
<cfset var local={}/>
<cfquery name="local.qResourceRealm" datasource="cmdb">
select r.resource_realm_id, r.properties
from resource_realm r
where r.resource_realm=<cfqueryparam cfsqltype="cf_sql_varchar" value=#arguments.resourceRealm#/>
</cfquery>
<!--- <cfdump var=#arguments#/>
<cfdump var=#local.qResourceRealm#/> --->
<cftry>
<cfset var structConfig = deserializeJson(local.qResourceRealm.properties)/>
<cfcatch type="ANY">
<cfreturn {"error":"error parsing resource realm properties"}/>
<!--- вообще-то такого быть не должно: свойства хранятся в поле jsonb --->
</cfcatch>
</cftry>
<cfif len(structConfig)>
<cfreturn structConfig/>
</cfif>
<cfreturn {}/>
</cffunction>
<!--- ReST methods --->
<!--- ----------------------------------------------------------------------------------------- --->
<!--- ----------------------------------------------------------------------------------------- --->
<!--- ----------------------------------------------------------------------------------------- --->
<cffunction name="get" hint="CFS параметр операции инстанса">
<cfargument name="instanceOperationCfsParamUid" type="string" required=true hint="type:guid"/>
<cftry>
<cfset this.helper.validateField(arguments, "instanceOperationCfsParamUid", "guid")/>
<cfcatch type="invalidParamValue">
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
</cfcatch>
</cftry>
<cfset local={}/>
<cfquery name="local.qCfsParam" result="local.result">
select
<m:field_set titleMapOut="local.titleMap" lengthOut="fieldCount">
<m:field>iop.instance_operation_cfs_param_uid::text as instance_operation_cfs_param_uid</m:field>
<m:field>iop.instance_operation_uid::text as instance_operation_uid</m:field>
<m:field>iop.svc_operation_cfs_param_id</m:field>
<!--- <m:field>iop.param_value</m:field> --->
<m:field>case when sop.is_sensitive then '********' else iop.param_value end as param_value </m:field><!--- внимание! если параметр типа MAP, то значение нужно разобрать и замаскировать секреты --->
<m:field>iop.note</m:field>
<m:field>to_char(iop.dt_created, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as dt_created</m:field>
<m:field>iop.creator_id</m:field>
<m:field>sop.svc_operation_cfs_param</m:field>
<m:field>sop.data_type</m:field>
<m:field>null as data_descriptor</m:field>
<m:field formatter=#(x)=>((isArray(x) OR isEmpty(x))? x : listToArray(x))#>sop.value_list</m:field>
<m:field>u.login as creator_login</m:field>
<m:field>u.shortname as creator_shortname</m:field>
<m:field formatter=#request.castToBool#>sop.is_sensitive</m:field>
<m:field formatter=#request.castToBool#>sop.is_hidden</m:field>
<m:field formatter=#request.castToBool#>sop.is_disabled</m:field>
<m:field>sop.man</m:field>
<m:field>sop.func</m:field>
<m:field>sop.expression</m:field>
<m:field>sop.nested_ref</m:field>
<m:field>sop.state_path</m:field>
<m:field>sop.depends_on_cfs_params</m:field>
<m:field>sop.config::text as config</m:field>
<m:field>e.service_id</m:field>
<m:field>e.instance_uid::text as instance_uid</m:field>
</m:field_set>
from instance_operation_cfs_param iop
join svc_operation_cfs_param sop on (iop.svc_operation_cfs_param_id=sop.svc_operation_cfs_param_id)
join instance_operation io on (iop.instance_operation_uid=io.instance_operation_uid)
join instance e on (io.instance_uid=e.instance_uid)
join specification_item si on (e.specification_item_id=si.specification_item_id)
left outer join usr u on (iop.creator_id=u.usr_id)
where iop.instance_operation_cfs_param_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationCfsParamUid#" null=#!isValid('guid',arguments.instanceOperationCfsParamUid)#/>
AND si.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/>
</cfquery>
<cfif local.qCfsParam.recordCount EQ 0>
<cfreturn representationOf(this.helper.formatMessage("Not Found")).withStatus(404)/>
</cfif>
<cfif len(local.qCfsParam.func)><!--- приоритет отдается функции перед списком значений--->
<cfset var args = {
"functionName":"#local.qCfsParam.func#",
"svcId":#local.qCfsParam.service_id#,
"contractId":#arguments.contractId#
}/> <!--- если появятся новые аргументы у новых функций, будем добавлять их сюда --->
<cfset local.qCfsParam.value_list=generateValueList(argumentCollection=#args#)/> <!--- можно перечислить именованные аргументы обычным порядком, но с коллекцией потенциально более гибко --->
<!--- <cfdump var=#local.qCfsParam#/><cfabort/> --->
<cfif len(trim(local.qCfsParam.value_list)) AND listLen(local.qCfsParam.value_list) EQ 1>
<cfset local.qCfsParam.default_value=local.qCfsParam.value_list/>
</cfif>
<cfelseif len(local.qCfsParam.nested_ref)>
<cfset var fNestedRef = generateClosure(local.qCfsParam.nested_ref, local.qCfsParam.config)/>
<cfset local.qCfsParam.nested_ref_data = fNestedRef() />
<cfelseif len(local.qCfsParam.state_path)>
<!--- для экономии читаем стейт только при необходимости --->
<cfquery name="local.qCurrentState">
select g.instance_state_uid, g.version, g.instance_data, g.is_test, g.instance_uid
from instance_state g
where g.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value=#local.qCfsParam.instance_uid#/>
order by g.version desc
limit 1
</cfquery>
<cfset var currentState = {}/>
<cftry>
<cfset currentState = deserializeJson(local.qCurrentState.instance_data)/>
<cfcatch type="ANY"></cfcatch>
</cftry>
<cfset local.qCfsParam.value_list = getListFromState(currentState, local.qCfsParam.state_path)/>
</cfif>
<cfif (len(local.qCfsParam.func) OR len(local.qCfsParam.expression) OR len(local.qCfsParam.state_path) OR len(local.qCfsParam.nested_ref))
AND len(local.qCfsParam.value_list) EQ 0>
<cfset local.qCfsParam.value_list = []/>
</cfif>
<cfif local.qCfsParam.data_type EQ "map" OR local.qCfsParam.data_type EQ "map-fixed" OR local.qCfsParam.data_type EQ "array-map-fixed">
<cfset processMap(local.qCfsParam)/><!--- query passed by reference --->
</cfif>
<cfset var out=structNew("linked")/>
<cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/>
<cfset "out.instanceOperationCfsParam" = this.helper.appendRecord(
structNew("linked"), "", local.titleMap, local.qCfsParam, this.helper.snake2camel
)/>
<cfset "out.runDurationMs"=getTickCount() - request.startTickCount/>
<cfreturn representationOf(out) />
</cffunction><!--- get --->
<cffunction name="delete" hint="Удаление CFS параметра операции по ключу.">
<cfargument name="instanceOperationCfsParamUid" type="string" required=true hint="type:guid"/>
<cftry>
<cfset this.helper.validateField(arguments, "instanceOperationCfsParamUid", "guid")/>
<!--- *** Нужна проверка, что операция не была выполнена, иначе она становится архивной --->
<cfcatch type="invalidParamValue">
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
</cfcatch>
</cftry>
<cfset local={}/>
<cftry><!--- *** без проверок существования --->
<cfquery name="local.qCheck" result="local.result">
select
io.dt_submit, io.submit_result
from instance_operation_cfs_param iop
join instance_operation io on iop.instance_operation_uid=io.instance_operation_uid
where iop.instance_operation_cfs_param_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationCfsParamUid#" null=#!isValid('guid',arguments.instanceOperationCfsParamUid)#/>
</cfquery>
<cfif left(local.qCheck.submit_result,1) EQ "2"><!--- 201 etc --->
<cfreturn representationOf(this.helper.formatMessage("Operation already started", "Parameter deletion disabled for started operation")).withStatus(422)/>
</cfif>
<!--- <cfquery name="local.qCheckSpecification" result="local.result">
select si.specification_id
from instance_operation_cfs_param iop
join instance_operation io on iop.instance_operation_uid=io.instance_operation_uid
join instance e on (io.instance_uid=e.instance_uid)
left outer join specification_item si on (e.specification_item_id=si.specification_item_id)
where iop.instance_operation_cfs_param_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationCfsParamUid#" null=#!isValid('guid',arguments.instanceOperationCfsParamUid)#/>
AND si.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/>
</cfquery>
<cfif local.qCheckSpecification.recordCount EQ 0>
<cfreturn representationOf(this.helper.formatMessage("Instance not accessible", "Instance does not belong to the current specification, contract or contragent")).withStatus(403)/>
</cfif> --->
<cfquery name="local.qCheckAccess" result="local.result">
select count(*) as cnt
from instance_operation_cfs_param iop
join instance_operation io on (iop.instance_operation_uid=io.instance_operation_uid)
join instance e on (io.instance_uid=e.instance_uid)
join specification_item si on (e.specification_item_id=si.specification_item_id)
where iop.instance_operation_cfs_param_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationCfsParamUid#" null=#!isValid('guid',arguments.instanceOperationCfsParamUid)#/>
AND si.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/>
</cfquery>
<cfif local.qCheckAccess.cnt EQ 0>
<cfreturn representationOf(this.helper.formatMessage("Instance not accessible", "Instance of this CFS parameter is not accessible to the current user (at least does not belong to the default specification)")).withStatus(403)/>
</cfif>
<cfquery name="local.qSave">
delete from instance_operation_cfs_param
where instance_operation_cfs_param_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationCfsParamUid#" null=#!isValid('guid',arguments.instanceOperationCfsParamUid)#/>
</cfquery>
<cfcatch type="any">
<cfreturn representationOf(this.helper.formatException(cfcatch, "Internal Error")).withStatus(500)/><!--- это не нужно показывать в продуктиве --->
</cfcatch>
</cftry>
<cfreturn noData().withStatus(204, "No Content") />
</cffunction><!--- delete --->
<cffunction name="put" hint="запись CFS параметра операции инстанса">
<cfargument name="instanceOperationCfsParamUid" type="string" required=true hint="type:guid"/>
<cfargument name="paramValue" type="string" required=true/>
<cfargument name="note" type="string" required=false default=""/>
<cfset var local={}/>
<cftry>
<cfset checkInstanceParam(arguments.instanceOperationCfsParamUid, arguments.paramValue, arguments.usrId)/>
<cfcatch type="invalidParamValue">
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
</cfcatch>
</cftry>
<cfquery name="local.qSave" result="local.result">
update instance_operation_cfs_param set
dt_created=<cfqueryparam cfsqltype="cf_sql_timestamp" value="#Now()#" />
,creator_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.usrId#" />
,param_value=<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.paramValue#" /> <!--- htmlEditFormat --->
,note=<cfqueryparam cfsqltype="cf_sql_varchar" value="#htmlEditFormat(arguments.note)#" />
where instance_operation_cfs_param_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationCfsParamUid#" null=#!isValid('guid',arguments.instanceOperationCfsParamUid)#/>
</cfquery>
<!--- *** проверить существование - 404 --->
<cfreturn noData().withStatus(204, "No Content") />
</cffunction><!--- put --->
<cffunction name="checkInstanceParam">
<cfargument name="instanceOperationCfsParamUid" type="guid" required=true/>
<cfargument name="paramValue" required=true/>
<cfargument name="usrId" type="numeric" required=true/>
<cfset var local={}/>
<cfquery name="local.qCheck" result="local.result">
select svc_operation_cfs_param_id
from instance_operation_cfs_param
where instance_operation_cfs_param_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationCfsParamUid#" null=#!isValid('guid',arguments.instanceOperationCfsParamUid)#/>
</cfquery>
<cfif local.qCheck.recordCount EQ 0>
<cfthrow type="invalidParamValue" message="Cannot find CFS parameter by instanceOperationCfsParamUid=#arguments.instanceOperationCfsParamUid#"/>
</cfif>
<cfset CreateObject("component", "instance_operation_cfs_param_ls").checkParam(local.qCheck.svc_operation_cfs_param_id, arguments.paramValue, arguments.usrId, arguments.instanceOperationCfsParamUid)/>
</cffunction>
<cffunction name="processMap" returntype="void" access="public">
<cfargument name="qParam" type="query" required=true/><!--- работаем с текущей строкой query. передача query это скорее колхоз, всего-то надо 4 понятных аргумента.
Конечно, то, что часть из них - id, не упрощает восприяие кода --->
<!--- Выполняем 2 задачи (*** вероятно, правильно их разделить по разным функциям)
- сформировать дескриптор
- замаскировать секреты --->
<!--- здесь могут использоваться 2 критерия: формат аргумента, array/struct, либо тип --->
<cfset local.spContainer = {}/><!--- может быть map или array of map --->
<cfset local.spMapArray = []/>
<!--- мы хотим обработать и случай array-map-fixed --->
<cftry>
<cfset local.spContainer = deserializeJSON(arguments.qParam.param_value)/> <!--- а собственно зачем нам тут local? помогает чем-то? --->
<cfif (arguments.qParam.data_type EQ "array-map-fixed")>
<cfset local.spMapArray = isEmpty(local.spContainer) ? [] : local.spContainer />
<cfelse>
<cfset local.spMapArray = [local.spContainer]/>
</cfif>
<cfcatch type="any">
<cfset local.spMapArray = [{"error":"#cfcatch.message#"}]/><!--- теряем все данные --->
</cfcatch>
</cftry>
<cfquery name="local.qSubparam">
select
sp.svc_operation_cfs_param_id
,sp.svc_operation_cfs_subparam_id
,sp.svc_operation_cfs_subparam
,sp.label
,sp.data_type
,sp.value_list
,sp.is_required
,sp.descr
,sp.man
,sp.default_value
,sp.minlength
,sp.maxlength
,sp.regex
,sp.sort
,sp.is_sensitive
,sp.depends_on_cfs_params
,sp.expression
,sp.ref_svc_id
,sp.unique_scope
,sp.default_compute
,sp.is_hidden
,sp.is_disabled
from svc_operation_cfs_subparam sp
where sp.svc_operation_cfs_param_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.qParam.svc_operation_cfs_param_id#"/>
order by sp.sort
</cfquery>
<!--- <cfdump var=#local.qSubparam#/><cfabort/> --->
<cfquery name="local.qInstSubparam">
select
sp.instance_operation_cfs_param_uid::text as instance_operation_cfs_param_uid
,sp.instance_operation_cfs_subparam
,sp.note
,sp.sort
,sp.is_sensitive
from instance_operation_cfs_subparam sp
where sp.instance_operation_cfs_param_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.qParam.instance_operation_cfs_param_uid#" null=#!isValid("guid",arguments.qParam.instance_operation_cfs_param_uid)#/>
order by sp.sort
</cfquery>
<!--- формируем дескриптор --->
<cfset var mapDescriptor=structNew("linked")/>
<cfset var parser=createObject("component","lib.expression_parser")/>
<cfloop query="local.qSubparam">
<cfset structInsert(mapDescriptor, local.qSubparam.svc_operation_cfs_subparam,
{
"svcOperationCfsSubparamId":"#local.qSubparam.svc_operation_cfs_subparam_id#",
"svcOperationCfsSubparam":"#local.qSubparam.svc_operation_cfs_subparam#",
"label":"#local.qSubparam.label#",
"dataType":"#local.qSubparam.data_type#",
"valueList":'#(len(local.qSubparam.expression)?
(parser.eval(
qSubparam.expression,
{
component:"resources.instance_operation_cfs_param",
keys:{
instanceOperationCfsParamUid:"#toString(arguments.qParam.instance_operation_cfs_param_uid)#", /*note camelCase*/
svcOperationCfsParamId:"#toString(arguments.qParam.svc_operation_cfs_param_id)#" /*note camelCase*/
},
params:{}
}
))
: local.qSubparam.value_list)#',
"dependsOnCfsParams":"#local.qSubparam.depends_on_cfs_params#",
"expression":"#local.qSubparam.expression#",
"minlength":"#local.qSubparam.minlength#",
"maxlength":"#local.qSubparam.maxlength#",
"regex":"#local.qSubparam.regex#",
"man":"#local.qSubparam.man#",
"descr":"#local.qSubparam.descr#",
"defaultValue":"#local.qSubparam.default_value#",
"isRequired":#request.castToBool(local.qSubparam.is_required)#,
"isSensitive":#request.castToBool(local.qSubparam.is_sensitive)#,
"isHidden":#request.castToBool(local.qSubparam.is_hidden)#,
"isHidden":#request.castToBool(local.qSubparam.is_disabled)#,
"refSvcId":"#local.qSubparam.ref_svc_id#",
"uniqueScope":"#local.qSubparam.unique_scope#",
"defaultCompute":"#local.qSubparam.default_compute#",
"isModifiableDefinition":false
}, true
)
/>
</cfloop>
<cfloop index="local.i" from=1 to=#arrayLen(local.spMapArray)#><!--- *** искусственное оборачивание в массив вот для этого, не придумал ничего умнее
чтобы не дублировать цикл по субпараметрам. Сделано некрасиво, но работать должно.
Ну а как сделать? Если массив - делать цикл по массиву, а если map-сразу обрабатыввать map. При этом запрос к таблице сабпараметров не хочется делать лишний раз.
--->
<!--- может быть, лучше смотрелось бы arrayMap, но тут в ней будет цикл по query, и надо это делать в cfscript... строчек будет явно больше,
и в cfscript циклы по query какие-то я не помню ... кстати, вместо цикла по query можно наверно использовать structMap по контенту --->
<!--- интересная и неожиданная разница между циклом по массиву и циклом по индексу массива:
в первом случае возвращается копия элемента, во втором мы естественно имеем дело со ссылокой на элемент,
а нам сейчас нужно второе --->
<cfif isStruct(local.spMapArray[local.i])>
<cfloop query="local.qSubparam">
<cfif local.qSubparam.is_sensitive AND structKeyExists(local.spMapArray[local.i],local.qSubparam.svc_operation_cfs_subparam)>
<cfset local.spMapArray[local.i][local.qSubparam.svc_operation_cfs_subparam] = "********"/>
</cfif>
</cfloop>
</cfif>
</cfloop>
<!--- *** проверку, что это не map-fixed, можно добавить здесь --->
<!--- чтобы не вставляли в параметр что попало --->
<!--- здесь мы не делаем цикл по массиву, поскольку не поддерживаем массив расширяемых map --->
<cfif arrayLen(spMapArray) AND isStruct(local.spMapArray[1])>
<cfloop query="local.qInstSubparam">
<cfset structInsert(mapDescriptor, local.qInstSubparam.instance_operation_cfs_subparam,
{
"note":"#local.qInstSubparam.note#",
"isSensitive":#request.castToBool(local.qInstSubparam.is_sensitive)#,
"isModifiableDefinition":true
}, true
)
/>
<cfif local.qInstSubparam.is_sensitive AND structKeyExists(local.spMapArray[1],local.qInstSubparam.instance_operation_cfs_subparam)>
<cfset local.spMapArray[1]["#local.qInstSubparam.instance_operation_cfs_subparam#"] = "********"/>
</cfif>
</cfloop>
</cfif>
<cfset arguments.qParam.data_descriptor = mapDescriptor/>
<cfif (arguments.qParam.data_type EQ "array-map-fixed")>
<cfset arguments.qParam.param_value = serializeJson(local.spMapArray)/><!--- как есть --->
<cfelse>
<cfset arguments.qParam.param_value = arrayLen(local.spMapArray) ? serializeJson(local.spMapArray[1]) : ""/><!--- вытаскиваем из массива-обертки --->
</cfif>
</cffunction>
<cffunction name="generateValueList" returntype="string" access="public">
<cfargument name="functionName" type="string" required="true"/>
<!--- остальные атрибуты необязательные, в argumentCollection (еще вопрос, насколько безопасно объявлять один из аргументов без остальных) --->
<cfswitch expression=#arguments.functionName#>
<cfcase value="">
<cfreturn ""/>
</cfcase>
<cfcase value="getAvailableResourceRealms">
<cfreturn getAvailableResourceRealms(arguments.svcId, arguments.contractId)/><!--- *** неочевидно, но ожидаются в argumentCollection --->
</cfcase>
<cfcase value="getSampleList"><!--- for debug --->
<cfreturn "dummy1,dummy2"/>
</cfcase>
<cfdefaultcase>
<cfreturn "function not found"/>
</cfdefaultcase>
</cfswitch>
</cffunction>
<cffunction name="getAvailableResourceRealms" returnType="string" access="public">
<cfargument name="svcId"/>
<cfargument name="contractId"/>
<cfset var local={}/>
<cfquery name="local.qAvailableResourceRealm"><!--- *** distinct халява, но придумывать корректную формулировку времени мало --->
select distinct r.resource_realm, r.sort
from resource_realm r
join resource_realm_access a on
(r.resource_realm_id=a.resource_realm_id
AND (a.contract_id=<cfqueryparam cfsqltype="CF_SQL_INTEGER" value=#arguments.contractId# null=#!isValid("integer", arguments.contractId)#/>
OR a.contract_id=0) /*0 means access to any contract*/
AND a.is_enabled)
join svc s on r.resource_realm_type_id=s.resource_realm_type_id
where s.svc_id=<cfqueryparam cfsqltype="CF_SQL_INTEGER" value=#arguments.svcId# null=#!isValid("integer", arguments.svcId)#/>
order by r.sort, r.resource_realm
</cfquery> <!--- <cfdump var=#arguments#/> cfdump здесь провоцирует NPE --->
<cfif local.qAvailableResourceRealm.recordCount>
<cfreturn valueList(local.qAvailableResourceRealm.resource_realm)/>
<cfelse>
<cfreturn ""/><!--- иначе для пустого резалтсета генерируется null --->
</cfif>
</cffunction>
<!--- для вложенных справочников --->
<!--- дублировано: deck-tool/instance_operation.cfm --->
<cffunction name="getSelectedResourceRealm" returnType="string">
<cfset var local={}/>
<cfquery name="local.qSelectedResourceRealm">
select iop.param_value
from instance_operation_cfs_param iop
join svc_operation_cfs_param sop on (iop.svc_operation_cfs_param_id=sop.svc_operation_cfs_param_id)
where iop.instance_operation_uid=<cfqueryparam cfsqltype="CF_SQL_OTHER" value=#d.instance_operation_uid# null=#!isValid("guid", d.instance_operation_uid)#/>
AND sop.svc_operation_cfs_param='resourceRealm'
order by 1
</cfquery> <!--- <cfdump var=#arguments#/> cfdump здесь провоцирует NPE --->
<cfreturn local.qSelectedResourceRealm.param_value/>
</cffunction>
<cffunction name="generateClosure" returntype="function">
<cfargument name="functionName" type="string" required="true"/>
<cfargument name="config" type="string" required="true"/>
<!--- остальные атрибуты необязательные, в argumentCollection --->
<cfswitch expression=#arguments.functionName#>
<cfcase value="">
<cfreturn function(){}/>
</cfcase>
<cfcase value="getRefFromRRealmConfig">
<cfreturn function(){return getRefFromRRealmConfig(getSelectedResourceRealm(),config)}/>
<!--- тут нам внезапно нужен контекст ресурсной платформы. При первичной отрисовке он может быть неизвестен (кроме специальных случаев, когда есть дефолтная платформа, или она вообще одна --->
<!--- теперь даже не знаю, хорошая ли практика - explicitly scope variables: с closures, похоже, так не принято --->
</cfcase>
<cfcase value="getSampleConfig"><!--- for debug --->
<cfreturn function(){return deserializeJson('{"providerVdc": [ { "hystax-pvdc": { "storageVdcProfile": [ ] } }, { "v1cl1-vsan-pvdc": { "albSegroup": [ "SEGROUP-V1CL1-VSAN-SHARED-01", "SEGROUP-V1CL1-VSAN-SHARED-02" ], "storageVdcProfile": [ "v1-backup-itprotect" ] } }, { "v1cl2-pvdc": { "albSegroup": [ "SEGROUP-V1CL2-SHARED-01", "SEGROUP-V1CL2-SHARED-02" ], "storageVdcProfile": [ "V1-SATA", "V1CL1-F1R1-SSD", "V1CL1-F2R6-SSD", "V1CL1-SAS" ] } }, { "v1cl3-vsan-pvdc": { "albSegroup": [ "SEGROUP-V1CL3-VSAN-SHARED-01", "SEGROUP-V1CL3-VSAN-SHARED-02" ], "storageVdcProfile": [ "V1-SATA", "v1-sata-cl3", "v1-sata-migr", "V1CL1-SAS", "V1CL3-F1R5-SSD", "V1CL3-F1R6-SSD_new", "V1CL3-F2R1-SSD", "V1CL3-F2R6-SSD" ] } }, { "v1cl4-vsan-pvdc": { "albSegroup": [ "SEGROUP-V1CL4-VSAN-SHARED-01" ], "storageVdcProfile": [ "V1-SATA", "v1-sata-migr", "V1CL3-F1R6-SSD_new", "V1CL4-F1R1-SSD", "V1CL4-F1R5-SSD", "V1CL4-F2R1-SSD" ] } }, { "v2cl2-1c-pvdc": { "storageVdcProfile": [ "V1CL1-F2R1-SSD", "V1CL1-F2R6-SSD" ] } } ]}')} />
</cfcase>
<cfdefaultcase>
<cfreturn "function not found"/>
</cfdefaultcase>
</cfswitch>
</cffunction>
<cffunction name="getRefFromRRealmConfig" returntype="any">
<cfargument name="resourceRealm" type="string" required="true"/>
<cfargument name="config" type="string" required="true"/>
<cfquery name="qResourceRealmConfig">
select properties::text
from resource_realm
where resource_realm='ngcloud.ru'
<!--- <cfqueryparam cfsqltype="cf_sql_varchar" value=#arguments.resourceRealm#/> --->
</cfquery>
<!--- <cfset var local={}/> ---> <!--- паранойя... и есть шансы, что я неправильно понимаю эту химию скоупов--->
<cfset var props = deserializeJson(qResourceRealmConfig.properties)/>
<cfset var cfg = deserializeJson(arguments.config)/> <!--- удобнее было бы передавать сразу структуру впр --->
<cfset cfg={"path":"vcd.providerVdc"}/><!--- *** временный пример для отладки --->
<!--- засада на ровном месте: у нас в конфиге оказался массив вместо структуры --->
<!--- вернуть нам нужно не просто содержимое по пути, а вместе с контейнером --->
<cfset var path=cfg.path/><!--- *** обработать исключение --->
<cfset var containerName = listLast(path,".")/>
<cfset var result = structNew()/>
<cfset structInsert(result, containerName, structGet("props.#path#"))/>
<cfreturn result/>
</cffunction>
<!--- duplicated in deck-tool --->
<cffunction name="getListFromState" returntype="string" hint="returns list">
<cfargument name="state" type="struct" required="true"/>
<cfargument name="path" type="string" required="true"/>
<cftry>
<cfreturn structKeyList(structGet("arguments.state.#arguments.path#"))/>
<cfcatch type="any">
<!--- можно ожидать ошибки, если по указанному пути расположена не структура --->
<cfreturn cfcatch.message/><!--- для упрощения диагностики --->
</cfcatch>
</cftry>
</cffunction>
</cfcomponent>
<!--- [{"b":"12","secret1":"preved"},{"b":"13","secret1":"preved404"},{"b":"14","secret1":"preved402"}] --->