Files
svc-api-x/v1/resources/instance_operation_default.cfc
T

249 lines
12 KiB
Plaintext
Raw 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="/instanceOperations/{instanceUid}/{svcOperationId}" hint="template for default instance operation. Legacy URL: /instanceOperations/default/{svcOperationId}">
<!--- *** вот похоже, что для deafult неправильно считается valueList (конкретно resourceRealm) --->
<!--- ну и как мне передать второй параметр для GET? --->
<cfsilent>
<cfimport prefix="m" taglib="../lib"/>
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/>
</cfsilent>
<cffunction name="get" hint="Шаблон операции экземпляра"><!--- *** TODO проверка принадлежности тенанту --->
<cfargument name="instanceUid" type="string" required=true hint="type:guid|'default'"/>
<cfargument name="svcOperationId" type="string" required=true hint="type:integer"/>
<!--- <cfargument name="usrId" type="string" hint="type:integer; no need to provide this argument in request, it is injected by IAM"/> ---><!--- arguments.usrId неявно инжектируется из Application.cfm, а с ним contractId, contragentId ... --->
<cftry>
<cfif arguments.instanceUid NEQ 'default'>
<cfset this.helper.validateField(arguments, "instanceUid", "guid")/>
</cfif>
<cfset this.helper.validateField(arguments, "svcOperationId", "integer")/>
<cfcatch type="invalidParamValue">
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
</cfcatch>
</cftry>
<cfset var local={}/>
<cfquery name="local.qSvcOperation" result="local.result">
select
<m:field_set titleMapOut="local.titleMap" lengthOut="local.fieldCount">
<m:field title="ID" cfSqlType="CF_SQL_INTEGER">o.svc_operation_id</m:field>
<m:field>o.svc_id</m:field>
<m:field title="operation">o.operation</m:field>
<m:field title="URL">o.url</m:field>
<m:field title="Описание">o.descr</m:field>
<m:field title="Руководство">o.man</m:field>
</m:field_set>
from svc_operation o
where o.svc_operation_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.svcOperationId#" null=#!isValid('integer',arguments.svcOperationId)#/>
</cfquery>
<cfif local.qSvcOperation.recordCount EQ 0>
<cfreturn representationOf(this.helper.formatMessage("Not Found")).withStatus(404)/>
</cfif>
<!--- получаем параметры из свежего стейта --->
<cfset local.instanceDataParams = {}/>
<cfset var currentState = {}/>
<cfquery name="local.qState" result="local.result">
select instance_data->'params' as params,
instance_data::text as instance_data
from instance_state
where instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceUid#" null=#!isValid('guid',arguments.instanceUid)#/>
order by version desc
limit 1
</cfquery>
<cfif local.qState.recordCount GT 0>
<cftry>
<cfset var currentState = deserializeJson(local.qState.instance_data)/>
<cfset local.instanceDataParams = deserializeJson(local.qState.params)/>
<cfcatch type="ANY">
<cfdump var=#cfcatch#/><cfabort/>
</cfcatch>
</cftry>
</cfif>
<cfquery name="local.qCfsParam" result="local.result">
select
<m:field_set titleMapOut="local.cfsParamMap" lengthOut="local.fieldCount">
<m:field title="ID" cfSqlType="CF_SQL_INTEGER">p.svc_operation_cfs_param_id</m:field>
<!--- <m:field cfSqlType="CF_SQL_INTEGER">p.svc_operation_id</m:field> --->
<m:field>p.svc_operation_cfs_param</m:field>
<m:field>p.label</m:field>
<m:field>p.data_type</m:field>
<m:field>null as data_descriptor</m:field>
<m:field formatter=#function(x){return listToArray(x);}#>p.value_list</m:field>
<m:field <!--- formatter=#function(x){return listToArray(generateValueList(x));}# --->>p.func</m:field><!--- *** отчаявшись сделать красиво --->
<m:field>p.ref_svc_id</m:field>
<m:field formatter=#request.castToBool#>p.is_required</m:field>
<m:field>p.default_value</m:field><!--- can be overridden bu default_compute --->
<m:field>p.default_compute</m:field>
<m:field>p.regex</m:field>
<m:field>p.unique_scope</m:field>
<m:field>p.maxlength</m:field>
<m:field>p.minlength</m:field>
<m:field>p.maxvalue</m:field>
<m:field>p.minvalue</m:field>
<m:field>p.descr</m:field>
<m:field>p.man</m:field>
<m:field>p.sort</m:field>
<m:field>p.nested_ref</m:field>
<!--- <m:field>p.config::text as config</m:field> --->
<m:field>p.config::text</m:field><!--- в таком виде конфиг доступен для кода, но не выводится в респонсе --->
<m:field>null as nested_ref_data</m:field>
<m:field>p.state_path</m:field>
<m:field formatter=#request.castToBool#>(
select 1 from svc_operation_cfs_param m
join svc_operation om on (m.svc_operation_id=om.svc_operation_id)
join svc_operation oc on (om.svc_id=oc.svc_id AND om.operation='modify' AND oc.operation='create')
join svc_operation_cfs_param c on (oc.svc_operation_id=c.svc_operation_id AND m.svc_operation_cfs_param=c.svc_operation_cfs_param)
where c.svc_operation_cfs_param_id=p.svc_operation_cfs_param_id
order by c.svc_operation_cfs_param_id
limit 1
) as is_modifiable</m:field>
<m:field formatter=#request.castToBool#>p.is_sensitive</m:field>
</m:field_set>
from svc_operation_cfs_param p
where p.svc_operation_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.svcOperationId#" null=#!isValid('integer',arguments.svcOperationId)#/>
order by p.sort, p.svc_operation_cfs_param_id
</cfquery>
<!--- тут разорвана обработка, ниже есть повторный проход по параметрам --->
<cfloop query="local.qCfsParam">
<cfif len(func)><!--- приоритет отдается функции перед списком значений--->
<cfset var args = {
"functionName":"#func#",
"svcId":#local.qSvcOperation.svc_id#,
"contractId":#arguments.contractId#
}/> <!--- если появятся новые аргументы у новых функций, будем добавлять их сюда --->
<!--- <cfset local.qCfsParam.value_list=generateValueList(argumentCollection=#args#)/> --->
<cfinvoke component="instance_operation_cfs_param" method="generateValueList" argumentCollection=#args# returnVariable="local.qCfsParam.value_list"/>
<cfif len(trim(local.qCfsParam.value_list)) AND listLen(local.qCfsParam.value_list) EQ 1>
<cfset local.qCfsParam.default_value=local.qCfsParam.value_list/><!--- *** не очень красиво перетирать query, но делаем это довольно часто --->
</cfif>
<cfelseif len(local.qCfsParam.nested_ref)><!--- *** спрашивается, зачем нам изгаляться и возвращать замыкание, когда нам нужен json --->
<!--- <cfset var fNestedRef = generateClosure(local.qCfsParam.nested_ref, local.qCfsParam.config)/> --->
<cfset var args = {
"functionName":"#local.qCfsParam.nested_ref#",
"config":"#local.qCfsParam.config#"
}/>
<cfinvoke component="instance_operation_cfs_param" method="generateClosure" argumentCollection=#args# returnVariable="local.fNestedRef"/>
<cfset local.qCfsParam.nested_ref_data = local.fNestedRef() />
<cfelseif len(local.qCfsParam.state_path) AND isStruct(currentState)><!--- deserializeJson может вернуть пустую строку вместо структуры,
по крайней мере, если получает поле пустого резалтсета --->
<cfset var args = {
"state":#currentState#,
"path":"#local.qCfsParam.state_path#"
}/>
<cfinvoke component="instance_operation_cfs_param"
method="getListFromState"
argumentCollection=#args#
returnVariable="local.qCfsParam.value_list"
/>
</cfif>
<cfif data_type EQ "map"><!--- *** частичное дублирование с instance_operation_cfs_param.processMap --->
<!--- без полей инстанса, только шаблон --->
<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
from svc_operation_cfs_subparam sp
where sp.svc_operation_cfs_param_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#svc_operation_cfs_param_id#"/>
order by sp.sort
</cfquery>
<cfset var mapDescriptor=structNew("linked")/>
<cfloop query="local.qSubparam">
<cfset structInsert(mapDescriptor, local.qSubparam.svc_operation_cfs_subparam,
{
"man":"#local.qSubparam.man#",
"isSensitive":#request.castToBool(local.qSubparam.is_sensitive)#,
"isModifiableDefinition":false
}, true
)
/>
</cfloop>
<cfset local.qCfsParam.data_descriptor = mapDescriptor/>
</cfif><!---/map --->
</cfloop>
<cfset queryDeleteColumn(local.qCfsParam, "func")/>
<cfset var out=structNew("linked")/>
<cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/>
<cfset "out.svcOperation" = this.helper.appendRecord(
structNew("linked"), "", local.titleMap, local.qSvcOperation, this.helper.snake2camel
)/>
<cfset "out.svcOperation.cfsParams"=[]/>
<!--- подставляем значение из стейта, если оно там есть (некорректно, потому что в стейте RFS параметры) --->
<cfloop query=#local.qCfsParam#>
<cfset local.qCfsParam.default_value = computeDefault(local.qCfsParam.default_compute, local.qCfsParam.default_value, qSvcOperation.svc_id, arguments.usrId)/><!--- *** не очень хорошо модифицировать запрос --->
<cfif len(local.qCfsParam.default_value) EQ 0>
<!--- и вот наконец мы извлекаем старое значение из стейта --->
<cfset var paramName = this.helper.snake2camel(local.qCfsParam.svc_operation_cfs_param)/>
<cfif structKeyExists(local.instanceDataParams, paramName)>
<cfset var oldValue = structFind(local.instanceDataParams, paramName)/>
<cfset local.qCfsParam.default_value = isStruct(oldValue) ? serializeJson(oldValue) : oldValue/> <!--- потому что передаем строку, а не объект --->
</cfif>
</cfif>
<cfset var rec = this.helper.appendRecord(structNew("linked"), "", local.cfsParamMap, local.qCfsParam, this.helper.snake2camel)/>
<cfset arrayAppend(out.svcOperation.cfsParams, rec)/>
</cfloop>
<cfset "out.runDurationMs"=getTickCount() - request.startTickCount/>
<cfreturn representationOf(out) />
</cffunction>
<!--- *** выглядит ужасно, но красивый вариант не придумывается ряд месяцев --->
<!--- *** Внимание! нужно учитывать скоуп уникальности --->
<cffunction name="computeDefault">
<cfargument name="defaultCompute"/>
<cfargument name="original"/>
<cfargument name="service_id" type="numeric"/>
<cfargument name="usr_id" type="numeric"/>
<cfswitch expression=#arguments.defaultCompute#>
<cfcase value="display_name">
<cfreturn CreateObject("component", "instance_ls").generateDefaultName(arguments.service_id,arguments.usr_id)/>
</cfcase>
<cfcase value="append_pseudorandom">
<!--- <cfset var generator=createObject('component', 'lib.TokenGenerator')/>
<cfset generator.init()/> --->
<cfset var generator = new lib.TokenGenerator()/>
<cfreturn "#arguments.original##lcase(generator.nextToken(6))#"/> <!--- почему-то длина отличается, чтобы получить 8, пишу 6 --->
</cfcase>
<cfdefaultcase>
<cfreturn #arguments.original#/>
</cfdefaultcase>
</cfswitch>
</cffunction>
</cfcomponent>