973 lines
54 KiB
Plaintext
973 lines
54 KiB
Plaintext
<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"}] ---> |