517 lines
29 KiB
Plaintext
517 lines
29 KiB
Plaintext
<cfcomponent extends="taffy.core.resource" taffy:uri="/instances/{instanceUid}">
|
||
|
||
<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"/>
|
||
<cftry>
|
||
<cfset this.helper.validateField(arguments, "instanceUid", "guid")/>
|
||
<cfcatch type="invalidParamValue">
|
||
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
|
||
</cfcatch>
|
||
</cftry>
|
||
|
||
<cfset var local={}/>
|
||
|
||
<cfquery name="local.qInstance" result="local.result">
|
||
select
|
||
<m:field_set titleMapOut="local.titleMap" lengthOut="local.fieldCount">
|
||
<m:field>e.instance_uid::text as instance_uid</m:field>
|
||
<m:field>e.display_name</m:field>
|
||
<m:field>e.service_id</m:field>
|
||
<m:field>e.descr</m:field>
|
||
<m:field>e.specification_item_id</m:field>
|
||
<m:field formatter=#request.castToBool#>e.is_auxiliary</m:field>
|
||
<m:field>to_char(e.dt_created, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as instance_config_dt_created</m:field><!--- to_json(e.dt_created)##>>'{}' --->
|
||
<m:field>to_char(e.dt_updated, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as instance_config_dt_updated</m:field>
|
||
<m:field>d.contract_id</m:field>
|
||
<m:field>i.specification_id</m:field>
|
||
<m:field>s.specification</m:field>
|
||
<m:field>i.quantity</m:field>
|
||
<m:field>i.price</m:field><!--- *** не цена, а скидка (Считая ссылку на базовый тариф атрибутом сервиса) --->
|
||
<m:field>v.svc</m:field>
|
||
<m:field>v.code</m:field>
|
||
<m:field>v.man
|
||
|
||
</m:field>
|
||
<m:field>e.updater_id</m:field>
|
||
<m:field>u.login as updater_login</m:field>
|
||
<m:field>u.shortname as updater_shortname</m:field>
|
||
<m:field>cast(st.instance_data->>'params' as json)->>'resourceRealm' as resource_realm</m:field>
|
||
<m:field formatter=#request.castToBool#>coalesce((io.dt_start IS NOT NULL AND io.dt_finish IS NULL AND io.submit_result='201'),false) as operation_is_in_progress</m:field>
|
||
<m:field formatter=#request.castToBool#>coalesce((io.dt_start IS NULL AND io.submit_result='201'),false) as operation_is_pending</m:field>
|
||
<m:field>case
|
||
when io.operation IN ('delete', 'suspend') AND io.is_successful then 0 /*null*/
|
||
when io.is_successful then extract('epoch' from CURRENT_TIMESTAMP - coalesce(io.dt_finish,CURRENT_TIMESTAMP))
|
||
else 0 end
|
||
as uptime</m:field>
|
||
<m:field>(case
|
||
when st.instance_uid IS NULL then 'not created'
|
||
when st.is_deleted = 'true' then 'deleted'
|
||
when st.is_suspended = 'true' then 'suspended'
|
||
/*when coalesce(st.is_deleted,'false') = 'false' AND coalesce(st.is_suspended, 'false') = 'false' then 'running'*/
|
||
when coalesce(st.is_deleted,'false') = 'false' AND coalesce(st.is_suspended, 'false') = 'false' then 'running'
|
||
when io.instance_uid IS NULL then 'not configured'
|
||
else null end
|
||
) as explained_status
|
||
</m:field>
|
||
<m:field>(select count(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 IN (
|
||
select contract_id
|
||
from contract d
|
||
where d.contragent_id=k.contragent_id AND NOT d.is_closed
|
||
) OR a.contract_id=0) /*0 means access to any contract*/
|
||
AND a.is_enabled)
|
||
where r.resource_realm_type_id=v.resource_realm_type_id) as resource_realm_cnt
|
||
</m:field>
|
||
<!--- <m:field>st.version</m:field> --->
|
||
</m:field_set>
|
||
from instance e
|
||
left outer join specification_item i on (e.specification_item_id=i.specification_item_id)
|
||
left outer join specification s on (i.specification_id=s.specification_id)
|
||
left outer join contract d on (s.contract_id=d.contract_id)
|
||
left outer join contragent k on (d.contragent_id=k.contragent_id)
|
||
left outer join svc v on (e.service_id=v.svc_id)
|
||
left outer join usr u on (e.updater_id=u.usr_id)
|
||
left outer join (select ist.instance_state_uid, ist.instance_uid, ist.version, ist.dt_state, ist.is_test
|
||
,(ist.instance_data->>'isSuspended') as is_suspended
|
||
,(ist.instance_data->>'isDeleted') as is_deleted
|
||
,ist.instance_data
|
||
from instance_state ist join (select instance_uid, max(version) as version from instance_state group by 1) lastv
|
||
on (ist.instance_uid=lastv.instance_uid AND ist.version=lastv.version) ) st
|
||
on (e.instance_uid=st.instance_uid)
|
||
left outer join (select o.instance_operation_uid, o.instance_uid, o.operation, o.dt_submit, o.submit_result, o.dt_start, o.dt_finish, o.is_successful
|
||
from instance_operation o join (select instance_uid, max(dt_submit) as dt_submit from instance_operation group by 1) lastv
|
||
on (o.instance_uid=lastv.instance_uid AND o.dt_submit=lastv.dt_submit) ) io
|
||
on (e.instance_uid=io.instance_uid)
|
||
where e.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceUid#" null=#!isValid('guid',arguments.instanceUid)#/>
|
||
AND s.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/><!--- access protection --->
|
||
</cfquery> <!--- *** правильнее при попытке доступа к чужому инстансу (НСД) выбрасывать 403, а тут будет 404, но так тоже делают, например, в gitea --->
|
||
|
||
<cfif local.qInstance.recordCount EQ 0>
|
||
<cfreturn representationOf("Instance not found or no permission to view").withStatus(404)/>
|
||
</cfif>
|
||
|
||
<!--- instanceData?.suspended
|
||
instanceData?.out?.monitoring?.allDashboards
|
||
instanceData?.params
|
||
instanceData?.out --->
|
||
|
||
<cfquery name="local.qCurrentState" result="local.result">
|
||
select
|
||
<m:field_set titleMapOut="local.currentStateTitleMap" lengthOut="local.fieldCount">
|
||
<m:field>st.instance_state_uid::text as instance_state_uid</m:field>
|
||
<m:field>st.version</m:field>
|
||
<m:field>st.creator_id</m:field>
|
||
<m:field>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>st.instance_operation_uid::text as instance_operation_uid</m:field>
|
||
<!--- <m:field formatter=#function(x){return (deserializeJson(x))}#>st.instance_data::text as instance_data</m:field> --->
|
||
<m:field formatter=#function(x){return (deserializeJson(x))}#>st.instance_data->>'out' as out</m:field>
|
||
<m:field formatter=#function(x){return (deserializeJson(x))}#>st.instance_data->>'params' as params</m:field>
|
||
<m:field formatter=#function(x){return (deserializeJson(x))}#>st.instance_data->>'vault' as vault</m:field>
|
||
<m:field formatter=#function(x){return (x GT 0)}#>(st.instance_data->>'isDeleted')::boolean as is_deleted</m:field>
|
||
<m:field formatter=#function(x){return (x GT 0)}#>(st.instance_data->>'isSuspended')::boolean as is_suspended</m:field>
|
||
</m:field_set>
|
||
from instance_state st
|
||
where st.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#local.qInstance.instance_uid#" null=#!isValid('guid',local.qInstance.instance_uid)#/>
|
||
order by st.version desc
|
||
limit 1
|
||
</cfquery><!--- берем local.qInstance.instance_uid ради изоляции (access protection) --->
|
||
|
||
|
||
<cfset local.isCreated = (local.qCurrentState.recordCount GT 0)/>
|
||
<cfset local.isDeleted = (local.qCurrentState.is_deleted GT 0)/>
|
||
|
||
<!--- <cfdump var=#local.qInstance#/><cfabort/> --->
|
||
|
||
<!--- операция, создавшая текущее состояние --->
|
||
<!--- *** странноватый селект --->
|
||
<cfquery name="local.qOperation" result="local.result">
|
||
select
|
||
<m:field_set titleMapOut="local.operationTitleMap" lengthOut="local.fieldCount">
|
||
<m:field>o.instance_operation_uid::text as instance_operation_uid</m:field>
|
||
<m:field>status.instance_state_uid::text as instance_state_uid</m:field>
|
||
<m:field>status.version as state_version</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>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>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>extract('epoch' from coalesce(o.dt_finish,CURRENT_TIMESTAMP)- o.dt_start) as duration</m:field>
|
||
<m:field>round(extract('epoch' from CURRENT_TIMESTAMP - coalesce(o.dt_finish,CURRENT_TIMESTAMP)),1) as seconds_passed</m:field>
|
||
<m:field formatter=#request.castToBool#>o.is_successful</m:field>
|
||
<m:field title="dt_created">to_char(o.dt_created, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as dt_created</m:field>
|
||
<m:field>o.error_log</m:field>
|
||
<m:field>u.login as updater_login</m:field>
|
||
<m:field>u.shortname as updater_shortname</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
|
||
left outer join usr u on (o.updater_id=u.usr_id)
|
||
left outer join resource_realm r on o.resource_realm_id=r.resource_realm_id
|
||
left outer join (select instance_operation_uid, max(version) as version from instance_state
|
||
group by instance_operation_uid) sts on (o.instance_operation_uid=sts.instance_operation_uid)
|
||
left outer join instance_state status on (sts.instance_operation_uid=status.instance_operation_uid AND sts.version=status.version)
|
||
where o.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#local.qInstance.instance_uid#" null=#!isValid('guid',local.qInstance.instance_uid)#/>
|
||
--order by status.version desc
|
||
order by o.dt_created desc
|
||
</cfquery>
|
||
<!--- *** А тут у нас не получится, что только операции с состояниями? Или в неправильном порядке? --->
|
||
<!--- ?Добавить параметры к операции --->
|
||
<!--- Разобраться в отличии текущей от последней. Может, нужна только одна? --->
|
||
|
||
<!--- <d:field title="Операция">(select operation from instance_state st join instance_operation io on (st.instance_operation_uid=io.instance_operation_uid) where st.instance_uid=e.instance_uid order by version desc limit 1) as operation</d:field>
|
||
<!--- текущая операция. Она еще не создала стейта и не завершена --->
|
||
<d:field title="Текущая операция">(select io.operation from instance_operation io where io.instance_uid=e.instance_uid order by dt_submit desc limit 1) as current_operation</d:field> --->
|
||
|
||
<!--- *** Отработать блокировку --->
|
||
<cfquery name="local.qAvailableOperation" result="local.result">
|
||
select
|
||
<m:field_set titleMapOut="local.availableOperationTitleMap" lengthOut="local.fieldCount">
|
||
<m:field>so.svc_operation_id</m:field>
|
||
<m:field>so.operation</m:field>
|
||
<m:field>
|
||
(select instance_operation_uid::text
|
||
from instance_operation io
|
||
where io.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#local.qInstance.instance_uid#" null=#!isValid('guid',local.qInstance.instance_uid)#/>
|
||
AND io.operation=so.operation AND io.dt_submit IS NULL
|
||
order by io.dt_created desc
|
||
limit 1
|
||
)as instance_operation_uid
|
||
</m:field>
|
||
</m:field_set>
|
||
from svc_operation so
|
||
where so.svc_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#local.qInstance.service_id#" null=#!isValid('integer',local.qInstance.service_id)#/>
|
||
<cfif local.isCreated>
|
||
AND NOT so.operation='create'
|
||
<cfelse>
|
||
AND so.operation='create'
|
||
</cfif>
|
||
<cfif local.isDeleted>
|
||
AND 1=0
|
||
</cfif>
|
||
order by so.svc_operation_id
|
||
</cfquery>
|
||
|
||
<!--- Проблема зависимостей. Чтобы их увидеть, нам нужно состояние, а его нет в реляционном виде.
|
||
Значит, придется парсить стейт
|
||
но чтобы получить все сервисы, которые зависят от данного, придется им отпарсить все стейты, что нереально
|
||
Значит, придется заняться нормализаций стейта (приведением в реляционный вид) - впрочем, ничего сильно сложного в этом нет
|
||
А есть смысл делать это в одну строну? наверно, есть - чтобы не забираться в операцию
|
||
--->
|
||
|
||
|
||
|
||
|
||
<!--- *** здесь уместна параноидальная проверка прав --->
|
||
<cfquery name="local.qDependency">
|
||
select
|
||
<m:field_set titleMapOut="local.dependencyTitleMap" lengthOut="local.fieldCount">
|
||
<m:field>p.param</m:field>
|
||
<m:field>sop.descr</m:field>
|
||
<m:field>s.svc_id</m:field>
|
||
<m:field>s.svc</m:field>
|
||
<m:field>s.code</m:field>
|
||
<m:field>sop.label</m:field>
|
||
<m:field>p.param_value as uid</m:field>
|
||
<m:field>r.display_name</m:field>
|
||
<m:field>r.is_auxiliary</m:field>
|
||
<m:field>c.contract_id</m:field>
|
||
<m:field>c.contract</m:field>
|
||
<m:field>to_char(c.dt_contract, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as dt_contract</m:field>
|
||
<m:field>k.external_code</m:field>
|
||
</m:field_set>
|
||
from instance_cfs_param p
|
||
left outer join instance_operation_cfs_param iop on (p.instance_operation_cfs_param_uid=iop.instance_operation_cfs_param_uid)
|
||
left outer join instance_operation o on (iop.instance_operation_uid=o.instance_operation_uid)
|
||
left outer join instance e on (o.instance_uid=e.instance_uid)
|
||
left outer join svc_operation so on (o.operation=so.operation AND e.service_id=so.svc_id)
|
||
left outer join svc_operation_cfs_param sop on (so.svc_operation_id=sop.svc_operation_id AND p.param=sop.svc_operation_cfs_param)
|
||
left outer join svc s on (sop.ref_svc_id=s.svc_id)
|
||
|
||
join instance r on (p.param_value=r.instance_uid::text)
|
||
left outer join specification_item si on (r.specification_item_id=si.specification_item_id)
|
||
left outer join specification sp on (si.specification_id=sp.specification_id)
|
||
left outer join contract c on (sp.contract_id=c.contract_id)
|
||
left outer join contragent k on (c.contragent_id=k.contragent_id)
|
||
where p.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceUid#"/>
|
||
AND sop.ref_svc_id > 0
|
||
order by sop.sort, p.param
|
||
</cfquery>
|
||
|
||
<!--- *** здесь уместна параноидальная проверка прав
|
||
потому что можно сослаться на чужой инстанс и увидеть какие-то лишние детали--->
|
||
<cfquery name="local.qDependentInstance">
|
||
select
|
||
<m:field_set titleMapOut="local.dependentInstanceTitleMap" lengthOut="local.fieldCount">
|
||
<m:field>p.param</m:field>
|
||
<m:field>sop.descr</m:field>
|
||
<m:field>s.svc_id</m:field>
|
||
<m:field>s.svc</m:field>
|
||
<m:field>s.code</m:field>
|
||
<m:field>sop.label</m:field>
|
||
<m:field>e.instance_uid::text as uid</m:field>
|
||
<m:field>e.display_name</m:field>
|
||
<m:field>e.is_auxiliary</m:field>
|
||
<m:field>c.contract_id</m:field>
|
||
<m:field>c.contract</m:field>
|
||
<m:field>to_char(c.dt_contract, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as dt_contract</m:field>
|
||
<m:field>k.external_code</m:field>
|
||
</m:field_set>
|
||
from instance_cfs_param p
|
||
left outer join instance_operation_cfs_param iop on (p.instance_operation_cfs_param_uid=iop.instance_operation_cfs_param_uid)
|
||
left outer join instance_operation o on (iop.instance_operation_uid=o.instance_operation_uid)
|
||
left outer join instance e on (o.instance_uid=e.instance_uid)
|
||
left outer join svc s on (e.service_id=s.svc_id)
|
||
left outer join svc_operation so on (o.operation=so.operation AND e.service_id=so.svc_id)
|
||
left outer join svc_operation_cfs_param sop on (so.svc_operation_id=sop.svc_operation_id AND p.param=sop.svc_operation_cfs_param)
|
||
left outer join svc r on (sop.ref_svc_id=r.svc_id)
|
||
left outer join specification_item si on (e.specification_item_id=si.specification_item_id)
|
||
left outer join specification sp on (si.specification_id=sp.specification_id)
|
||
left outer join contract c on (sp.contract_id=c.contract_id)
|
||
left outer join contragent k on (c.contragent_id=k.contragent_id)
|
||
where
|
||
p.param_value=<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.instanceUid#"/>
|
||
AND r.svc_id=(select i.service_id from instance i where i.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceUid#" null=#!isValid('guid',arguments.instanceUid)#/>)
|
||
</cfquery>
|
||
|
||
|
||
|
||
<!--- ---------------------------------------------------------------------------------- --->
|
||
<!--- маскируем секреты *** это не очень похоже на то же самое в списке, там мы просто удаляем параметры --->
|
||
<!--- *** подгоняем запрос под структуру из instance_operation_cfs_param --->
|
||
<cfquery name="local.qCfsParam" result="local.result">
|
||
select
|
||
p.svc_operation_cfs_param
|
||
,p.svc_operation_cfs_param_id
|
||
,p.label
|
||
,p.descr
|
||
,p.is_sensitive
|
||
,p.data_type
|
||
,null as data_descriptor
|
||
,(select instance_operation_cfs_param_uid 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)
|
||
where sop.svc_operation_cfs_param_id=p.svc_operation_cfs_param_id AND
|
||
io.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceUid#" null=#!isValid('guid',arguments.instanceUid)#/>)
|
||
from svc_operation_cfs_param p
|
||
join svc_operation o on (p.svc_operation_id=o.svc_operation_id)
|
||
join svc on (o.svc_id=svc.svc_id)
|
||
where svc.svc_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#qInstance.service_id#" null=#!isValid('integer',qInstance.service_id)#/>
|
||
AND o.operation='create'
|
||
</cfquery>
|
||
|
||
<!--- *** сделано не так, как в instance_operation_cfs_param (а там тоже сделано так себе) --->
|
||
<cfset local.params = structNew("linked")/>
|
||
<cftry>
|
||
<cfset local.params=deserializeJson(local.qCurrentState.params)/>
|
||
<cfloop query="local.qCfsParam">
|
||
<cfset var paramName = local.qCfsParam.svc_operation_cfs_param/>
|
||
<cfif structKeyExists(local.params, paramName)>
|
||
<!--- маскируем секреты --->
|
||
<cfif local.qCfsParam.is_sensitive>
|
||
<cfset local.params[paramName]="********"/>
|
||
<cfelseif local.qCfsParam.data_type EQ "map" OR local.qCfsParam.data_type EQ "map-fixed" OR local.qCfsParam.data_type EQ "array-map-fixed">
|
||
<!--- Не разбираем вариант "sensitive map" --->
|
||
<!--- <cfset processMap(local.qCfsParam)/> ---><!--- query passed by reference --->
|
||
<!--- маскируем секреты в map --->
|
||
<!--- *** сделано ненадежно, с расчетом на структуру qCfsParam (ради этого ее пришлось дополнить) --->
|
||
<!--- что характерно, мы передаем запрос (с фокусом, установленным на текущую строку) по ссылке и прямо там ее патчим --->
|
||
<cfset CreateObject("component", "instance_operation_cfs_param").processMap(local.qCfsParam)/>
|
||
</cfif>
|
||
</cfif>
|
||
</cfloop>
|
||
|
||
<!--- грубо и цинично патчим запрос --->
|
||
<cfset local.qCurrentState.params = serializeJson(local.params)/>
|
||
<cfcatch type="ANY"><!--- *** <cfrethrow/>---></cfcatch>
|
||
</cftry>
|
||
|
||
<!--- ---------------------------------------------------------------------------------- --->
|
||
|
||
|
||
<cfset var out=structNew("linked")/>
|
||
|
||
|
||
<cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/>
|
||
|
||
<cfset "out.instance" = this.helper.appendRecord(
|
||
structNew("linked"), "", local.titleMap, local.qInstance, this.helper.snake2camel
|
||
)/>
|
||
<!--- <cfset "out.instance.uptime"=(local.qOperation.is_successful GT 0) ? local.qOperation.seconds_passed : 0/> --->
|
||
<cfset "out.instance.isCreated"=local.isCreated/>
|
||
<cfset "out.instance.isDeleted"=local.qCurrentState.is_deleted GT 0/>
|
||
<!--- <cfset "out.instance.vaultData"=local.vaultData/> --->
|
||
|
||
<cfset "out.instance.state" = (local.qCurrentState.recordCount GT 0) ? this.helper.appendRecord(structNew("linked"), "", local.currentStateTitleMap, local.qCurrentState, this.helper.snake2camel) : {}/>
|
||
|
||
<cfset "out.instance.operations"=[]/>
|
||
<cfloop query=#local.qOperation#>
|
||
<cfset arrayAppend(out.instance.operations, this.helper.appendRecord(structNew("linked"), "", local.operationTitleMap, local.qOperation, this.helper.snake2camel))/>
|
||
</cfloop>
|
||
|
||
<cfset "out.instance.availableOperations"=[]/>
|
||
<cfloop query=#local.qAvailableOperation#>
|
||
<cfset arrayAppend(out.instance.availableOperations, this.helper.appendRecord(structNew("linked"), "", local.availableOperationTitleMap, local.qAvailableOperation, this.helper.snake2camel))/>
|
||
</cfloop>
|
||
|
||
<!--- <cfset "out.instance.dependencies0"=#dependencies#/> --->
|
||
|
||
<cfset "out.instance.dependentInstances"=[]/>
|
||
<cfloop query=#local.qDependentInstance#>
|
||
<cfset arrayAppend(out.instance.dependentInstances, this.helper.appendRecord(structNew("linked"), "", local.dependentInstanceTitleMap, local.qDependentInstance, this.helper.snake2camel))/>
|
||
</cfloop>
|
||
|
||
<cfset "out.instance.dependencies"=[]/>
|
||
<cfloop query=#local.qDependency#>
|
||
<cfset arrayAppend(out.instance.dependencies, this.helper.appendRecord(structNew("linked"), "", local.dependencyTitleMap, local.qDependency, this.helper.snake2camel))/>
|
||
</cfloop>
|
||
<!--- <cfset "out.instance.availableResourceRealms"=[]/>
|
||
<cfloop query=#local.qAvailableResourceRealm#>
|
||
<cfset arrayAppend(out.instance.availableResourceRealms, this.helper.appendRecord(structNew("linked"), "", local.realmTitleMap, local.qAvailableResourceRealm, this.helper.snake2camel))/>
|
||
</cfloop> --->
|
||
|
||
<cfset "out.runDurationMs"=getTickCount() - request.startTickCount/>
|
||
<!--- <cfdump var=#local.qCurrentState#/>
|
||
<cfdump var=#out#/>
|
||
<cfabort/> --->
|
||
<cfreturn representationOf(out) />
|
||
</cffunction>
|
||
|
||
|
||
<cffunction name="patch">
|
||
<cfargument name="instanceUid" type="string" required=true hint="type:guid"/>
|
||
<cfargument name="displayName" type="string" required=false hint="type:string"/>
|
||
<!--- <cfargument name="resourceRealmId" type="string" required=false hint="type:integer"/> --->
|
||
<cfargument name="descr" type="string" required=false default="" hint="type:varchar (no cleanup here!)"/>
|
||
|
||
<!--- ****** проверка уникальности --->
|
||
<cftry>
|
||
<cfset checkDisplayName(arguments.displayName, arguments.usrId, arguments.instanceUid)/><!--- как идея - офорить как обертку, возвращающую то же значение. Но будет соблазн еще оттримить иначе пофиксить, а это уже избыточная функция и должно усложнить название --->
|
||
<cfset this.helper.keyExistsAndValid(arguments, "instanceUid", "guid")/>
|
||
<cfquery name="local.qSave">
|
||
update instance set
|
||
dt_updated=<cfqueryparam cfsqltype="cf_sql_timestamp" value="#Now()#" />
|
||
,updater_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.usrId#" />
|
||
<cfif structKeyExists(arguments,"displayName")>
|
||
,display_name=<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.displayName#" />
|
||
</cfif>
|
||
<!--- <cfif structKeyExists(arguments,"displayName")>
|
||
,resource_realm_id=<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.resourceRealmId#" />
|
||
</cfif> --->
|
||
<cfif structKeyExists(arguments,"descr")>
|
||
,descr=<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.descr#" />
|
||
</cfif>
|
||
where instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceUid#" />;
|
||
--select @@rowcount as cnt;
|
||
</cfquery>
|
||
|
||
<!--- <cfif local.qSave.cnt EQ 0>
|
||
<cfreturn noData().withStatus(404, "Record Not Found") />
|
||
</cfif> --->
|
||
|
||
<cfcatch type="invalidParamValue">
|
||
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
|
||
</cfcatch>
|
||
</cftry>
|
||
|
||
<cfreturn noData().withStatus(204, "No Content") />
|
||
</cffunction>
|
||
|
||
<cffunction name="delete" hint="Удаление экземпляра сервиса по ключу. Допускается в статусе not configured">
|
||
<cfargument name="instanceUid" type="string" required=true hint="type:guid"/>
|
||
|
||
<cftry>
|
||
<cfset this.helper.validateField(arguments, "instanceUid", "guid")/>
|
||
|
||
<cfcatch type="invalidParamValue">
|
||
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
|
||
</cfcatch>
|
||
</cftry>
|
||
|
||
<cfset local={}/>
|
||
<cftry>
|
||
|
||
<cfquery name="local.qCheckAccess" result="local.result">
|
||
select count(*) as cnt
|
||
from instance e
|
||
join specification_item si on (e.specification_item_id=si.specification_item_id)
|
||
where e.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceUid#" null=#!isValid('guid',arguments.instanceUid)#/>
|
||
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 or does not exist",
|
||
"Instance is not accessible for the current user (possibly does not belong to the default specification)")
|
||
).withStatus(404)/>
|
||
</cfif>
|
||
|
||
<!--- халява какая-то --->
|
||
<cfquery name="local.qCheckOperation" result="local.result">
|
||
select count(*) as cnt
|
||
from instance_operation io
|
||
where io.dt_finish IS NULL AND
|
||
io.submit_result like '2%' /*201 etc*/ AND
|
||
io.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceUid#" null=#!isValid('guid',arguments.instanceUid)#/>
|
||
</cfquery>
|
||
<cfif local.qCheckOperation.cnt GT 0>
|
||
<cfreturn representationOf(this.helper.formatMessage(
|
||
"Operation already started", "Instance deletion disabled when operation is started")
|
||
).withStatus(422)/>
|
||
</cfif>
|
||
|
||
<cfquery name="local.qCheckState" result="local.result">
|
||
select count(*) as cnt
|
||
from instance_state st
|
||
where
|
||
st.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceUid#" null=#!isValid('guid',arguments.instanceUid)#/>
|
||
</cfquery>
|
||
<cfif local.qCheckState.cnt GT 0>
|
||
<cfreturn representationOf(this.helper.formatMessage(
|
||
"Instance has a state", "Instance deletion disabled when having state")
|
||
).withStatus(422)/>
|
||
</cfif>
|
||
|
||
<!--- мы не включаем проверку доступа в саму операцию удаления, а выполняем отдельно --->
|
||
<cfquery name="local.qSave">
|
||
delete from instance_state
|
||
where instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceUid#" null=#!isValid('guid',arguments.instanceUid)#/>;
|
||
delete from instance_operation
|
||
where instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceUid#" null=#!isValid('guid',arguments.instanceUid)#/>;
|
||
delete from instance
|
||
where instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceUid#" null=#!isValid('guid',arguments.instanceUid)#/>;
|
||
</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="checkDisplayName">
|
||
<cfargument name="displayName" required=true/>
|
||
<cfargument name="usrId" type="numeric" required=true/>
|
||
<cfargument name="instanceUid" type="guid" required=true/>
|
||
|
||
<cfset CreateObject("component", "instance_ls").checkDisplayName(arguments.displayName, arguments.usrId, arguments.instanceUid)/>
|
||
</cffunction>
|
||
|
||
</cfcomponent> |