Files
svc-api-x/v1/resources/instance_operation.cfc
T
2025-04-23 12:15:57 +03:00

243 lines
13 KiB
Plaintext

<cfcomponent extends="taffy.core.resource" taffy:uri="/instanceOperations/{instanceOperationUid}">
<cfsilent>
<cfimport prefix="m" taglib="../lib"/>
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/><!---*** странно, почему мы его видим?---><!---вынести в апп?--->
</cfsilent>
<cffunction name="get" hint="Операция над экземпляром сервиса"><!--- *** TODO проверка принадлежности тенанту --->
<cfargument name="instanceOperationUid" type="string" required=true hint="type:guid"/>
<!--- arguments.specificationId injected implicitly --->
<cftry>
<cfset this.helper.validateField(arguments, "instanceOperationUid", "guid")/>
<cfcatch type="invalidParamValue">
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
</cfcatch>
</cftry>
<cfset var out={}/>
<cfquery name="local.qInstanceOperation" result="local.result">
select
<m:field_set titleMapOut="local.titleMap" lengthOut="local.fieldCount">
<m:field>o.instance_operation_uid::text as instance_operation_uid</m:field>
<m:field>o.operation</m:field>
<!--- <m:field>o.resource_realm_id</m:field>
<m:field>r.resource_realm</m:field> --->
<m:field>o.instance_uid::text as instance_uid</m:field>
<m:field>to_char(o.dt_submit, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as dt_submit</m:field>
<m:field>o.submit_result</m:field>
<m:field>o.error_log</m:field>
<m:field>to_char(o.dt_start, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as dt_start</m:field>
<m:field>to_char(o.dt_finish, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as dt_finish</m:field>
<m:field title="Длит. сек">extract('epoch' from coalesce(o.dt_finish,CURRENT_TIMESTAMP)- o.dt_start) as duration</m:field>
<m:field formatter=#request.castToBool#>o.is_successful</m:field>
<m:field>e.display_name</m:field>
<m:field>e.service_id</m:field>
<m:field>e.specification_item_id</m:field>
<m:field>to_char(o.dt_created, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as dt_created</m:field>
<m:field>to_char(o.dt_updated, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as dt_updated</m:field>
<m:field>o.updater_id</m:field>
<m:field>u.login as updater_login</m:field>
<m:field>u.shortname as updater_shortname</m:field>
<m:field>v.svc</m:field>
<m:field>so.svc_operation_id</m:field>
<m:field formatter=#request.castToBool#>coalesce((o.dt_start IS NOT NULL AND o.dt_finish IS NULL AND o.submit_result='201'),false) as is_in_progress</m:field>
<m:field formatter=#request.castToBool#>coalesce((o.dt_start IS NULL AND o.submit_result='201'),false) as is_pending</m:field>
</m:field_set>
from instance_operation o
join instance e on (o.instance_uid=e.instance_uid)
join specification_item i on (e.specification_item_id=i.specification_item_id)
join specification s on (i.specification_id=s.specification_id)
join contract d on (s.contract_id=d.contract_id)
join contragent k on (d.contragent_id=k.contragent_id)
join svc v on (e.service_id=v.svc_id)
join svc_operation so on (v.svc_id=so.svc_id AND o.operation=so.operation)
<!--- left outer join resource_realm r on (o.resource_realm_id=r.resource_realm_id) --->
left outer join usr u on (o.updater_id=u.usr_id)
where <!--- u.usr_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.usrId#/> AND--->
o.instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationUid#" null=#!isValid('guid',arguments.instanceOperationUid)#/>
AND s.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/>
</cfquery>
<!--- <cfdump var=#local.qInstanceOperation#/><cfabort/> --->
<cfif local.qInstanceOperation.recordCount EQ 0>
<cfreturn representationOf(this.helper.formatMessage("Not Found")).withStatus(404)/>
</cfif>
<!--- Чтобы не нагружать второй селект проверкой принадлежности клиенту, мы берем ключ не из аргументов, а из первого запроса --->
<cfquery name="local.qStage" result="local.result">
select
<m:field_set titleMapOut="local.stageMap" lengthOut="local.fieldCount">
<m:field>ios.instance_operation_stage_uid::text as instance_operation_stage_uid</m:field>
<m:field>ios.stage</m:field>
<m:field formatter=#request.castToBool#>ios.is_successful</m:field>
<m:field>to_char(ios.dt_start, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as dt_start</m:field>
<m:field>to_char(ios.dt_finish, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as dt_finish</m:field>
<m:field>round(extract('epoch' from coalesce(ios.dt_finish,CURRENT_TIMESTAMP)- ios.dt_start),1) as duration</m:field>
</m:field_set>
from instance_operation_stage ios
where ios.instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#local.qInstanceOperation.instance_operation_uid#" null=#!isValid('guid',local.qInstanceOperation.instance_operation_uid)#/>
order by dt_start asc
</cfquery>
<cfquery name="local.qState" result="local.result">
select
<m:field_set titleMapOut="local.stateTitleMap" lengthOut="local.fieldCount">
<m:field title="instance_state_uid">st.instance_state_uid::text as instance_state_uid</m:field>
<m:field title="v.">st.version</m:field>
<m:field title="creator_id">st.creator_id</m:field>
<m:field title="dt_state">to_char(st.dt_state, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as dt_state</m:field>
<m:field formatter=#request.castToBool#>st.is_test</m:field>
<m:field title="instance_operation_uid">st.instance_operation_uid::text as instance_operation_uid</m:field>
<m:field title="instance_data" formatter=#function(x){return (deserializeJson(x))}#>st.instance_data::text as instance_data</m:field>
</m:field_set>
from instance_state st
where st.instance_operation_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#local.qInstanceOperation.instance_operation_uid#" null=#!isValid('guid',local.qInstanceOperation.instance_operation_uid)#/>
order by st.version desc limit 1
</cfquery>
<cfquery name="local.qCfsParam" result="local.result">
select
<m:field_set titleMapOut="local.cfsParamTitleMap" lengthOut="fieldCount">
<m:field title="instance_operation_cfs_param_uid">iop.instance_operation_cfs_param_uid::text as instance_operation_cfs_param_uid</m:field>
<!--- <m:field title="instance_operation_uid">instance_operation_uid::text as instance_operation_uid</m:field> --->
<m:field>sop.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>
<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.label</m:field>
<m:field>sop.data_type</m:field>
<m:field formatter=#function(x){return listToArray(x);}#>sop.value_list</m:field>
<m:field>sop.ref_svc_id</m:field>
<m:field>sop.func</m:field>
<m:field formatter=#request.castToBool#>sop.is_required</m:field>
<m:field>sop.default_value</m:field>
<m:field>sop.regex</m:field>
<m:field>sop.unique_scope</m:field>
<m:field>sop.descr</m:field>
<m:field>sop.sort</m:field>
<m:field>iop.note</m:field>
<m:field formatter=#request.castToBool#>sop.is_sensitive</m:field>
</m:field_set>
from svc_operation_cfs_param sop
left outer join instance_operation_cfs_param iop
on (sop.svc_operation_cfs_param_id=iop.svc_operation_cfs_param_id
AND iop.instance_operation_uid = <cfqueryparam cfsqltype="cf_sql_other"
value="#local.qInstanceOperation.instance_operation_uid#"
null=#!isValid('guid',local.qInstanceOperation.instance_operation_uid)#/>
)
where sop.svc_operation_id = <cfqueryparam cfsqltype="cf_sql_integer"
value=#local.qInstanceOperation.svc_operation_id#
null=#!isValid('integer',local.qInstanceOperation.svc_operation_id)#/>
order by sop.sort, sop.svc_operation_cfs_param_id
</cfquery>
<cfloop query="local.qCfsParam">
<cfif len(func)><!--- приоритет отдается функции перед списком значений--->
<cfset var args = {
"functionName":"#func#",
"svcId":#local.qInstanceOperation.service_id#,
"contractId":#arguments.contractId#
}/> <!--- если появятся новые аргументы у новых функций, будем добавлять их сюда --->
<cfset local.qCfsParam.value_list=generateValueList(argumentCollection=#args#)/> <!--- можно перечислить именованные аргументы обычным порядком, но с коллекцией потенциально более гибко --->
<!--- <cfdump var=#local.qCfsParam#/><cfabort/> --->
</cfif>
</cfloop>
<!--- <cfquery name="local.qAvailableResourceRealm" result="local.result">
select
<m:field_set titleMapOut="local.realmTitleMap" lengthOut="local.realmFieldCount">
<m:field>r.resource_realm_id</m:field>
<m:field>r.resource_realm_type_id</m:field>
<m:field>r.resource_realm</m:field>
</m:field_set>
from resource_realm r
join resource_realm_type t on (r.resource_realm_type_id=t.resource_realm_type_id)
/*left outer join resource_realm p on (r.parent_id=p.resource_realm_id)*/
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#/>
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=#local.qInstanceOperation.service_id#/>
order by 1
</cfquery> --->
<cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/>
<cfset "out.instanceOperation" = this.helper.appendRecord(
structNew("linked"), "", local.titleMap, local.qInstanceOperation, this.helper.snake2camel
)/>
<cfset "out.instanceOperation.cfsParams"=[]/>
<cfloop query=#local.qCfsParam#>
<cfset arrayAppend(out.instanceOperation.cfsParams, this.helper.appendRecord(structNew("linked"), "", local.cfsParamTitleMap, local.qCfsParam, this.helper.snake2camel))/>
</cfloop>
<cfset "out.instanceOperation.stages"=[]/>
<cfloop query=#local.qStage#>
<cfset arrayAppend(out.instanceOperation.stages, this.helper.appendRecord(structNew("linked"), "", local.stageMap, local.qStage, this.helper.snake2camel))/>
</cfloop>
<cfset "out.instanceOperation.state"=(local.qState.recordCount GT 0) ? this.helper.appendRecord(structNew("linked"), "", local.stateTitleMap, local.qState, this.helper.snake2camel) : {}/>
<!--- <cfset "out.instanceOperation.availableResourceRealms"=[]/>
<cfloop query=#local.qAvailableResourceRealm#>
<cfset arrayAppend(out.instanceOperation.availableResourceRealms, this.helper.appendRecord(structNew("linked"), "", local.realmTitleMap, local.qAvailableResourceRealm, this.helper.snake2camel))/>
</cfloop> --->
<cfset "out.runDurationMs"=getTickCount() - request.startTickCount/>
<cfreturn representationOf(out) />
</cffunction>
<!--- *** дублируются --->
<cffunction name="getAvailableResourceRealms" returnType="string">
<cfargument name="svcId"/>
<cfargument name="contractId"/>
<cfset var local={}/>
<cfquery name="local.qAvailableResourceRealm"><!--- *** distinct халява, но придумывать корректную формулировку времени мало --->
select distinct r.resource_realm
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 1
</cfquery> <!--- <cfdump var=#arguments#/> cfdump здесь провоцирует NPE --->
<cfreturn valueList(local.qAvailableResourceRealm.resource_realm)/>
</cffunction>
<cffunction name="generateValueList" returntype="string">
<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)/>
</cfcase>
<cfcase value="getSampleList"><!--- for debug --->
<cfreturn "dummy1,dummy2"/>
</cfcase>
<cfdefaultcase>
<cfreturn "function not found"/>
</cfdefaultcase>
</cfswitch>
</cffunction>
</cfcomponent>