20 changed files with 352 additions and 1640 deletions
+91
View File
@@ -0,0 +1,91 @@
"""
Пересобирает results/source-bundle.md и results/source-toc.md
из очищенных исходников v1/ (без taffy и без backup-каталогов).
Запуск:
python3 build_bundle.py
Что делает:
1. Обходит v1/ рекурсивно, собирает все .cfc и .cfm файлы
(исключая taffy/ и bk/)
2. Формирует results/source-bundle.md — один большой MD,
каждый файл как раздел ## filepath + код в блоке ```cfml
3. Формирует results/source-toc.md — оглавление с номерами строк
в bundle (не страниц)
Настройки:
ROOT — корневая директория исходников
SKIP — папки, которые исключаются из обхода
OUT_DIR — куда писать результирующие файлы
"""
import os
import re
from datetime import date
ROOT = 'v1'
SKIP = ['taffy', 'bk']
OUT_DIR = 'results'
BUILD_DATE = date.today().isoformat()
def collect_files(root, skip):
files = []
for dirpath, dirnames, filenames in os.walk(root):
dirnames[:] = sorted([d for d in dirnames if d not in skip])
for fname in sorted(filenames):
if fname.endswith('.cfc') or fname.endswith('.cfm'):
files.append(os.path.join(dirpath, fname))
return files
def build_bundle(files):
lines = []
lines.append(f'# Исходники svc-api-x\n')
lines.append(f'Дата сборки: {BUILD_DATE}\n')
lines.append('Прикладной слой после cleanup: v1/ без taffy и без backup-каталогов.\n')
for fpath in files:
with open(fpath, encoding='utf-8', errors='ignore') as f:
code = f.read().rstrip('\n')
lines.append(f'\n## {fpath}\n')
lines.append(f'\n```cfml\n{code}\n```\n')
return '\n'.join(lines)
def build_toc(bundle_content):
bundle_lines = bundle_content.split('\n')
toc_entries = []
for i, line in enumerate(bundle_lines, 1):
m = re.match(r'^## (.+)$', line)
if m:
toc_entries.append((m.group(1).strip(), i))
out = []
out.append(f'# Оглавление исходников svc-api-x\n')
out.append(f'Дата сборки: {BUILD_DATE}\n')
out.append('\n## Прикладной слой\n')
out.append('```text')
for rel, lineno in toc_entries:
dots = '.' * max(1, 55 - len(rel) - len(str(lineno)))
out.append(f'{rel} {dots} {lineno}')
out.append('```')
return '\n'.join(out) + '\n'
if __name__ == '__main__':
files = collect_files(ROOT, SKIP)
bundle = build_bundle(files)
bundle_path = os.path.join(OUT_DIR, 'source-bundle.md')
with open(bundle_path, 'w', encoding='utf-8') as f:
f.write(bundle)
toc = build_toc(bundle)
toc_path = os.path.join(OUT_DIR, 'source-toc.md')
with open(toc_path, 'w', encoding='utf-8') as f:
f.write(toc)
print(f'Файлов в bundle: {len(files)}')
print(f'{bundle_path} — готово')
print(f'{toc_path} — готово')
+71 -8
View File
@@ -7,9 +7,16 @@
3. Строит DOCX: 3. Строит DOCX:
- Титульная страница (название, подзаголовок, дата) - Титульная страница (название, подзаголовок, дата)
- Оглавление (поле Word TOC — пользователь жмёт правую кнопку → Обновить поле) - Оглавление (поле Word TOC — пользователь жмёт правую кнопку → Обновить поле)
- 47 разделов с кодом (заголовок файла + код моноширинным шрифтом на сером фоне) - разделы с кодом (заголовок файла + код с подсветкой синтаксиса на сером фоне)
- Номер страницы в нижнем колонтитуле - Номер страницы в нижнем колонтитуле
Подсветка синтаксиса CFML (4 цвета):
синий — CF-теги (<cfif>, <cfset>, </cffunction>, ...)
зелёный — строковые значения ("...", '...')
фиолетовый — выражения в # (#variables#, #func()#)
тёмно-голубой — SQL-ключевые слова (SELECT, FROM, WHERE, JOIN, ...)
чёрный — всё остальное
Запуск: Запуск:
/home/naeel/svc-api-x/.venv/bin/python build_docx.py /home/naeel/svc-api-x/.venv/bin/python build_docx.py
@@ -39,8 +46,8 @@ from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.oxml.ns import qn from docx.oxml.ns import qn
from docx.oxml import OxmlElement from docx.oxml import OxmlElement
BUNDLE_PATH = '/home/naeel/svc-api-x/results/source-bundle.md' # входной файл BUNDLE_PATH = 'results/source-bundle.md' # входной файл
OUTPUT_PATH = '/home/naeel/svc-api-x/results/svc-api-x.docx' # выходной файл OUTPUT_PATH = 'results/svc-api-x.docx' # выходной файл
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@@ -70,7 +77,61 @@ def parse_bundle(path):
# Вспомогательные функции # Вспомогательные функции
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
def set_font(run, name='Courier New', size=9, bold=False, color=None): # ---------------------------------------------------------------------------
# Токенизатор CFML
# ---------------------------------------------------------------------------
# Цвета подсветки (RGB)
COL_TAG = (0x1A, 0x5F, 0xB4) # синий — CF-теги
COL_STR = (0x1E, 0x7E, 0x34) # зелёный — строки
COL_VAR = (0x6F, 0x31, 0x78) # фиолетовый — #переменные#
COL_SQL = (0x0D, 0x5C, 0x73) # тёмно-голубой — SQL
COL_DEF = None # чёрный (default)
_PATTERNS = [
('tag', re.compile(
r'</cf\w+|<cf\w+|</cfscript>|<cfscript>', re.IGNORECASE)),
('var', re.compile(
r'#[^#\n]+#')),
('str', re.compile(
r'"[^"\n]*"|' + r"'[^'\n]*'")),
('sql', re.compile(
r'\b(SELECT|FROM|WHERE|JOIN|LEFT|RIGHT|INNER|OUTER|ON|AND|OR|NOT|'
r'INSERT|INTO|UPDATE|DELETE|SET|GROUP|ORDER|BY|HAVING|LIMIT|OFFSET|'
r'AS|DISTINCT|COUNT|SUM|AVG|MAX|MIN|CAST|COALESCE|CASE|WHEN|THEN|'
r'ELSE|END|IS|NULL|IN|EXISTS|UNION|ALL)\b', re.IGNORECASE)),
]
_COLOR_MAP = {'tag': COL_TAG, 'str': COL_STR, 'var': COL_VAR,
'sql': COL_SQL, None: COL_DEF}
def tokenize_cfml(line):
"""Разбивает строку кода на список (text, color) с подсветкой CFML."""
tokens = []
pos = 0
length = len(line)
while pos < length:
best_match = None
best_kind = None
best_start = length
for kind, pat in _PATTERNS:
m = pat.search(line, pos)
if m and m.start() < best_start:
best_match = m
best_kind = kind
best_start = m.start()
if best_match is None:
tokens.append((line[pos:], COL_DEF))
break
if best_start > pos:
tokens.append((line[pos:best_start], COL_DEF))
tokens.append((best_match.group(0), _COLOR_MAP[best_kind]))
pos = best_match.end()
return tokens
def set_font(run, name='Courier New', size=8, bold=False, color=None):
run.font.name = name run.font.name = name
run.font.size = Pt(size) run.font.size = Pt(size)
run.font.bold = bold run.font.bold = bold
@@ -259,11 +320,13 @@ def build(sections):
for idx, line in enumerate(lines): for idx, line in enumerate(lines):
if idx > 0: if idx > 0:
run = code_para.add_run() br_run = code_para.add_run()
br = OxmlElement('w:br') br = OxmlElement('w:br')
run._r.append(br) br_run._r.append(br)
run = code_para.add_run(line) set_font(br_run)
set_font(run, name='Courier New', size=8) for text, color in tokenize_cfml(line):
run = code_para.add_run(text)
set_font(run, color=color)
doc.save(OUTPUT_PATH) doc.save(OUTPUT_PATH)
print(f'Готово: {OUTPUT_PATH}') print(f'Готово: {OUTPUT_PATH}')
+116 -783
View File
File diff suppressed because it is too large Load Diff
+48 -61
View File
@@ -1,68 +1,55 @@
# Оглавление исходников svc-api-x # Оглавление исходников svc-api-x
Дата сборки: 2026-04-30 Дата сборки: 2026-05-19
## Прикладной слой ## Прикладной слой
```text ```text
health.cfm ........................................ 7 v1/Application.cfc .................................... 8
v1/Application.cfc ................................ 12 v1/index.cfm ........................................ 767
v1/index.cfm ...................................... 761 v1/lib/JsonSerializer.cfc ........................... 775
v1/lib/JsonSerializer.cfc .......................... 767 v1/lib/TokenGenerator.cfc .......................... 1296
v1/lib/TokenGenerator.cfc .......................... 1286 v1/lib/encodingUtils.cfc ........................... 1360
v1/lib/encodingUtils.cfc ........................... 1348 v1/lib/expression_parser.cfc ....................... 1650
v1/lib/expression_parser.cfc ....................... 1636 v1/lib/field.cfm ................................... 1811
v1/lib/field.cfm ................................... 1795 v1/lib/field_set.cfm ............................... 1878
v1/lib/field_set.cfm .............................. 1860 v1/lib/filter_build.cfm ............................ 1949
v1/lib/filter_build.cfm ........................... 1929 v1/lib/index.cfm ................................... 2018
v1/lib/index.cfm .................................. 1996 v1/lib/jwt.cfc ..................................... 2026
v1/lib/jwt.cfc .................................... 2002 v1/lib/notifier.cfc ................................ 2295
v1/lib/notifier.cfc ................................ 2269 v1/lib/order_build.cfm ............................. 2335
v1/lib/order_build.cfm ............................ 2307 v1/lib/rest_api_helper.cfc ......................... 2383
v1/lib/rest_api_helper.cfc ........................ 2353 v1/resources/available_resource_realms.cfc ......... 2848
v1/resources/available_resource_realms.cfc .......... 2816 v1/resources/bookmark.cfc .......................... 2944
v1/resources/bookmark.cfc .......................... 2910 v1/resources/bookmark_ls.cfc ....................... 3057
v1/resources/bookmark_ls.cfc ....................... 3021 v1/resources/catalog_service_ls.cfc ................ 3243
v1/resources/catalog_service_ls.cfc ................ 3205 v1/resources/catalog_service_param_ls.cfc .......... 3418
v1/resources/catalog_service_param_ls.cfc .......... 3378 v1/resources/err.cfc ............................... 3616
v1/resources/err.cfc ............................... 3574 v1/resources/instance.cfc .......................... 3633
v1/resources/instance.cfc .......................... 3589 v1/resources/instance_default.cfc .................. 4081
v1/resources/instance_default.cfc .................. 4120 v1/resources/instance_ls.cfc ....................... 4139
v1/resources/instance_ls.cfc ....................... 4176 v1/resources/instance_operation.cfc ................ 4577
v1/resources/instance_operation.cfc ............... 4725 v1/resources/instance_operation_cfs_param.cfc ...... 4880
v1/resources/instance_operation_cfs_param.cfc ...... 5026 v1/resources/instance_operation_cfs_param_ls.cfc ... 5678
v1/resources/instance_operation_cfs_param_ls.cfc ... 6004 v1/resources/instance_operation_cfs_subparam.cfc ... 6125
v1/resources/instance_operation_cfs_subparam.cfc ... 6449 v1/resources/instance_operation_cfs_subparam_ls.cfc . 6270
v1/resources/instance_operation_cfs_subparam_ls.cfc . 6626 v1/resources/instance_operation_default.cfc ........ 6338
v1/resources/instance_operation_default.cfc ........ 6712 v1/resources/instance_operation_ls.cfc ............. 6619
v1/resources/instance_operation_ls.cfc ............. 7039 v1/resources/instance_operation_run.cfc ............ 6878
v1/resources/instance_operation_run.cfc ............ 7345 v1/resources/instance_operation_validate.cfc ....... 7326
v1/resources/instance_operation_validate.cfc ....... 7791 v1/resources/notification_ls.cfc ................... 7348
v1/resources/notification_ls.cfc ................... 7820 v1/resources/param_value_list.cfc .................. 7458
v1/resources/param_value_list.cfc .................. 7928 v1/resources/resource_realm.cfc .................... 7490
v1/resources/resource_realm.cfc .................... 7958 v1/resources/resource_realm_ls.cfc ................. 7572
v1/resources/resource_realm_ls.cfc ................. 8038 v1/resources/resource_realm_type_ls.cfc ............ 7684
v1/resources/resource_realm_type_ls.cfc ............ 8148 v1/resources/svc.cfc ............................... 7777
v1/resources/svc.cfc ................................ 8239 v1/resources/svc_default.cfc ....................... 7844
v1/resources/svc_default.cfc ........................ 8322 v1/resources/svc_grouped_ls.cfc .................... 7891
v1/resources/svc_grouped_ls.cfc .................... 8367 v1/resources/svc_ls.cfc ............................ 8018
v1/resources/svc_ls.cfc ............................ 8541 v1/resources/svc_operation.cfc ..................... 8211
v1/resources/svc_operation.cfc ..................... 8770 v1/resources/svc_operation_cfs_param_compute.cfc ... 8319
v1/resources/svc_operation_cfs_param_compute.cfc ... 8891 v1/resources/svc_operation_cfs_subparam_compute.cfc . 8398
v1/resources/svc_operation_cfs_subparam_compute.cfc . 8968 v1/resources/user.cfc .............................. 8477
v1/resources/user.cfc .............................. 9045 v1/resources/vault_record.cfc ...................... 8533
v1/resources/vault_record.cfc ...................... 9140
```
## Backup-слой, исключенный из основного bundle
```text
отсутствует
```
## Исключено из bundle
```text
v1/resources/bk/* .......................... удаленные backup-сериализаторы
v1/taffy/* ................................ vendor framework, примеры и тесты
``` ```
Binary file not shown.
Binary file not shown.
+2 -87
View File
@@ -1,11 +1,8 @@
<cfcomponent extends="taffy.core.resource" taffy:uri="/instances/{instanceUid}"> <cfcomponent extends="taffy.core.resource" taffy:uri="/instances/{instanceUid}">
<cfsilent> <cfsilent>
<cfimport prefix="m" taglib="../lib"/> <cfimport prefix="m" taglib="../lib"/>
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/><!---*** странно, почему мы его видим?---><!---вынести в апп?---> <cfset this.helper=CreateObject("component","lib.rest_api_helper")/><!---*** странно, почему мы его видим?---><!---вынести в апп?--->
</cfsilent> </cfsilent>
<cffunction name="get" hint="Экземпляр сервиса"><!--- *** TODO проверка принадлежности тенанту ---> <cffunction name="get" hint="Экземпляр сервиса"><!--- *** TODO проверка принадлежности тенанту --->
<cfargument name="instanceUid" type="string" required=true hint="type:guid"/> <cfargument name="instanceUid" type="string" required=true hint="type:guid"/>
<cftry> <cftry>
@@ -14,9 +11,7 @@
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/> <cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
</cfcatch> </cfcatch>
</cftry> </cftry>
<cfset var local={}/> <cfset var local={}/>
<cfquery name="local.qInstance" result="local.result"> <cfquery name="local.qInstance" result="local.result">
select select
<m:field_set titleMapOut="local.titleMap" lengthOut="local.fieldCount"> <m:field_set titleMapOut="local.titleMap" lengthOut="local.fieldCount">
@@ -36,7 +31,6 @@
<m:field>v.svc</m:field> <m:field>v.svc</m:field>
<m:field>v.code</m:field> <m:field>v.code</m:field>
<m:field>v.man <m:field>v.man
</m:field> </m:field>
<m:field>e.updater_id</m:field> <m:field>e.updater_id</m:field>
<m:field>u.login as updater_login</m:field> <m:field>u.login as updater_login</m:field>
@@ -71,7 +65,6 @@
AND a.is_enabled) AND a.is_enabled)
where r.resource_realm_type_id=v.resource_realm_type_id) as resource_realm_cnt where r.resource_realm_type_id=v.resource_realm_type_id) as resource_realm_cnt
</m:field> </m:field>
<!--- <m:field>st.version</m:field> --->
</m:field_set> </m:field_set>
from instance e from instance e
left outer join specification_item i on (e.specification_item_id=i.specification_item_id) left outer join specification_item i on (e.specification_item_id=i.specification_item_id)
@@ -94,16 +87,13 @@
where e.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceUid#" null=#!isValid('guid',arguments.instanceUid)#/> 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 ---> AND s.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/><!--- access protection --->
</cfquery> <!--- *** правильнее при попытке доступа к чужому инстансу (НСД) выбрасывать 403, а тут будет 404, но так тоже делают, например, в gitea ---> </cfquery> <!--- *** правильнее при попытке доступа к чужому инстансу (НСД) выбрасывать 403, а тут будет 404, но так тоже делают, например, в gitea --->
<cfif local.qInstance.recordCount EQ 0> <cfif local.qInstance.recordCount EQ 0>
<cfreturn representationOf("Instance not found or no permission to view").withStatus(404)/> <cfreturn representationOf("Instance not found or no permission to view").withStatus(404)/>
</cfif> </cfif>
<!--- instanceData?.suspended <!--- instanceData?.suspended
instanceData?.out?.monitoring?.allDashboards instanceData?.out?.monitoring?.allDashboards
instanceData?.params instanceData?.params
instanceData?.out ---> instanceData?.out --->
<cfquery name="local.qCurrentState" result="local.result"> <cfquery name="local.qCurrentState" result="local.result">
select select
<m:field_set titleMapOut="local.currentStateTitleMap" lengthOut="local.fieldCount"> <m:field_set titleMapOut="local.currentStateTitleMap" lengthOut="local.fieldCount">
@@ -113,7 +103,6 @@
<m:field>to_char(st.dt_state, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as dt_state</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 formatter=#request.castToBool#>st.is_test</m:field>
<m:field>st.instance_operation_uid::text as instance_operation_uid</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->>'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->>'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 (deserializeJson(x))}#>st.instance_data->>'vault' as vault</m:field>
@@ -125,13 +114,8 @@
order by st.version desc order by st.version desc
limit 1 limit 1
</cfquery><!--- берем local.qInstance.instance_uid ради изоляции (access protection) ---> </cfquery><!--- берем local.qInstance.instance_uid ради изоляции (access protection) --->
<cfset local.isCreated = (local.qCurrentState.recordCount GT 0)/> <cfset local.isCreated = (local.qCurrentState.recordCount GT 0)/>
<cfset local.isDeleted = (local.qCurrentState.is_deleted GT 0)/> <cfset local.isDeleted = (local.qCurrentState.is_deleted GT 0)/>
<!--- <cfdump var=#local.qInstance#/><cfabort/> --->
<!--- операция, создавшая текущее состояние ---> <!--- операция, создавшая текущее состояние --->
<!--- *** странноватый селект ---> <!--- *** странноватый селект --->
<cfquery name="local.qOperation" result="local.result"> <cfquery name="local.qOperation" result="local.result">
@@ -171,11 +155,7 @@
<!--- *** А тут у нас не получится, что только операции с состояниями? Или в неправильном порядке? ---> <!--- *** А тут у нас не получится, что только операции с состояниями? Или в неправильном порядке? --->
<!--- ?Добавить параметры к операции ---> <!--- ?Добавить параметры к операции --->
<!--- Разобраться в отличии текущей от последней. Может, нужна только одна? ---> <!--- Разобраться в отличии текущей от последней. Может, нужна только одна? --->
<!--- <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> ---> <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"> <cfquery name="local.qAvailableOperation" result="local.result">
select select
@@ -204,17 +184,12 @@
</cfif> </cfif>
order by so.svc_operation_id order by so.svc_operation_id
</cfquery> </cfquery>
<!--- Проблема зависимостей. Чтобы их увидеть, нам нужно состояние, а его нет в реляционном виде. <!--- Проблема зависимостей. Чтобы их увидеть, нам нужно состояние, а его нет в реляционном виде.
Значит, придется парсить стейт Значит, придется парсить стейт
но чтобы получить все сервисы, которые зависят от данного, придется им отпарсить все стейты, что нереально но чтобы получить все сервисы, которые зависят от данного, придется им отпарсить все стейты, что нереально
Значит, придется заняться нормализаций стейта (приведением в реляционный вид) - впрочем, ничего сильно сложного в этом нет Значит, придется заняться нормализаций стейта (приведением в реляционный вид) - впрочем, ничего сильно сложного в этом нет
А есть смысл делать это в одну строну? наверно, есть - чтобы не забираться в операцию А есть смысл делать это в одну строну? наверно, есть - чтобы не забираться в операцию
---> --->
<!--- *** здесь уместна параноидальная проверка прав ---> <!--- *** здесь уместна параноидальная проверка прав --->
<cfquery name="local.qDependency"> <cfquery name="local.qDependency">
select select
@@ -240,7 +215,6 @@
left outer join svc_operation so on (o.operation=so.operation AND e.service_id=so.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_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) left outer join svc s on (sop.ref_svc_id=s.svc_id)
join instance r on (p.param_value=r.instance_uid::text) 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_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 specification sp on (si.specification_id=sp.specification_id)
@@ -250,7 +224,6 @@
AND sop.ref_svc_id > 0 AND sop.ref_svc_id > 0
order by sop.sort, p.param order by sop.sort, p.param
</cfquery> </cfquery>
<!--- *** здесь уместна параноидальная проверка прав <!--- *** здесь уместна параноидальная проверка прав
потому что можно сослаться на чужой инстанс и увидеть какие-то лишние детали---> потому что можно сослаться на чужой инстанс и увидеть какие-то лишние детали--->
<cfquery name="local.qDependentInstance"> <cfquery name="local.qDependentInstance">
@@ -289,14 +262,10 @@
where i.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceUid#" null=#!isValid('guid',arguments.instanceUid)#/> where i.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceUid#" null=#!isValid('guid',arguments.instanceUid)#/>
) )
</cfquery> </cfquery>
<!--- ---------------------------------------------------------------------------------- ---> <!--- ---------------------------------------------------------------------------------- --->
<!--- маскируем секреты *** это не очень похоже на то же самое в списке, там мы просто удаляем параметры ---> <!--- маскируем секреты *** это не очень похоже на то же самое в списке, там мы просто удаляем параметры --->
<!--- *** подгоняем запрос под структуру из instance_operation_cfs_param ---> <!--- *** подгоняем запрос под структуру из instance_operation_cfs_param --->
<!--- а мы тут упускаем, что может быть несколько операций create, как правило из-за сломавшихся. Но параметры мы берем из текущего стейта, и операцию возьмем оттуда же ---> <!--- а мы тут упускаем, что может быть несколько операций create, как правило из-за сломавшихся. Но параметры мы берем из текущего стейта, и операцию возьмем оттуда же --->
<cfquery name="local.qCfsParam" result="local.result"> <cfquery name="local.qCfsParam" result="local.result">
select select
p.svc_operation_cfs_param p.svc_operation_cfs_param
@@ -320,7 +289,6 @@
where svc.svc_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#qInstance.service_id#" null=#!isValid('integer',qInstance.service_id)#/> where svc.svc_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#qInstance.service_id#" null=#!isValid('integer',qInstance.service_id)#/>
AND o.operation='create' AND o.operation='create'
</cfquery> </cfquery>
<!--- *** сделано не так, как в instance_operation_cfs_param (а там тоже сделано так себе) ---> <!--- *** сделано не так, как в instance_operation_cfs_param (а там тоже сделано так себе) --->
<cfset local.params = structNew("linked")/> <cfset local.params = structNew("linked")/>
<cftry> <cftry>
@@ -333,7 +301,7 @@
<cfset local.params[paramName]="********"/> <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"> <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" ---> <!--- Не разбираем вариант "sensitive map" --->
<!--- <cfset processMap(local.qCfsParam)/> ---><!--- query passed by reference ---> <!--- query passed by reference --->
<!--- маскируем секреты в map ---> <!--- маскируем секреты в map --->
<!--- *** сделано ненадежно, с расчетом на структуру qCfsParam (ради этого ее пришлось дополнить) ---> <!--- *** сделано ненадежно, с расчетом на структуру qCfsParam (ради этого ее пришлось дополнить) --->
<!--- что характерно, мы передаем запрос (с фокусом, установленным на текущую строку) по ссылке и прямо там ее патчим ---> <!--- что характерно, мы передаем запрос (с фокусом, установленным на текущую строку) по ссылке и прямо там ее патчим --->
@@ -341,70 +309,42 @@
</cfif> </cfif>
</cfif> </cfif>
</cfloop> </cfloop>
<!--- грубо и цинично патчим запрос ---> <!--- грубо и цинично патчим запрос --->
<cfset local.qCurrentState.params = serializeJson(local.params)/> <cfset local.qCurrentState.params = serializeJson(local.params)/>
<cfcatch type="ANY"><!--- *** <cfrethrow/>---></cfcatch> <cfcatch type="ANY"></cfcatch>
</cftry> </cftry>
<!--- ---------------------------------------------------------------------------------- ---> <!--- ---------------------------------------------------------------------------------- --->
<cfset var out=structNew("linked")/> <cfset var out=structNew("linked")/>
<cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/> <cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/>
<cfset "out.instance" = this.helper.appendRecord( <cfset "out.instance" = this.helper.appendRecord(
structNew("linked"), "", local.titleMap, local.qInstance, this.helper.snake2camel 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.isCreated"=local.isCreated/>
<cfset "out.instance.isDeleted"=local.qCurrentState.is_deleted GT 0/> <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.state" = (local.qCurrentState.recordCount GT 0) ? this.helper.appendRecord(structNew("linked"), "", local.currentStateTitleMap, local.qCurrentState, this.helper.snake2camel) : {}/>
<cfset "out.instance.operations"=[]/> <cfset "out.instance.operations"=[]/>
<cfloop query=#local.qOperation#> <cfloop query=#local.qOperation#>
<cfset arrayAppend(out.instance.operations, this.helper.appendRecord(structNew("linked"), "", local.operationTitleMap, local.qOperation, this.helper.snake2camel))/> <cfset arrayAppend(out.instance.operations, this.helper.appendRecord(structNew("linked"), "", local.operationTitleMap, local.qOperation, this.helper.snake2camel))/>
</cfloop> </cfloop>
<cfset "out.instance.availableOperations"=[]/> <cfset "out.instance.availableOperations"=[]/>
<cfloop query=#local.qAvailableOperation#> <cfloop query=#local.qAvailableOperation#>
<cfset arrayAppend(out.instance.availableOperations, this.helper.appendRecord(structNew("linked"), "", local.availableOperationTitleMap, local.qAvailableOperation, this.helper.snake2camel))/> <cfset arrayAppend(out.instance.availableOperations, this.helper.appendRecord(structNew("linked"), "", local.availableOperationTitleMap, local.qAvailableOperation, this.helper.snake2camel))/>
</cfloop> </cfloop>
<!--- <cfset "out.instance.dependencies0"=#dependencies#/> --->
<cfset "out.instance.dependentInstances"=[]/> <cfset "out.instance.dependentInstances"=[]/>
<cfloop query=#local.qDependentInstance#> <cfloop query=#local.qDependentInstance#>
<cfset arrayAppend(out.instance.dependentInstances, this.helper.appendRecord(structNew("linked"), "", local.dependentInstanceTitleMap, local.qDependentInstance, this.helper.snake2camel))/> <cfset arrayAppend(out.instance.dependentInstances, this.helper.appendRecord(structNew("linked"), "", local.dependentInstanceTitleMap, local.qDependentInstance, this.helper.snake2camel))/>
</cfloop> </cfloop>
<cfset "out.instance.dependencies"=[]/> <cfset "out.instance.dependencies"=[]/>
<cfloop query=#local.qDependency#> <cfloop query=#local.qDependency#>
<cfset arrayAppend(out.instance.dependencies, this.helper.appendRecord(structNew("linked"), "", local.dependencyTitleMap, local.qDependency, this.helper.snake2camel))/> <cfset arrayAppend(out.instance.dependencies, this.helper.appendRecord(structNew("linked"), "", local.dependencyTitleMap, local.qDependency, this.helper.snake2camel))/>
</cfloop> </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/> <cfset "out.runDurationMs"=getTickCount() - request.startTickCount/>
<!--- <cfdump var=#local.qCurrentState#/>
<cfdump var=#out#/>
<cfabort/> --->
<cfreturn representationOf(out) /> <cfreturn representationOf(out) />
</cffunction> </cffunction>
<cffunction name="patch"> <cffunction name="patch">
<cfargument name="instanceUid" type="string" required=true hint="type:guid"/> <cfargument name="instanceUid" type="string" required=true hint="type:guid"/>
<cfargument name="displayName" type="string" required=false hint="type:string"/> <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!)"/> <cfargument name="descr" type="string" required=false default="" hint="type:varchar (no cleanup here!)"/>
<!--- ****** проверка уникальности ---> <!--- ****** проверка уникальности --->
<cftry> <cftry>
<cfset checkDisplayName(arguments.displayName, arguments.usrId, arguments.instanceUid)/><!--- как идея - офорить как обертку, возвращающую то же значение. Но будет соблазн еще оттримить иначе пофиксить, а это уже избыточная функция и должно усложнить название ---> <cfset checkDisplayName(arguments.displayName, arguments.usrId, arguments.instanceUid)/><!--- как идея - офорить как обертку, возвращающую то же значение. Но будет соблазн еще оттримить иначе пофиксить, а это уже избыточная функция и должно усложнить название --->
@@ -416,42 +356,28 @@
<cfif structKeyExists(arguments,"displayName")> <cfif structKeyExists(arguments,"displayName")>
,display_name=<cfqueryparam cfsqltype="cf_sql_varchar" value="#htmlEditFormat(arguments.displayName)#" /> ,display_name=<cfqueryparam cfsqltype="cf_sql_varchar" value="#htmlEditFormat(arguments.displayName)#" />
</cfif> </cfif>
<!--- <cfif structKeyExists(arguments,"displayName")>
,resource_realm_id=<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.resourceRealmId#" />
</cfif> --->
<cfif structKeyExists(arguments,"descr")> <cfif structKeyExists(arguments,"descr")>
,descr=<cfqueryparam cfsqltype="cf_sql_varchar" value="#htmlEditFormat(arguments.descr)#" /> ,descr=<cfqueryparam cfsqltype="cf_sql_varchar" value="#htmlEditFormat(arguments.descr)#" />
</cfif> </cfif>
where instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceUid#" />; where instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceUid#" />;
--select @@rowcount as cnt; --select @@rowcount as cnt;
</cfquery> </cfquery>
<!--- <cfif local.qSave.cnt EQ 0>
<cfreturn noData().withStatus(404, "Record Not Found") />
</cfif> --->
<cfcatch type="invalidParamValue"> <cfcatch type="invalidParamValue">
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/> <cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
</cfcatch> </cfcatch>
</cftry> </cftry>
<cfreturn noData().withStatus(204, "No Content") /> <cfreturn noData().withStatus(204, "No Content") />
</cffunction> </cffunction>
<cffunction name="delete" hint="Удаление экземпляра сервиса по ключу. Допускается в статусе not configured"> <cffunction name="delete" hint="Удаление экземпляра сервиса по ключу. Допускается в статусе not configured">
<cfargument name="instanceUid" type="string" required=true hint="type:guid"/> <cfargument name="instanceUid" type="string" required=true hint="type:guid"/>
<cftry> <cftry>
<cfset this.helper.validateField(arguments, "instanceUid", "guid")/> <cfset this.helper.validateField(arguments, "instanceUid", "guid")/>
<cfcatch type="invalidParamValue"> <cfcatch type="invalidParamValue">
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/> <cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
</cfcatch> </cfcatch>
</cftry> </cftry>
<cfset local={}/> <cfset local={}/>
<cftry> <cftry>
<cfquery name="local.qCheckAccess" result="local.result"> <cfquery name="local.qCheckAccess" result="local.result">
select count(*) as cnt select count(*) as cnt
from instance e from instance e
@@ -465,7 +391,6 @@
"Instance is not accessible for the current user (possibly does not belong to the default specification)") "Instance is not accessible for the current user (possibly does not belong to the default specification)")
).withStatus(404)/> ).withStatus(404)/>
</cfif> </cfif>
<!--- халява какая-то ---> <!--- халява какая-то --->
<cfquery name="local.qCheckOperation" result="local.result"> <cfquery name="local.qCheckOperation" result="local.result">
select count(*) as cnt select count(*) as cnt
@@ -479,7 +404,6 @@
"Operation already started", "Instance deletion disabled when operation is started") "Operation already started", "Instance deletion disabled when operation is started")
).withStatus(422)/> ).withStatus(422)/>
</cfif> </cfif>
<cfquery name="local.qCheckState" result="local.result"> <cfquery name="local.qCheckState" result="local.result">
select count(*) as cnt select count(*) as cnt
from instance_state st from instance_state st
@@ -491,7 +415,6 @@
"Instance has a state", "Instance deletion disabled when having state") "Instance has a state", "Instance deletion disabled when having state")
).withStatus(422)/> ).withStatus(422)/>
</cfif> </cfif>
<!--- мы не включаем проверку доступа в саму операцию удаления, а выполняем отдельно ---> <!--- мы не включаем проверку доступа в саму операцию удаления, а выполняем отдельно --->
<cfquery name="local.qSave"> <cfquery name="local.qSave">
delete from instance_state delete from instance_state
@@ -501,26 +424,18 @@
delete from instance delete from instance
where instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceUid#" null=#!isValid('guid',arguments.instanceUid)#/>; where instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceUid#" null=#!isValid('guid',arguments.instanceUid)#/>;
</cfquery> </cfquery>
<cfcatch type="any"> <cfcatch type="any">
<cfreturn representationOf(this.helper.formatException(cfcatch, "Internal Error")).withStatus(500)/><!--- это не нужно показывать в продуктиве ---> <cfreturn representationOf(this.helper.formatException(cfcatch, "Internal Error")).withStatus(500)/><!--- это не нужно показывать в продуктиве --->
</cfcatch> </cfcatch>
</cftry> </cftry>
<cfreturn noData().withStatus(204, "No Content") /> <cfreturn noData().withStatus(204, "No Content") />
</cffunction><!--- delete ---> </cffunction><!--- delete --->
<!--- неудобно бегать из одного компонента в соседний при том, что разделение ответственности между ними получается довольно странное <!--- неудобно бегать из одного компонента в соседний при том, что разделение ответственности между ними получается довольно странное
Решил, что логичнее повесить проверки уникальности и генерацию дефолтов на коллекцию, тем более и связей так меньше ---> Решил, что логичнее повесить проверки уникальности и генерацию дефолтов на коллекцию, тем более и связей так меньше --->
<cffunction name="checkDisplayName"> <cffunction name="checkDisplayName">
<cfargument name="displayName" required=true/> <cfargument name="displayName" required=true/>
<cfargument name="usrId" type="numeric" required=true/> <cfargument name="usrId" type="numeric" required=true/>
<cfargument name="instanceUid" type="guid" required=true/> <cfargument name="instanceUid" type="guid" required=true/>
<cfset CreateObject("component", "instance_ls").checkDisplayName(arguments.displayName, arguments.usrId, arguments.instanceUid)/> <cfset CreateObject("component", "instance_ls").checkDisplayName(arguments.displayName, arguments.usrId, arguments.instanceUid)/>
</cffunction> </cffunction>
</cfcomponent> </cfcomponent>
+3 -116
View File
@@ -1,10 +1,8 @@
<cfcomponent extends="taffy.core.resource" taffy:uri="/instances"> <cfcomponent extends="taffy.core.resource" taffy:uri="/instances">
<cfsilent> <cfsilent>
<cfimport prefix="m" taglib="../lib"/> <cfimport prefix="m" taglib="../lib"/>
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/><!---*** странно, почему мы его видим?---><!---вынести в апп?---> <cfset this.helper=CreateObject("component","lib.rest_api_helper")/><!---*** странно, почему мы его видим?---><!---вынести в апп?--->
</cfsilent> </cfsilent>
<!---спецификация полей, пригодных для фильтрации (?и сортировки)---> <!---спецификация полей, пригодных для фильтрации (?и сортировки)--->
<cfset this.fieldsSpec={ <cfset this.fieldsSpec={
"instance_uid"={prefix="inr", type="guid"}, "instance_uid"={prefix="inr", type="guid"},
@@ -48,8 +46,6 @@
"st_instance_uid"={prefix="inr", type="integer"} ---> "st_instance_uid"={prefix="inr", type="integer"} --->
} }
/> />
<cffunction name="get" hint="Список экземпляров сервисов, принадлежащих данному клиенту"> <cffunction name="get" hint="Список экземпляров сервисов, принадлежащих данному клиенту">
<cfargument name="pageSize" type="string" hint="type:integer" required=false default="100"/> <cfargument name="pageSize" type="string" hint="type:integer" required=false default="100"/>
<cfargument name="page" type="string" hint="type:integer" required=false default="1"/> <cfargument name="page" type="string" hint="type:integer" required=false default="1"/>
@@ -57,21 +53,17 @@
<cfargument name="fields" type="string" hint="type:string, description:comma-separated list of fields to limit output to, empty string or omitted for default field set" required=false default=""/> <cfargument name="fields" type="string" hint="type:string, description:comma-separated list of fields to limit output to, empty string or omitted for default field set" required=false default=""/>
<cfargument name="search" type="string" hint="type:string, free search (black box)" required=false default=""/> <cfargument name="search" type="string" hint="type:string, free search (black box)" required=false default=""/>
<!---сюда можно воткнуть спецификацию полей для сортировки и фильтрации, но только ручками, идея компактного кода еще более отдаляется---> <!---сюда можно воткнуть спецификацию полей для сортировки и фильтрации, но только ручками, идея компактного кода еще более отдаляется--->
<!---parse and validate request parameters---> <!---parse and validate request parameters--->
<cfset local={}/> <cfset local={}/>
<cftry> <cftry>
<cfset this.helper.validateField(arguments, "pageSize", "integer")/> <cfset this.helper.validateField(arguments, "pageSize", "integer")/>
<cfset this.helper.validateField(arguments, "page", "integer")/> <cfset this.helper.validateField(arguments, "page", "integer")/>
<!---мы мирно игнорируем поля, отсутствующие в спецификации, что позволяет не делать исключения для orderBy и т.п.---> <!---мы мирно игнорируем поля, отсутствующие в спецификации, что позволяет не делать исключения для orderBy и т.п.--->
<cfset var filter=this.helper.parseFilterParams(this.fieldsSpec)/> <cfset var filter=this.helper.parseFilterParams(this.fieldsSpec)/>
<cfset var order=this.helper.parseOrderBy(this.fieldsSpec, arguments.orderBy)/> <cfset var order=this.helper.parseOrderBy(this.fieldsSpec, arguments.orderBy)/>
<cfset local.fieldsToOutput=""/> <cfset local.fieldsToOutput=""/>
<!--- <cfif listLen(arguments.fields)> ---><!--- *** если идти от arguments.fields, будет лаконичнее ---> <!--- *** если идти от arguments.fields, будет лаконичнее --->
<cfloop collection=#this.fieldsSpec# item="fld"> <cfloop collection=#this.fieldsSpec# item="fld">
<!--- <cfoutput>#this.helper.snake2camel(trim(fld))#</cfoutput> --->
<!--- *** в данном случае мы некорректно ограничиваем состав выводимых полей <!--- *** в данном случае мы некорректно ограничиваем состав выводимых полей
полями, перечисленными в fieldSpec ---> полями, перечисленными в fieldSpec --->
<cfif listFind(arguments.fields, this.helper.snake2camel(trim(fld))) <cfif listFind(arguments.fields, this.helper.snake2camel(trim(fld)))
@@ -81,13 +73,10 @@
</cfif> </cfif>
</cfloop> </cfloop>
<!--- </cfif> ---> <!--- </cfif> --->
<cfset local.fieldsToQueryFor = local.fieldsToOutput/> <cfset local.fieldsToQueryFor = local.fieldsToOutput/>
<cfset local.fieldsShortList=""/> <cfset local.fieldsShortList=""/>
<!--- теперь добавим в перечень полей, которые нужно оставить, поля для фильтрации и сортировки ---> <!--- теперь добавим в перечень полей, которые нужно оставить, поля для фильтрации и сортировки --->
<cfloop array=#filter# index="fltr"> <cfloop array=#filter# index="fltr">
<!--- <cfset var fltr = structFind(filter,item)/> --->
<cfif listLen(fltr.field,".") EQ 2> <cfif listLen(fltr.field,".") EQ 2>
<cfset var fld = listGetAt(fltr.field,2,".")/> <cfset var fld = listGetAt(fltr.field,2,".")/>
<cfelseif listLen(fltr.field,".") EQ 1> <cfelseif listLen(fltr.field,".") EQ 1>
@@ -120,12 +109,10 @@
<cfset local.fieldsShortList=listAppend(local.fieldsShortList,fld)/> <cfset local.fieldsShortList=listAppend(local.fieldsShortList,fld)/>
</cfif> </cfif>
</cfloop> </cfloop>
<cfcatch type="invalidParamValue"> <cfcatch type="invalidParamValue">
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/> <cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
</cfcatch> </cfcatch>
</cftry> </cftry>
<cftry><!--- *** времянка, пока глотается ошибка 500 ---> <cftry><!--- *** времянка, пока глотается ошибка 500 --->
<!--- Такая бодяга. Кастомные сериализаторы не умеют вложенных структур (поразительно, или я не нашел как). <!--- Такая бодяга. Кастомные сериализаторы не умеют вложенных структур (поразительно, или я не нашел как).
Стандартный сериализатор не умеет выводить дату в ISO 8601. Стандартный сериализатор не умеет выводить дату в ISO 8601.
@@ -133,7 +120,6 @@
Также на стороне БД приходится конвертировать GUID, потому что драйвер pg jdbc его представляет как структуру из 2 чисел. Также на стороне БД приходится конвертировать GUID, потому что драйвер pg jdbc его представляет как структуру из 2 чисел.
Еще jsonb как-то странно сериализуется, в 3 поля, вместо одного Value (решается преобразованием ::text) Еще jsonb как-то странно сериализуется, в 3 поля, вместо одного Value (решается преобразованием ::text)
---> --->
<m:field_set titleMapOut="local.titleMap" <m:field_set titleMapOut="local.titleMap"
lengthOut="local.fieldCount" lengthOut="local.fieldCount"
nameListOut="local.definedRecordFields" nameListOut="local.definedRecordFields"
@@ -154,29 +140,24 @@
<m:field>v.svc</m:field> <m:field>v.svc</m:field>
<m:field>v.code</m:field> <m:field>v.code</m:field>
<m:field>v.resource_realm_type_id</m:field> <m:field>v.resource_realm_type_id</m:field>
<!--- <m:field>p.param_value as resource_realm</m:field> --->
<m:field>e.updater_id</m:field> <m:field>e.updater_id</m:field>
<m:field>u.login as updater_login</m:field> <m:field>u.login as updater_login</m:field>
<m:field>u.shortname as updater_shortname</m:field> <m:field>u.shortname as updater_shortname</m:field>
<m:field>io.operation as last_operation</m:field> <m:field>io.operation as last_operation</m:field>
<m:field>io.instance_operation_uid::text as last_operation_uid</m:field> <m:field>io.instance_operation_uid::text as last_operation_uid</m:field>
<m:field>io.submit_result as submit_result</m:field> <m:field>io.submit_result as submit_result</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 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 formatter=#request.castToBool#>coalesce((io.dt_start IS NULL AND io.submit_result='201'),false) as operation_is_pending</m:field>
<m:field>to_char(io.dt_start, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as operation_dt_start</m:field> <m:field>to_char(io.dt_start, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as operation_dt_start</m:field>
<m:field>to_char(io.dt_finish, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as operation_dt_finish</m:field> <m:field>to_char(io.dt_finish, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as operation_dt_finish</m:field>
<m:field>round(extract('epoch' from coalesce(io.dt_finish,CURRENT_TIMESTAMP)- io.dt_start),1) as duration</m:field> <m:field>round(extract('epoch' from coalesce(io.dt_finish,CURRENT_TIMESTAMP)- io.dt_start),1) as duration</m:field>
<m:field>case <m:field>case
when io.operation IN ('delete', 'suspend') AND io.is_successful then 0 /*null*/ 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)) when io.is_successful then extract('epoch' from CURRENT_TIMESTAMP - coalesce(io.dt_finish,CURRENT_TIMESTAMP))
else 0 end else 0 end
as uptime</m:field> as uptime</m:field>
<m:field>to_char(io.dt_finish, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as dt_deploy</m:field> <m:field>to_char(io.dt_finish, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as dt_deploy</m:field>
<!--- <m:field formatter=#function(x){return (deserializeJson(x))}#>st.instance_data::text as instance_data</m:field> ---><!--- *** операция выглядит очень накладно, но можно это поле в дельнейшем не выводить ---> <!--- *** операция выглядит очень накладно, но можно это поле в дельнейшем не выводить --->
<m:field>st.instance_state_uid::text as instance_state_uid</m:field> <m:field>st.instance_state_uid::text as instance_state_uid</m:field>
<m:field formatter=#request.castToBool#>st.is_test as is_test</m:field> <m:field formatter=#request.castToBool#>st.is_test as is_test</m:field>
<m:field formatter=#request.castToBool#>coalesce(st.instance_data->>'isDeleted','false') as is_deleted</m:field><!--- attention it is not bool in state ---> <m:field formatter=#request.castToBool#>coalesce(st.instance_data->>'isDeleted','false') as is_deleted</m:field><!--- attention it is not bool in state --->
@@ -185,8 +166,6 @@
<m:field>st.instance_data->'out'->'monitoring'->>'resourceMetrics' as monitoring_url</m:field> <m:field>st.instance_data->'out'->'monitoring'->>'resourceMetrics' as monitoring_url</m:field>
<m:field>st.instance_data->'params'->>'resourceRealm' as resource_realm</m:field> <m:field>st.instance_data->'params'->>'resourceRealm' as resource_realm</m:field>
<m:field>to_char(st.dt_state, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as dt_state</m:field> <m:field>to_char(st.dt_state, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as dt_state</m:field>
<!--- <m:field>io.instance_uid::text as io_instance_uid</m:field>
<m:field>st.instance_uid::text as st_instance_uid</m:field> --->
<m:field>(case <m:field>(case
when st.instance_uid IS NULL then 'not created' when st.instance_uid IS NULL then 'not created'
when job_is_pending = 'true' then 'pending' when job_is_pending = 'true' then 'pending'
@@ -198,8 +177,6 @@
) as explained_status</m:field> ) as explained_status</m:field>
<m:field>st.version</m:field> <m:field>st.version</m:field>
</m:field_set> </m:field_set>
<cfquery name="local.qCnt" result="local.result"> <cfquery name="local.qCnt" result="local.result">
select count(*) as cnt select count(*) as cnt
from ( from (
@@ -242,10 +219,6 @@
) inr ) inr
where 1=1 <m:filter_build filter=#filter#/> where 1=1 <m:filter_build filter=#filter#/>
</cfquery> </cfquery>
<!--- <cfdump var=#filter#/><cfabort/> --->
<cfquery name="local.qRead" result="local.result"> <cfquery name="local.qRead" result="local.result">
select select
<cfif listLen(local.fieldsToOutput)>#local.fieldsToOutput#<cfelse>*</cfif> <cfif listLen(local.fieldsToOutput)>#local.fieldsToOutput#<cfelse>*</cfif>
@@ -273,23 +246,19 @@
on (e.instance_uid=io.instance_uid) on (e.instance_uid=io.instance_uid)
<!--- left outer join instance_cfs_param p on (e.instance_uid=p.instance_uid AND p.param='resourceRealm') ---> <!--- left outer join instance_cfs_param p on (e.instance_uid=p.instance_uid AND p.param='resourceRealm') --->
where s.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/><!--- *** make project entity ---> where s.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/><!--- *** make project entity --->
<!--- u.usr_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.usrId#/> --->
<cfif len(arguments.search)> <cfif len(arguments.search)>
AND ( AND (
(e.display_name) ilike (<cfqueryparam cfsqltype="cf_sql_varchar" value='%#arguments.search#%'/>) (e.display_name) ilike (<cfqueryparam cfsqltype="cf_sql_varchar" value='%#arguments.search#%'/>)
OR ((coalesce(v.svc,'') ||' '|| coalesce(v.svc_short,'') ||' '|| coalesce(v.synonyms,''))) ilike (<cfqueryparam cfsqltype="cf_sql_varchar" value='%#arguments.search#%'/>) OR ((coalesce(v.svc,'') ||' '|| coalesce(v.svc_short,'') ||' '|| coalesce(v.synonyms,''))) ilike (<cfqueryparam cfsqltype="cf_sql_varchar" value='%#arguments.search#%'/>)
) )
</cfif> </cfif>
) inr ) inr
where 1=1 <m:filter_build filter=#filter#/> where 1=1 <m:filter_build filter=#filter#/>
<!--- order by <m:order_build sortCollection=#this.helper.parseNumericOrder(local.titleMap, arguments.orderBy)# fieldCount=0/> ---><!--- из-за нефиксированного числа колонок труднее становится использовать цифровую нотацию ---> <!--- из-за нефиксированного числа колонок труднее становится использовать цифровую нотацию --->
order by <m:order_build sortCollection=#order# fieldCount=0 defaultOrder="1 desc"/><!---no sort length limit---> order by <m:order_build sortCollection=#order# fieldCount=0 defaultOrder="1 desc"/><!---no sort length limit--->
limit #arguments.pageSize# limit #arguments.pageSize#
offset #arguments.pageSize*(arguments.page-1)# offset #arguments.pageSize*(arguments.page-1)#
</cfquery> </cfquery>
<!---<cfdump var=#arguments#/><cfdump var=#local.qRead#/><cfabort/> --->
<cfquery name="local.qTotal"> <cfquery name="local.qTotal">
select count(*) as cnt select count(*) as cnt
from instance e from instance e
@@ -298,7 +267,6 @@
join contract d on (s.contract_id=d.contract_id) join contract d on (s.contract_id=d.contract_id)
join contragent k on (d.contragent_id=k.contragent_id) join contragent k on (d.contragent_id=k.contragent_id)
join svc v on (e.service_id=v.svc_id) join svc v on (e.service_id=v.svc_id)
left outer join (select ist.instance_state_uid, ist.instance_uid, ist.version, ist.dt_state, ist.is_test 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->>'isSuspended') as is_suspended
,(ist.instance_data->>'isDeleted') as is_deleted ,(ist.instance_data->>'isDeleted') as is_deleted
@@ -310,52 +278,37 @@
from instance_operation o join (select instance_uid, max(dt_submit) as dt_submit from instance_operation group by 1) lastv 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 (o.instance_uid=lastv.instance_uid AND o.dt_submit=lastv.dt_submit) ) io
on (e.instance_uid=io.instance_uid) on (e.instance_uid=io.instance_uid)
<!--- specificationId инжектируется в arguments scope в Application.cfc ---> <!--- specificationId инжектируется в arguments scope в Application.cfc --->
where s.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/> where s.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/>
<!--- u.usr_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.usrId#/> --->
</cfquery> </cfquery>
<cfset var out=structNew("linked")/> <cfset var out=structNew("linked")/>
<cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/> <cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/>
<cfset "out.total"=#local.qTotal.cnt#/> <cfset "out.total"=#local.qTotal.cnt#/>
<cfset "out.resultSetSize"=#local.qCnt.cnt#/> <cfset "out.resultSetSize"=#local.qCnt.cnt#/>
<cfset "out.pageSize"=#arguments.pageSize*1#/> <cfset "out.pageSize"=#arguments.pageSize*1#/>
<cfset "out.page"=#arguments.page*1#/> <cfset "out.page"=#arguments.page*1#/>
<cfset "out.orderBy"=#arguments.orderBy#/> <cfset "out.orderBy"=#arguments.orderBy#/>
<cfset var resultCollection=[]/> <cfset var resultCollection=[]/>
<cfloop query=#local.qRead# <!--- startRow=#startrow# endRow=#(startrow+maxrows-1)# --->> <cfloop query=#local.qRead# <!--- startRow=#startrow# endRow=#(startrow+maxrows-1)# --->>
<cfset var rec=structNew("linked")/> <cfset var rec=structNew("linked")/>
<cfset this.helper.appendRecord(rec, "", local.titleMap, local.qRead, this.helper.snake2camel)/> <cfset this.helper.appendRecord(rec, "", local.titleMap, local.qRead, this.helper.snake2camel)/>
<cfset arrayAppend(resultCollection, rec)/> <cfset arrayAppend(resultCollection, rec)/>
</cfloop> </cfloop>
<cfset "out.size"=#arrayLen(resultCollection)#/> <cfset "out.size"=#arrayLen(resultCollection)#/>
<cfset "out.results"=#resultCollection#/> <cfset "out.results"=#resultCollection#/>
<cfset "out.runDurationMs"=getTickCount()-request.startTickCount/> <cfset "out.runDurationMs"=getTickCount()-request.startTickCount/>
<!---<cfset "out.sql"=#local.result.sql#/>--->
<cfreturn representationOf(out)/> <cfreturn representationOf(out)/>
<cfcatch type="any"> <!--- {"message"=cfcatch.message, "detail"=cfcatch.detail} ---> <cfcatch type="any"> <!--- {"message"=cfcatch.message, "detail"=cfcatch.detail} --->
<cfreturn representationOf(cfcatch).withStatus(500)/> <cfreturn representationOf(cfcatch).withStatus(500)/>
</cfcatch> </cfcatch>
</cftry> </cftry>
</cffunction><!--- get ---> </cffunction><!--- get --->
<cffunction name="post" hint="ВНИМАНИЕ! У текущего контрагента должна быть спецификация, в которую будет вписан создаваемый экземпляр. Новая пустая запись экземпляра. Фактическое развертывание выполняется отдельно,асинхронной операцией create сконфигурированного экземпляра. Одновременно мы создаем строку в спецификации по умолчанию и связываем экземпляр с этой строкой. Первичный ключ генерируется. Текущий пользователь, контракт, спецификация получаются из контекста."> <cffunction name="post" hint="ВНИМАНИЕ! У текущего контрагента должна быть спецификация, в которую будет вписан создаваемый экземпляр. Новая пустая запись экземпляра. Фактическое развертывание выполняется отдельно,асинхронной операцией create сконфигурированного экземпляра. Одновременно мы создаем строку в спецификации по умолчанию и связываем экземпляр с этой строкой. Первичный ключ генерируется. Текущий пользователь, контракт, спецификация получаются из контекста.">
<cfargument name="displayName" type="string" required=true hint="type:string"/> <cfargument name="displayName" type="string" required=true hint="type:string"/>
<cfargument name="serviceId" type="string" required=true hint="type:integer"/> <cfargument name="serviceId" type="string" required=true hint="type:integer"/>
<cfargument name="descr" type="string" required=false default="" hint="type:varchar (no cleanup here!)"/> <cfargument name="descr" type="string" required=false default="" hint="type:varchar (no cleanup here!)"/>
<cfargument name="resourceRealmId" type="string" required=false default="-1" hint="type:integer"/> <cfargument name="resourceRealmId" type="string" required=false default="-1" hint="type:integer"/>
<!--- <cfargument name="instanceUid" type="string" required=false default="" hint="type:guid)"/>
<cfargument name="usrUid" type="string" required=true hint="type:guid"/>
<cfargument name="companyUid" type="string" required=true hint="type:guid"/> --->
<!--- оказывается, их можно и не декларировать ---> <!--- оказывается, их можно и не декларировать --->
<cfif !structKeyExists(arguments, "specificationId")> <cfif !structKeyExists(arguments, "specificationId")>
<cfreturn representationOf("arguments.specificationId not defined").withStatus(500)/> <cfreturn representationOf("arguments.specificationId not defined").withStatus(500)/>
</cfif> </cfif>
@@ -365,16 +318,11 @@
<cfif !(arguments.specificationId GT 0)> <cfif !(arguments.specificationId GT 0)>
<cfreturn representationOf("specification not defined (arguments.specificationId should be a posititve integer)").withStatus(500)/> <cfreturn representationOf("specification not defined (arguments.specificationId should be a posititve integer)").withStatus(500)/>
</cfif> </cfif>
<cfset var local={}/> <cfset var local={}/>
<cfset local.instanceUid=#createGUID()#/> <cfset local.instanceUid=#createGUID()#/>
<cftry> <cftry>
<cfset this.helper.keyExistsAndValid(arguments, "serviceId", "integer")/> <cfset this.helper.keyExistsAndValid(arguments, "serviceId", "integer")/>
<cfset checkDisplayName(arguments.displayName, arguments.usrId, local.instanceUid)/> <cfset checkDisplayName(arguments.displayName, arguments.usrId, local.instanceUid)/>
<!--- делаем вставку в спецификацию и таблицу экземпляров ---> <!--- делаем вставку в спецификацию и таблицу экземпляров --->
<cfquery name="local.qSpecItem"> <cfquery name="local.qSpecItem">
insert into specification_item insert into specification_item
@@ -392,7 +340,6 @@
,<cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.usrId#" /> ,<cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.usrId#" />
) returning specification_item_id; ) returning specification_item_id;
</cfquery> </cfquery>
<cfquery name="local.qSave"> <cfquery name="local.qSave">
insert into instance insert into instance
(instance_uid, display_name, service_id, specification_item_id, descr, dt_created, creator_id, dt_updated, updater_id) (instance_uid, display_name, service_id, specification_item_id, descr, dt_created, creator_id, dt_updated, updater_id)
@@ -409,28 +356,21 @@
,<cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.usrId#" /> ,<cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.usrId#" />
); );
</cfquery> </cfquery>
<cfcatch type="invalidParamValue"> <cfcatch type="invalidParamValue">
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/> <cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
</cfcatch> </cfcatch>
</cftry> </cftry>
<cfreturn noData() <cfreturn noData()
.withHeaders({location: "./#local.instanceUid#"}) .withHeaders({location: "./#local.instanceUid#"})
.withStatus(201, "Created") .withStatus(201, "Created")
/> />
</cffunction><!--- post ---> </cffunction><!--- post --->
<cffunction name="checkDisplayName"> <cffunction name="checkDisplayName">
<cfargument name="displayName" required=true/> <cfargument name="displayName" required=true/>
<cfargument name="usrId" type="numeric" required=true/> <cfargument name="usrId" type="numeric" required=true/>
<cfargument name="instanceUid" type="guid" required=true/> <cfargument name="instanceUid" type="guid" required=true/>
<cfset var local={}/> <cfset var local={}/>
<cfset var display_name=trim(lcase(arguments.displayName))/> <cfset var display_name=trim(lcase(arguments.displayName))/>
<cfif len(display_name) LT 3> <cfif len(display_name) LT 3>
<cfthrow type="InvalidParamValue" message="Instance Display Name too short" detail="Имя должно быть не короче 3 символов"/> <cfthrow type="InvalidParamValue" message="Instance Display Name too short" detail="Имя должно быть не короче 3 символов"/>
<cfelseif len(display_name) GT 80> <cfelseif len(display_name) GT 80>
@@ -454,20 +394,16 @@
</cfif> </cfif>
</cfif> </cfif>
</cffunction> </cffunction>
<cffunction name="generateDefaultName" returnType="string"> <cffunction name="generateDefaultName" returnType="string">
<!--- *** Это некорректно, потому что имя может содержать пробелы и т.п. ---> <!--- *** Это некорректно, потому что имя может содержать пробелы и т.п. --->
<!--- *** Неуклюже и медленно ---> <!--- *** Неуклюже и медленно --->
<!--- Эти валидации и генерации занимают удивительно много рабочего времени ---> <!--- Эти валидации и генерации занимают удивительно много рабочего времени --->
<cfargument name="service_id" type="numeric"/> <cfargument name="service_id" type="numeric"/>
<cfargument name="usr_id" type="numeric"/> <cfargument name="usr_id" type="numeric"/>
<cfset var local={}/> <cfset var local={}/>
<cfquery name="local.qSvc"> <cfquery name="local.qSvc">
select coalesce(svc_short,svc) as svc_short from svc where svc_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.service_id#/> select coalesce(svc_short,svc) as svc_short from svc where svc_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.service_id#/>
</cfquery> </cfquery>
<cfquery name="local.qInst"> <cfquery name="local.qInst">
select display_name select display_name
from instance e from instance e
@@ -480,7 +416,6 @@
AND lower(e.display_name) like lower(<cfqueryparam cfsqltype="cf_sql_varchar" value="#local.qSvc.svc_short#%"/>) AND lower(e.display_name) like lower(<cfqueryparam cfsqltype="cf_sql_varchar" value="#local.qSvc.svc_short#%"/>)
AND service_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.service_id#/> AND service_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.service_id#/>
</cfquery> </cfquery>
<cfset var prefixLen=len(local.qSvc.svc_short)+1/> <cfset var prefixLen=len(local.qSvc.svc_short)+1/>
<cfset var i=1/> <cfset var i=1/>
<cfloop query="local.qInst"> <cfloop query="local.qInst">
@@ -491,54 +426,6 @@
</cfif> </cfif>
</cfif> </cfif>
</cfloop> </cfloop>
<cfreturn "#local.qSvc.svc_short#-#i+1#"/> <cfreturn "#local.qSvc.svc_short#-#i+1#"/>
</cffunction> </cffunction>
</cfcomponent> </cfcomponent>
<!---
select
updater_shortname,duration,specification_id,display_name,contract_id,instance_config_dt_created,operation_is_pending,code,updater_login,operation_is_in_progress,instance_config_dt_updated,is_auxiliary,svc,service_id,dt_state,last_operation,submit_result,instance_state_uid,dt_deploy,is_test,specification_item_id,is_deleted,version,resource_realm,updater_id,operation_dt_start,operation_dt_finish,explained_status,last_operation_uid,uptime,instance_uid,suspended,instance_data,specification
from (
select
to_char(e.dt_created, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as instance_config_dt_created,to_char(e.dt_updated, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as instance_config_dt_updated,e.instance_uid::text as instance_uid,e.display_name,e.service_id,e.specification_item_id,e.is_auxiliary,d.contract_id,i.specification_id,s.specification,v.svc,v.code,e.updater_id,u.login as updater_login,u.shortname as updater_shortname,(select io.operation from instance_operation io where io.instance_uid=e.instance_uid order by dt_submit desc limit 1) as last_operation,(select io.instance_operation_uid::text from instance_operation io where io.instance_uid=e.instance_uid order by dt_submit desc limit 1) as last_operation_uid,(select io.submit_result from instance_operation io where io.instance_uid=e.instance_uid order by dt_submit desc limit 1) as submit_result,(select coalesce((io.dt_start IS NOT NULL AND io.dt_finish IS NULL AND io.submit_result='201'),false) from instance_operation io where io.instance_uid=e.instance_uid order by dt_submit desc limit 1) as operation_is_in_progress,(select coalesce((io.dt_start IS NULL AND io.submit_result='201'),false) from instance_operation io where io.instance_uid=e.instance_uid order by dt_submit desc limit 1) as operation_is_pending,(select to_char(io.dt_start, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') from instance_operation io where io.instance_uid=e.instance_uid order by dt_submit desc limit 1) as operation_dt_start,(select to_char(io.dt_finish, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') from instance_operation io where io.instance_uid=e.instance_uid order by dt_submit desc limit 1) as operation_dt_finish,(select round(extract('epoch' from coalesce(io.dt_finish,CURRENT_TIMESTAMP)- io.dt_start),1) from instance_operation io where io.instance_uid=e.instance_uid order by dt_submit desc limit 1) as duration,(select case
when io.operation IN ('delete', 'suspend') AND io.is_successful then 0
when io.is_successful then extract('epoch' from CURRENT_TIMESTAMP - coalesce(io.dt_finish,CURRENT_TIMESTAMP))
else 0 end
from instance_operation io
where io.instance_uid=e.instance_uid
order by dt_submit desc
limit 1)
as uptime,(select to_char(io.dt_finish, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') from instance_operation io where io.instance_uid=e.instance_uid AND io.is_successful AND io.operation='create' order by dt_submit desc limit 1) as dt_deploy,(select instance_data::text from instance_state st where st.instance_uid=e.instance_uid order by version desc limit 1) as instance_data,(select st.instance_state_uid::text from instance_state st where st.instance_uid=e.instance_uid order by version desc limit 1) as instance_state_uid,(select st.is_test from instance_state st where st.instance_uid=e.instance_uid order by version desc limit 1) as is_test,coalesce((select st.instance_data->>'isDeleted' from instance_state st where st.instance_uid=e.instance_uid order by version desc limit 1),'false') as is_deleted,(select st.instance_data->>'isSuspended' from instance_state st where st.instance_uid=e.instance_uid order by version desc limit 1) as suspended,(select cast(st.instance_data->>'params' as json)->>'resourceRealm' from instance_state st where st.instance_uid=e.instance_uid order by version desc limit 1) as resource_realm,(select to_char(st.dt_state, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') from instance_state st where st.instance_uid=e.instance_uid order by version desc limit 1) as dt_state,
(case
when
(select st.instance_data->>'isDeleted' from instance_state st where st.instance_uid=e.instance_uid order by version desc limit 1) = 'true' then 'deleted'
when
(select st.instance_data->>'isSuspended' from instance_state st where st.instance_uid=e.instance_uid order by version desc limit 1) = 'true' then 'suspended'
when
(select coalesce(st.instance_data->>'isDeleted','false') from instance_state st where st.instance_uid=e.instance_uid order by version desc limit 1) = 'false'
AND
(select coalesce(st.instance_data->>'isSuspended','false') from instance_state st where st.instance_uid=e.instance_uid order by version desc limit 1) = 'false'
then 'running'
when
not exists (select * from instance_operation o where o.instance_uid=e.instance_uid) then 'not configured'
when
not exists (select * from instance_state st where st.instance_uid=e.instance_uid) then 'not created'
else null end
) as explained_status
,(select max(version) from instance_state st where st.instance_uid=e.instance_uid) as version
from instance e
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)
left outer join usr u on (e.updater_id=u.usr_id)
where s.specification_id=2
) inr
where 1=1
order by 1 desc
limit 100
offset 100
--->
+5 -187
View File
@@ -4,25 +4,21 @@
Но: мы не хотели бы менять положение сущности в дереве. Либо она в корне, либо она ниже. И получится, когда мы выбираем один параметр, нам ни к чему контекст - мы к нему однозначно адресуемся. Но: мы не хотели бы менять положение сущности в дереве. Либо она в корне, либо она ниже. И получится, когда мы выбираем один параметр, нам ни к чему контекст - мы к нему однозначно адресуемся.
Проголосуем против избыточности? Проголосуем против избыточности?
---> --->
<!--- Все методы неявно получают <!--- Все методы неявно получают
arguments.usrId arguments.usrId
arguments.contragentId arguments.contragentId
arguments.contractId arguments.contractId
arguments.specificationId arguments.specificationId
arguments.requestArguments.usrId=usrCustomerInfo.usrId; //Integer! arguments.requestArguments.usrId=usrCustomerInfo.usrId; //Integer!
arguments.requestArguments.contragentId=usrCustomerInfo.contragentId; //Integer arguments.requestArguments.contragentId=usrCustomerInfo.contragentId; //Integer
arguments.requestArguments.contractId=usrCustomerInfo.contractId; //Integer arguments.requestArguments.contractId=usrCustomerInfo.contractId; //Integer
arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //Integer arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //Integer
---> --->
<cfsilent> <cfsilent>
<cfimport prefix="m" taglib="../lib"/> <cfimport prefix="m" taglib="../lib"/>
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/><!---*** странно, почему мы его видим?---><!---вынести в апп?---> <cfset this.helper=CreateObject("component","lib.rest_api_helper")/><!---*** странно, почему мы его видим?---><!---вынести в апп?--->
</cfsilent> </cfsilent>
<!--- cfproperty использовать не надо, это для веб сервисов ---> <!--- cfproperty использовать не надо, это для веб сервисов --->
<cffunction name="init"> <cffunction name="init">
<!--- *** ---------------- !!! note camelCase in keys naming!!! ----------------- ---> <!--- *** ---------------- !!! note camelCase in keys naming!!! ----------------- --->
<!--- для нового инстанса нам нужно знать хотя бы его класс (сервис) ---> <!--- для нового инстанса нам нужно знать хотя бы его класс (сервис) --->
@@ -34,7 +30,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
<cfset this.instance_operation_cfs_param_uid = "00000000-0000-0000-0000-000000000000"/><!--- *** костыль default=---> <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_operation_uid = "00000000-0000-0000-0000-000000000000"/><!--- *** костыль default=--->
<cfset this.instance_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)> <cfif structKeyExists(arguments.keys,"instanceOperationCfsParamUid") AND isValid("guid", arguments.keys.instanceOperationCfsParamUid)>
<cfset this.instance_operation_cfs_param_uid=arguments.keys.instanceOperationCfsParamUid/> <cfset this.instance_operation_cfs_param_uid=arguments.keys.instanceOperationCfsParamUid/>
<cfquery name="local.qResolve"> <cfquery name="local.qResolve">
@@ -66,20 +61,15 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
<cfif structKeyExists(arguments.params,"resourceRealm")> <cfif structKeyExists(arguments.params,"resourceRealm")>
<cfset this.resourceRealm=arguments.params.resourceRealm/> <cfset this.resourceRealm=arguments.params.resourceRealm/>
</cfif> </cfif>
<!--- <cfdump var=#this# abort=true/> --->
<!--- <cfdump var=#this#/> --->
<cfreturn this> <cfreturn this>
</cffunction> </cffunction>
<!--- ---------------------------------------------------------------------- ---> <!--- ---------------------------------------------------------------------- --->
<!--- Прикладные функции, которые можно использовать в составе выражений. Аргументами им могут служить параметры, от которых мы зависим ---> <!--- Прикладные функции, которые можно использовать в составе выражений. Аргументами им могут служить параметры, от которых мы зависим --->
<!--- Добавить обработку исключений ---> <!--- Добавить обработку исключений --->
<cffunction name="dummy" returntype="any" access="public"> <cffunction name="dummy" returntype="any" access="public">
<cfargument name="arg" type="any"/> <cfargument name="arg" type="any"/>
<cfreturn arg/> <cfreturn arg/>
</cffunction> </cffunction>
<cffunction name="concat" returntype="string" access="public"> <cffunction name="concat" returntype="string" access="public">
<cfset var local={}/> <cfset var local={}/>
<cfset var s=""/> <cfset var s=""/>
@@ -88,7 +78,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
</cfloop> </cfloop>
<cfreturn s/> <cfreturn s/>
</cffunction> </cffunction>
<cffunction name="getValue"><!--- используем пока только для параметров, в принципе может видеть больше, чем положено ---> <cffunction name="getValue"><!--- используем пока только для параметров, в принципе может видеть больше, чем положено --->
<cfargument name="token" type="string"/> <cfargument name="token" type="string"/>
<!--- тут такой странный синтаксис: для скоупа params подставляем getCfsParam ---> <!--- тут такой странный синтаксис: для скоупа params подставляем getCfsParam --->
@@ -103,7 +92,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
</cfif> </cfif>
<cfreturn variables[scope][name]/><!--- *** вряд ли это отработает для субпараметров ---> <cfreturn variables[scope][name]/><!--- *** вряд ли это отработает для субпараметров --->
</cffunction> </cffunction>
<!--- может быть, обобщить для наследуемых параметров... или для всех вообще ---> <!--- может быть, обобщить для наследуемых параметров... или для всех вообще --->
<cffunction name="getResourceRealm"> <cffunction name="getResourceRealm">
<!--- нужна отдельная функция, потому что resourceRealm может браться из параметров операции, а может наследоваться от родительского инстанса ---> <!--- нужна отдельная функция, потому что resourceRealm может браться из параметров операции, а может наследоваться от родительского инстанса --->
@@ -111,11 +99,10 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
<!--- если операция не сохранена - мы как узнаем, есть у нее параметр resourceRealm, или нет? наверно, простой джойн тут не поможет <!--- если операция не сохранена - мы как узнаем, есть у нее параметр resourceRealm, или нет? наверно, простой джойн тут не поможет
но никто не мешает спросить отдельно---> но никто не мешает спросить отдельно--->
<!--- *** тут возникает определенная путаница из-за того, что часть данных берется из параметров операции, а часть из параметров инстанса (кумулятивных) ---> <!--- *** тут возникает определенная путаница из-за того, что часть данных берется из параметров операции, а часть из параметров инстанса (кумулятивных) --->
<!--- <cfdump var=#this#/> --->
<cfif structKeyExists(this,"resourceRealm") AND len(this.resourceRealm)><!--- может быть, понятнее было бы брать прямо из параметров ---> <cfif structKeyExists(this,"resourceRealm") AND len(this.resourceRealm)><!--- может быть, понятнее было бы брать прямо из параметров --->
<cfreturn this.resourceRealm/> <cfreturn this.resourceRealm/>
</cfif> </cfif>
<!--- ищем у даннной операции CFS параметр resourceRealm ---><!--- <cfdump var=#this#/><cfabort/> ---> <!--- ищем у даннной операции CFS параметр resourceRealm --->
<cfquery name="local.qCfsParam"> <cfquery name="local.qCfsParam">
select p.param_value select p.param_value
from svc_operation_cfs_param s from svc_operation_cfs_param s
@@ -123,7 +110,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
where s.svc_operation_cfs_param = 'resourceRealm' 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)#/> AND p.instance_operation_uid = <cfqueryparam cfsqltype="cf_sql_other" value=#this.instance_operation_uid# null=#!isValid('guid',this.instance_operation_uid)#/>
</cfquery> </cfquery>
<!--- <cfdump var=#local.qCfsParam#/> --->
<!--- ---> <!--- --->
<cfif local.qCfsParam.recordCount> <cfif local.qCfsParam.recordCount>
<!--- параметр определен в операции сервиса. Если его не нашли - значит, не судьба ---> <!--- параметр определен в операции сервиса. Если его не нашли - значит, не судьба --->
@@ -136,7 +122,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
и инстанс-операцию-параметр (регулярная реляционная иерархия) и инстанс-операцию-параметр (регулярная реляционная иерархия)
хотя инстанс и операция есть в параметрах (некоторое дублирование, потому что оркестратору все передается через параметры) хотя инстанс и операция есть в параметрах (некоторое дублирование, потому что оркестратору все передается через параметры)
---> --->
<cfset local.instance_uid = this.instance_uid/> <cfset local.instance_uid = this.instance_uid/>
<cfif !isValid("guid", local.instance_uid) OR local.instance_uid EQ "00000000-0000-0000-0000-000000000000"> <cfif !isValid("guid", local.instance_uid) OR local.instance_uid EQ "00000000-0000-0000-0000-000000000000">
<!--- тогда нам нужно найти параметр-референс и взять его значение ---> <!--- тогда нам нужно найти параметр-референс и взять его значение --->
@@ -149,7 +134,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
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)#/> 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 AND r.ref_svc_id > 0
</cfquery> </cfquery>
<!--- <cfdump var=#local.qRefParam#/> --->
<cfloop query="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])> <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]/> <cfset local.instance_uid = this.params[local.qRefParam.svc_operation_cfs_param]/>
@@ -163,7 +147,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
Можно сделать дополнительную фильтрацию по типу справочника (resourceRealm) Можно сделать дополнительную фильтрацию по типу справочника (resourceRealm)
---> --->
</cfif> </cfif>
<!--- внимание! мы тут опрашиваем параметры инстанса, а не операции! ---> <!--- внимание! мы тут опрашиваем параметры инстанса, а не операции! --->
<!--- *** тут возникает непонятная ссылка на себя, впрочем, она не мешает ---> <!--- *** тут возникает непонятная ссылка на себя, впрочем, она не мешает --->
<cfquery name="local.qCfsParam"> <cfquery name="local.qCfsParam">
@@ -183,9 +166,7 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
LEFT JOIN instance_cfs_param rp on (e.instance_uid=rp.instance_uid ) LEFT JOIN instance_cfs_param rp on (e.instance_uid=rp.instance_uid )
LEFT JOIN instance ri on (rp.instance_uid=ri.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)#/> WHERE e.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value=#local.instance_uid# null=#!isValid('guid',local.instance_uid)#/>
UNION UNION
SELECT SELECT
i+1 AS i i+1 AS i
,e.display_name ,e.display_name
@@ -202,7 +183,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
select param, param_value from r select param, param_value from r
order by r.i desc order by r.i desc
</cfquery> </cfquery>
<cfif local.qCfsParam.recordCount EQ 0> <cfif local.qCfsParam.recordCount EQ 0>
<!--- тогда зайдем от параметров операции (только в данном экземпляре, зависимости все должны быть уже созданы) ---> <!--- тогда зайдем от параметров операции (только в данном экземпляре, зависимости все должны быть уже созданы) --->
<cfquery name="local.qCfsParam"> <cfquery name="local.qCfsParam">
@@ -223,9 +203,7 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
--LEFT JOIN instance_cfs_param rp on (e.instance_uid=rp.instance_uid ) --LEFT JOIN instance_cfs_param rp on (e.instance_uid=rp.instance_uid )
--LEFT JOIN instance ri on (rp.instance_uid=ri.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)#/> WHERE e.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value=#local.instance_uid# null=#!isValid('guid',local.instance_uid)#/>
UNION UNION
SELECT SELECT
i+1 AS i i+1 AS i
,e.display_name ,e.display_name
@@ -243,17 +221,14 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
order by r.i desc order by r.i desc
</cfquery> </cfquery>
</cfif> </cfif>
<!--- <cfdump var=#local.qCfsParam#/>--->
<cfloop query="local.qCfsParam"> <cfloop query="local.qCfsParam">
<cfif local.qCfsParam.param EQ "resourceRealm"> <cfif local.qCfsParam.param EQ "resourceRealm">
<cfreturn local.qCfsParam.param_value/> <cfreturn local.qCfsParam.param_value/>
</cfif> </cfif>
</cfloop> </cfloop>
<cfreturn "Resource Realm Not Found"/> <cfreturn "Resource Realm Not Found"/>
</cfif> </cfif>
</cffunction> </cffunction>
<cffunction name="getCfsParam"> <cffunction name="getCfsParam">
<cfargument name="param" type="string"/> <cfargument name="param" type="string"/>
<cfargument name="subparam" type="string" required=false/> <cfargument name="subparam" type="string" required=false/>
@@ -264,12 +239,10 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
при этом мы ожидаем в параметрах структуру paramName:{subparamName:subparamValue} при этом мы ожидаем в параметрах структуру paramName:{subparamName:subparamValue}
но почему не находим в сохраненных? возможно такое совпадение, что в сценарии у нас как раз надо выбрать svcId а они не ---> но почему не находим в сохраненных? возможно такое совпадение, что в сценарии у нас как раз надо выбрать svcId а они не --->
<!--- {"startupConfiguration":{"vdcUid":"ea81db31-2197-407d-b32b-e60577c2671c"}} ---> <!--- {"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(this.params,arguments.param)><!--- AND len(this.params[arguments.param]) --->
<cfif structKeyExists(arguments,"subparam")><!--- *** не изящно, но просто и понятно ---> <cfif structKeyExists(arguments,"subparam")><!--- *** не изящно, но просто и понятно --->
<cfreturn (this.params[arguments.param])[arguments.subparam]/> <cfreturn (this.params[arguments.param])[arguments.subparam]/>
<cfelse>this.params[arguments.param] <!--- <cfdump var=#this.params[arguments.param]#/> ---> <cfelse>this.params[arguments.param]
<cfreturn this.params[arguments.param]/> <cfreturn this.params[arguments.param]/>
</cfif> </cfif>
</cfif> </cfif>
@@ -281,7 +254,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
where p.instance_operation_uid = <cfqueryparam cfsqltype="cf_sql_other" value=#this.instance_operation_uid# null=#!isValid('guid',this.instance_operation_uid)#/> 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#/> AND s.svc_operation_cfs_param = <cfqueryparam cfsqltype="cf_sql_varchar" value=#arguments.param#/>
</cfquery> </cfquery>
<!--- <cfdump var=#this.keys#/> --->
<cfif structKeyExists(arguments,"subparam")><!--- *** не изящно, но просто и понятно ---> <cfif structKeyExists(arguments,"subparam")><!--- *** не изящно, но просто и понятно --->
<cfset var value = deserializeJson(local.qCfsParam.param_value)/> <cfset var value = deserializeJson(local.qCfsParam.param_value)/>
<cfif isStruct(value) AND structKeyExists(value, arguments.subparam)> <cfif isStruct(value) AND structKeyExists(value, arguments.subparam)>
@@ -293,24 +265,13 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
<cfreturn local.qCfsParam.param_value/> <cfreturn local.qCfsParam.param_value/>
</cfif> </cfif>
</cffunction> </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/><!--- халява, для упрощения диагностики ---> <cfreturn cfcatch.message/><!--- халява, для упрощения диагностики --->
</cfcatch> </cfcatch>
</cftry> </cftry>
</cffunction> ---> </cffunction> --->
<cffunction name="getValueFromStruct" returntype="any"> <cffunction name="getValueFromStruct" returntype="any">
<cfargument name="struct" type="struct" required="true"/> <cfargument name="struct" type="struct" required="true"/>
<cfargument name="path" type="string" required="true"/> <cfargument name="path" type="string" required="true"/>
<cftry> <cftry>
<cfreturn structGet("arguments.struct.#arguments.path#")/> <cfreturn structGet("arguments.struct.#arguments.path#")/>
<cfcatch type="any"> <cfcatch type="any">
@@ -319,24 +280,18 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
</cfcatch> </cfcatch>
</cftry> </cftry>
</cffunction> </cffunction>
<cffunction name="getStringFromStruct" returntype="string" hint="returns scalar"> <cffunction name="getStringFromStruct" returntype="string" hint="returns scalar">
<cfargument name="struct" type="struct" required="true"/> <cfargument name="struct" type="struct" required="true"/>
<cfargument name="path" type="string" required="true"/> <cfargument name="path" type="string" required="true"/>
<cfset var value = getValueFromStruct(arguments.struct,arguments.path)/> <cfset var value = getValueFromStruct(arguments.struct,arguments.path)/>
<cfif isStruct(value) OR isArray(value)> <cfif isStruct(value) OR isArray(value)>
<cfreturn serializeJson(value)/> <cfreturn serializeJson(value)/>
</cfif> </cfif>
<cfreturn toString(value)/> <cfreturn toString(value)/>
</cffunction> </cffunction>
<cffunction name="getKeyListFromStruct" returntype="string" hint="returns list"> <cffunction name="getKeyListFromStruct" returntype="string" hint="returns list">
<cfargument name="struct" type="struct" required="true"/> <cfargument name="struct" type="struct" required="true"/>
<cfargument name="path" type="string" required="true"/> <cfargument name="path" type="string" required="true"/>
<cftry> <cftry>
<cfreturn structKeyList(structGet("arguments.struct.#arguments.path#"))/> <cfreturn structKeyList(structGet("arguments.struct.#arguments.path#"))/>
<cfcatch type="any"> <cfcatch type="any">
@@ -346,12 +301,9 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
</cfcatch> </cfcatch>
</cftry> </cftry>
</cffunction> </cffunction>
<cffunction name="getArrayAsListFromStruct" returntype="string" hint="returns list"> <cffunction name="getArrayAsListFromStruct" returntype="string" hint="returns list">
<cfargument name="struct" type="struct" required="true"/> <cfargument name="struct" type="struct" required="true"/>
<cfargument name="path" type="string" required="true"/> <cfargument name="path" type="string" required="true"/>
<cftry> <cftry>
<cfreturn arrayToList(structGet("arguments.struct.#arguments.path#"))/> <cfreturn arrayToList(structGet("arguments.struct.#arguments.path#"))/>
<cfcatch type="any"> <cfcatch type="any">
@@ -361,39 +313,11 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
</cfcatch> </cfcatch>
</cftry> </cftry>
</cffunction> </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"> <cffunction name="getInstanceState" returntype="struct">
<cfargument name="instanceUid" default=#this.instance_uid#/><!--- type="guid" ---> <cfargument name="instanceUid" default=#this.instance_uid#/><!--- type="guid" --->
<cfif !isValid("guid",arguments.instanceUid)> <cfif !isValid("guid",arguments.instanceUid)>
<cfreturn {}/><!--- иначе при неопределенном параметре мы получаем исключение ---> <cfreturn {}/><!--- иначе при неопределенном параметре мы получаем исключение --->
</cfif> </cfif>
<cfset var local={}/> <cfset var local={}/>
<cfquery name="local.qInstance" datasource="cmdb"> <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 select g.instance_state_uid, g.version, g.dt_state, g.instance_data, g.is_test, g.instance_uid
@@ -402,7 +326,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
order by g.version desc order by g.version desc
limit 1 limit 1
</cfquery> </cfquery>
<!--- <cfreturn deserializeJson(local.qInstance.instance_data)/><cfabort/> --->
<cftry> <cftry>
<cfset var structConfig = deserializeJson(local.qInstance.instance_data)/> <cfset var structConfig = deserializeJson(local.qInstance.instance_data)/>
<cfcatch type="ANY"> <cfcatch type="ANY">
@@ -414,19 +337,14 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
</cfif> </cfif>
<cfreturn structConfig/> <cfreturn structConfig/>
</cffunction> </cffunction>
<cffunction name="getResourceRealmConfig" returntype="struct"> <cffunction name="getResourceRealmConfig" returntype="struct">
<cfargument name="resourceRealm" type="string" default=#getResourceRealm()#/><!--- платформа может быть определена для родительского инстанса где то в иерархии ---> <cfargument name="resourceRealm" type="string" default=#getResourceRealm()#/><!--- платформа может быть определена для родительского инстанса где то в иерархии --->
<cfset var local={}/> <cfset var local={}/>
<cfquery name="local.qResourceRealm" datasource="cmdb"> <cfquery name="local.qResourceRealm" datasource="cmdb">
select r.resource_realm_id, r.properties select r.resource_realm_id, r.properties
from resource_realm r from resource_realm r
where r.resource_realm=<cfqueryparam cfsqltype="cf_sql_varchar" value=#arguments.resourceRealm#/> where r.resource_realm=<cfqueryparam cfsqltype="cf_sql_varchar" value=#arguments.resourceRealm#/>
</cfquery> </cfquery>
<!--- <cfdump var=#arguments#/>
<cfdump var=#local.qResourceRealm#/> --->
<cftry> <cftry>
<cfset var structConfig = deserializeJson(local.qResourceRealm.properties)/> <cfset var structConfig = deserializeJson(local.qResourceRealm.properties)/>
<cfcatch type="ANY"> <cfcatch type="ANY">
@@ -439,17 +357,10 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
</cfif> </cfif>
<cfreturn {}/> <cfreturn {}/>
</cffunction> </cffunction>
<!--- ReST methods ---> <!--- ReST methods --->
<!--- ----------------------------------------------------------------------------------------- ---> <!--- ----------------------------------------------------------------------------------------- --->
<!--- ----------------------------------------------------------------------------------------- ---> <!--- ----------------------------------------------------------------------------------------- --->
<!--- ----------------------------------------------------------------------------------------- ---> <!--- ----------------------------------------------------------------------------------------- --->
<cffunction name="get" hint="CFS параметр операции инстанса"> <cffunction name="get" hint="CFS параметр операции инстанса">
<cfargument name="instanceOperationCfsParamUid" type="string" required=true hint="type:guid"/> <cfargument name="instanceOperationCfsParamUid" type="string" required=true hint="type:guid"/>
<cftry> <cftry>
@@ -458,16 +369,13 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/> <cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
</cfcatch> </cfcatch>
</cftry> </cftry>
<cfset local={}/> <cfset local={}/>
<cfquery name="local.qCfsParam" result="local.result"> <cfquery name="local.qCfsParam" result="local.result">
select select
<m:field_set titleMapOut="local.titleMap" lengthOut="fieldCount"> <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_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.instance_operation_uid::text as instance_operation_uid</m:field>
<m:field>iop.svc_operation_cfs_param_id</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>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>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>to_char(iop.dt_created, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as dt_created</m:field>
@@ -482,14 +390,11 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
<m:field formatter=#request.castToBool#>sop.is_hidden</m:field> <m:field formatter=#request.castToBool#>sop.is_hidden</m:field>
<m:field formatter=#request.castToBool#>sop.is_disabled</m:field> <m:field formatter=#request.castToBool#>sop.is_disabled</m:field>
<m:field>sop.man</m:field> <m:field>sop.man</m:field>
<m:field>sop.func</m:field> <m:field>sop.func</m:field>
<m:field>sop.expression</m:field> <m:field>sop.expression</m:field>
<m:field>sop.nested_ref</m:field> <m:field>sop.nested_ref</m:field>
<m:field>sop.state_path</m:field> <m:field>sop.state_path</m:field>
<m:field>sop.depends_on_cfs_params</m:field> <m:field>sop.depends_on_cfs_params</m:field>
<m:field>sop.config::text as config</m:field> <m:field>sop.config::text as config</m:field>
<m:field>e.service_id</m:field> <m:field>e.service_id</m:field>
<m:field>e.instance_uid::text as instance_uid</m:field> <m:field>e.instance_uid::text as instance_uid</m:field>
@@ -503,11 +408,9 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
where iop.instance_operation_cfs_param_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationCfsParamUid#" null=#!isValid('guid',arguments.instanceOperationCfsParamUid)#/> 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#/> AND si.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/>
</cfquery> </cfquery>
<cfif local.qCfsParam.recordCount EQ 0> <cfif local.qCfsParam.recordCount EQ 0>
<cfreturn representationOf(this.helper.formatMessage("Not Found")).withStatus(404)/> <cfreturn representationOf(this.helper.formatMessage("Not Found")).withStatus(404)/>
</cfif> </cfif>
<cfif len(local.qCfsParam.func)><!--- приоритет отдается функции перед списком значений---> <cfif len(local.qCfsParam.func)><!--- приоритет отдается функции перед списком значений--->
<cfset var args = { <cfset var args = {
"functionName":"#local.qCfsParam.func#", "functionName":"#local.qCfsParam.func#",
@@ -515,7 +418,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
"contractId":#arguments.contractId# "contractId":#arguments.contractId#
}/> <!--- если появятся новые аргументы у новых функций, будем добавлять их сюда ---> }/> <!--- если появятся новые аргументы у новых функций, будем добавлять их сюда --->
<cfset local.qCfsParam.value_list=generateValueList(argumentCollection=#args#)/> <!--- можно перечислить именованные аргументы обычным порядком, но с коллекцией потенциально более гибко ---> <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> <cfif len(trim(local.qCfsParam.value_list)) AND listLen(local.qCfsParam.value_list) EQ 1>
<cfset local.qCfsParam.default_value=local.qCfsParam.value_list/> <cfset local.qCfsParam.default_value=local.qCfsParam.value_list/>
</cfif> </cfif>
@@ -538,43 +440,32 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
</cftry> </cftry>
<cfset local.qCfsParam.value_list = getListFromState(currentState, local.qCfsParam.state_path)/> <cfset local.qCfsParam.value_list = getListFromState(currentState, local.qCfsParam.state_path)/>
</cfif> </cfif>
<cfif (len(local.qCfsParam.func) OR len(local.qCfsParam.expression) OR len(local.qCfsParam.state_path) OR len(local.qCfsParam.nested_ref)) <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> AND len(local.qCfsParam.value_list) EQ 0>
<cfset local.qCfsParam.value_list = []/> <cfset local.qCfsParam.value_list = []/>
</cfif> </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"> <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 ---> <cfset processMap(local.qCfsParam)/><!--- query passed by reference --->
</cfif> </cfif>
<cfset var out=structNew("linked")/> <cfset var out=structNew("linked")/>
<cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/> <cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/>
<cfset "out.instanceOperationCfsParam" = this.helper.appendRecord( <cfset "out.instanceOperationCfsParam" = this.helper.appendRecord(
structNew("linked"), "", local.titleMap, local.qCfsParam, this.helper.snake2camel structNew("linked"), "", local.titleMap, local.qCfsParam, this.helper.snake2camel
)/> )/>
<cfset "out.runDurationMs"=getTickCount() - request.startTickCount/> <cfset "out.runDurationMs"=getTickCount() - request.startTickCount/>
<cfreturn representationOf(out) /> <cfreturn representationOf(out) />
</cffunction><!--- get ---> </cffunction><!--- get --->
<cffunction name="delete" hint="Удаление CFS параметра операции по ключу."> <cffunction name="delete" hint="Удаление CFS параметра операции по ключу.">
<cfargument name="instanceOperationCfsParamUid" type="string" required=true hint="type:guid"/> <cfargument name="instanceOperationCfsParamUid" type="string" required=true hint="type:guid"/>
<cftry> <cftry>
<cfset this.helper.validateField(arguments, "instanceOperationCfsParamUid", "guid")/> <cfset this.helper.validateField(arguments, "instanceOperationCfsParamUid", "guid")/>
<!--- *** Нужна проверка, что операция не была выполнена, иначе она становится архивной ---> <!--- *** Нужна проверка, что операция не была выполнена, иначе она становится архивной --->
<cfcatch type="invalidParamValue"> <cfcatch type="invalidParamValue">
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/> <cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
</cfcatch> </cfcatch>
</cftry> </cftry>
<cfset local={}/> <cfset local={}/>
<cftry><!--- *** без проверок существования ---> <cftry><!--- *** без проверок существования --->
<cfquery name="local.qCheck" result="local.result"> <cfquery name="local.qCheck" result="local.result">
select select
io.dt_submit, io.submit_result io.dt_submit, io.submit_result
@@ -585,19 +476,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
<cfif left(local.qCheck.submit_result,1) EQ "2"><!--- 201 etc ---> <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)/> <cfreturn representationOf(this.helper.formatMessage("Operation already started", "Parameter deletion disabled for started operation")).withStatus(422)/>
</cfif> </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"> <cfquery name="local.qCheckAccess" result="local.result">
select count(*) as cnt select count(*) as cnt
from instance_operation_cfs_param iop from instance_operation_cfs_param iop
@@ -610,26 +488,20 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
<cfif local.qCheckAccess.cnt EQ 0> <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)/> <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> </cfif>
<cfquery name="local.qSave"> <cfquery name="local.qSave">
delete from instance_operation_cfs_param 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)#/> where instance_operation_cfs_param_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationCfsParamUid#" null=#!isValid('guid',arguments.instanceOperationCfsParamUid)#/>
</cfquery> </cfquery>
<cfcatch type="any"> <cfcatch type="any">
<cfreturn representationOf(this.helper.formatException(cfcatch, "Internal Error")).withStatus(500)/><!--- это не нужно показывать в продуктиве ---> <cfreturn representationOf(this.helper.formatException(cfcatch, "Internal Error")).withStatus(500)/><!--- это не нужно показывать в продуктиве --->
</cfcatch> </cfcatch>
</cftry> </cftry>
<cfreturn noData().withStatus(204, "No Content") /> <cfreturn noData().withStatus(204, "No Content") />
</cffunction><!--- delete ---> </cffunction><!--- delete --->
<cffunction name="put" hint="запись CFS параметра операции инстанса"> <cffunction name="put" hint="запись CFS параметра операции инстанса">
<cfargument name="instanceOperationCfsParamUid" type="string" required=true hint="type:guid"/> <cfargument name="instanceOperationCfsParamUid" type="string" required=true hint="type:guid"/>
<cfargument name="paramValue" type="string" required=true/> <cfargument name="paramValue" type="string" required=true/>
<cfargument name="note" type="string" required=false default=""/> <cfargument name="note" type="string" required=false default=""/>
<cfset var local={}/> <cfset var local={}/>
<cftry> <cftry>
<cfset checkInstanceParam(arguments.instanceOperationCfsParamUid, arguments.paramValue, arguments.usrId)/> <cfset checkInstanceParam(arguments.instanceOperationCfsParamUid, arguments.paramValue, arguments.usrId)/>
@@ -637,7 +509,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/> <cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
</cfcatch> </cfcatch>
</cftry> </cftry>
<cfquery name="local.qSave" result="local.result"> <cfquery name="local.qSave" result="local.result">
update instance_operation_cfs_param set update instance_operation_cfs_param set
dt_created=<cfqueryparam cfsqltype="cf_sql_timestamp" value="#Now()#" /> dt_created=<cfqueryparam cfsqltype="cf_sql_timestamp" value="#Now()#" />
@@ -649,14 +520,10 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
<!--- *** проверить существование - 404 ---> <!--- *** проверить существование - 404 --->
<cfreturn noData().withStatus(204, "No Content") /> <cfreturn noData().withStatus(204, "No Content") />
</cffunction><!--- put ---> </cffunction><!--- put --->
<cffunction name="checkInstanceParam"> <cffunction name="checkInstanceParam">
<cfargument name="instanceOperationCfsParamUid" type="guid" required=true/> <cfargument name="instanceOperationCfsParamUid" type="guid" required=true/>
<cfargument name="paramValue" required=true/> <cfargument name="paramValue" required=true/>
<cfargument name="usrId" type="numeric" required=true/> <cfargument name="usrId" type="numeric" required=true/>
<cfset var local={}/> <cfset var local={}/>
<cfquery name="local.qCheck" result="local.result"> <cfquery name="local.qCheck" result="local.result">
select svc_operation_cfs_param_id select svc_operation_cfs_param_id
@@ -666,11 +533,8 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
<cfif local.qCheck.recordCount EQ 0> <cfif local.qCheck.recordCount EQ 0>
<cfthrow type="invalidParamValue" message="Cannot find CFS parameter by instanceOperationCfsParamUid=#arguments.instanceOperationCfsParamUid#"/> <cfthrow type="invalidParamValue" message="Cannot find CFS parameter by instanceOperationCfsParamUid=#arguments.instanceOperationCfsParamUid#"/>
</cfif> </cfif>
<cfset CreateObject("component", "instance_operation_cfs_param_ls").checkParam(local.qCheck.svc_operation_cfs_param_id, arguments.paramValue, arguments.usrId, arguments.instanceOperationCfsParamUid)/> <cfset CreateObject("component", "instance_operation_cfs_param_ls").checkParam(local.qCheck.svc_operation_cfs_param_id, arguments.paramValue, arguments.usrId, arguments.instanceOperationCfsParamUid)/>
</cffunction> </cffunction>
<cffunction name="processMap" returntype="void" access="public"> <cffunction name="processMap" returntype="void" access="public">
<cfargument name="qParam" type="query" required=true/><!--- работаем с текущей строкой query. передача query это скорее колхоз, всего-то надо 4 понятных аргумента. <cfargument name="qParam" type="query" required=true/><!--- работаем с текущей строкой query. передача query это скорее колхоз, всего-то надо 4 понятных аргумента.
Конечно, то, что часть из них - id, не упрощает восприяие кода ---> Конечно, то, что часть из них - id, не упрощает восприяие кода --->
@@ -678,7 +542,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
- сформировать дескриптор - сформировать дескриптор
- замаскировать секреты ---> - замаскировать секреты --->
<!--- здесь могут использоваться 2 критерия: формат аргумента, array/struct, либо тип ---> <!--- здесь могут использоваться 2 критерия: формат аргумента, array/struct, либо тип --->
<cfset local.spContainer = {}/><!--- может быть map или array of map ---> <cfset local.spContainer = {}/><!--- может быть map или array of map --->
<cfset local.spMapArray = []/> <cfset local.spMapArray = []/>
<!--- мы хотим обработать и случай array-map-fixed ---> <!--- мы хотим обработать и случай array-map-fixed --->
@@ -693,7 +556,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
<cfset local.spMapArray = [{"error":"#cfcatch.message#"}]/><!--- теряем все данные ---> <cfset local.spMapArray = [{"error":"#cfcatch.message#"}]/><!--- теряем все данные --->
</cfcatch> </cfcatch>
</cftry> </cftry>
<cfquery name="local.qSubparam"> <cfquery name="local.qSubparam">
select select
sp.svc_operation_cfs_param_id sp.svc_operation_cfs_param_id
@@ -722,8 +584,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
where sp.svc_operation_cfs_param_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.qParam.svc_operation_cfs_param_id#"/> where sp.svc_operation_cfs_param_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.qParam.svc_operation_cfs_param_id#"/>
order by sp.sort order by sp.sort
</cfquery> </cfquery>
<!--- <cfdump var=#local.qSubparam#/><cfabort/> --->
<cfquery name="local.qInstSubparam"> <cfquery name="local.qInstSubparam">
select select
sp.instance_operation_cfs_param_uid::text as instance_operation_cfs_param_uid sp.instance_operation_cfs_param_uid::text as instance_operation_cfs_param_uid
@@ -735,11 +595,9 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
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)#/> 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 order by sp.sort
</cfquery> </cfquery>
<!--- формируем дескриптор ---> <!--- формируем дескриптор --->
<cfset var mapDescriptor=structNew("linked")/> <cfset var mapDescriptor=structNew("linked")/>
<cfset var parser=createObject("component","lib.expression_parser")/> <cfset var parser=createObject("component","lib.expression_parser")/>
<cfloop query="local.qSubparam"> <cfloop query="local.qSubparam">
<cfset structInsert(mapDescriptor, local.qSubparam.svc_operation_cfs_subparam, <cfset structInsert(mapDescriptor, local.qSubparam.svc_operation_cfs_subparam,
{ {
@@ -776,12 +634,10 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
"uniqueScope":"#local.qSubparam.unique_scope#", "uniqueScope":"#local.qSubparam.unique_scope#",
"defaultCompute":"#local.qSubparam.default_compute#", "defaultCompute":"#local.qSubparam.default_compute#",
"isModifiableDefinition":false "isModifiableDefinition":false
}, true }, true
) )
/> />
</cfloop> </cfloop>
<cfloop index="local.i" from=1 to=#arrayLen(local.spMapArray)#><!--- *** искусственное оборачивание в массив вот для этого, не придумал ничего умнее <cfloop index="local.i" from=1 to=#arrayLen(local.spMapArray)#><!--- *** искусственное оборачивание в массив вот для этого, не придумал ничего умнее
чтобы не дублировать цикл по субпараметрам. Сделано некрасиво, но работать должно. чтобы не дублировать цикл по субпараметрам. Сделано некрасиво, но работать должно.
Ну а как сделать? Если массив - делать цикл по массиву, а если map-сразу обрабатыввать map. При этом запрос к таблице сабпараметров не хочется делать лишний раз. Ну а как сделать? Если массив - делать цикл по массиву, а если map-сразу обрабатыввать map. При этом запрос к таблице сабпараметров не хочется делать лишний раз.
@@ -799,7 +655,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
</cfloop> </cfloop>
</cfif> </cfif>
</cfloop> </cfloop>
<!--- *** проверку, что это не map-fixed, можно добавить здесь ---> <!--- *** проверку, что это не map-fixed, можно добавить здесь --->
<!--- чтобы не вставляли в параметр что попало ---> <!--- чтобы не вставляли в параметр что попало --->
<!--- здесь мы не делаем цикл по массиву, поскольку не поддерживаем массив расширяемых map ---> <!--- здесь мы не делаем цикл по массиву, поскольку не поддерживаем массив расширяемых map --->
@@ -818,21 +673,16 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
</cfif> </cfif>
</cfloop> </cfloop>
</cfif> </cfif>
<cfset arguments.qParam.data_descriptor = mapDescriptor/> <cfset arguments.qParam.data_descriptor = mapDescriptor/>
<cfif (arguments.qParam.data_type EQ "array-map-fixed")> <cfif (arguments.qParam.data_type EQ "array-map-fixed")>
<cfset arguments.qParam.param_value = serializeJson(local.spMapArray)/><!--- как есть ---> <cfset arguments.qParam.param_value = serializeJson(local.spMapArray)/><!--- как есть --->
<cfelse> <cfelse>
<cfset arguments.qParam.param_value = arrayLen(local.spMapArray) ? serializeJson(local.spMapArray[1]) : ""/><!--- вытаскиваем из массива-обертки ---> <cfset arguments.qParam.param_value = arrayLen(local.spMapArray) ? serializeJson(local.spMapArray[1]) : ""/><!--- вытаскиваем из массива-обертки --->
</cfif> </cfif>
</cffunction> </cffunction>
<cffunction name="generateValueList" returntype="string" access="public"> <cffunction name="generateValueList" returntype="string" access="public">
<cfargument name="functionName" type="string" required="true"/> <cfargument name="functionName" type="string" required="true"/>
<!--- остальные атрибуты необязательные, в argumentCollection (еще вопрос, насколько безопасно объявлять один из аргументов без остальных) ---> <!--- остальные атрибуты необязательные, в argumentCollection (еще вопрос, насколько безопасно объявлять один из аргументов без остальных) --->
<cfswitch expression=#arguments.functionName#> <cfswitch expression=#arguments.functionName#>
<cfcase value=""> <cfcase value="">
<cfreturn ""/> <cfreturn ""/>
@@ -848,14 +698,10 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
</cfdefaultcase> </cfdefaultcase>
</cfswitch> </cfswitch>
</cffunction> </cffunction>
<cffunction name="getAvailableResourceRealms" returnType="string" access="public"> <cffunction name="getAvailableResourceRealms" returnType="string" access="public">
<cfargument name="svcId"/> <cfargument name="svcId"/>
<cfargument name="contractId"/> <cfargument name="contractId"/>
<cfset var local={}/> <cfset var local={}/>
<cfquery name="local.qAvailableResourceRealm"><!--- *** distinct халява, но придумывать корректную формулировку времени мало ---> <cfquery name="local.qAvailableResourceRealm"><!--- *** distinct халява, но придумывать корректную формулировку времени мало --->
select distinct r.resource_realm, r.sort select distinct r.resource_realm, r.sort
from resource_realm r from resource_realm r
@@ -867,21 +713,16 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
join svc s on r.resource_realm_type_id=s.resource_realm_type_id 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)#/> where s.svc_id=<cfqueryparam cfsqltype="CF_SQL_INTEGER" value=#arguments.svcId# null=#!isValid("integer", arguments.svcId)#/>
order by r.sort, r.resource_realm order by r.sort, r.resource_realm
</cfquery> <!--- <cfdump var=#arguments#/> cfdump здесь провоцирует NPE ---> </cfquery>
<cfif local.qAvailableResourceRealm.recordCount> <cfif local.qAvailableResourceRealm.recordCount>
<cfreturn valueList(local.qAvailableResourceRealm.resource_realm)/> <cfreturn valueList(local.qAvailableResourceRealm.resource_realm)/>
<cfelse> <cfelse>
<cfreturn ""/><!--- иначе для пустого резалтсета генерируется null ---> <cfreturn ""/><!--- иначе для пустого резалтсета генерируется null --->
</cfif> </cfif>
</cffunction> </cffunction>
<!--- для вложенных справочников ---> <!--- для вложенных справочников --->
<!--- дублировано: deck-tool/instance_operation.cfm ---> <!--- дублировано: deck-tool/instance_operation.cfm --->
<cffunction name="getSelectedResourceRealm" returnType="string"> <cffunction name="getSelectedResourceRealm" returnType="string">
<cfset var local={}/> <cfset var local={}/>
<cfquery name="local.qSelectedResourceRealm"> <cfquery name="local.qSelectedResourceRealm">
select iop.param_value select iop.param_value
@@ -890,15 +731,13 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
where iop.instance_operation_uid=<cfqueryparam cfsqltype="CF_SQL_OTHER" value=#d.instance_operation_uid# null=#!isValid("guid", d.instance_operation_uid)#/> 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' AND sop.svc_operation_cfs_param='resourceRealm'
order by 1 order by 1
</cfquery> <!--- <cfdump var=#arguments#/> cfdump здесь провоцирует NPE ---> </cfquery>
<cfreturn local.qSelectedResourceRealm.param_value/> <cfreturn local.qSelectedResourceRealm.param_value/>
</cffunction> </cffunction>
<cffunction name="generateClosure" returntype="function"> <cffunction name="generateClosure" returntype="function">
<cfargument name="functionName" type="string" required="true"/> <cfargument name="functionName" type="string" required="true"/>
<cfargument name="config" type="string" required="true"/> <cfargument name="config" type="string" required="true"/>
<!--- остальные атрибуты необязательные, в argumentCollection ---> <!--- остальные атрибуты необязательные, в argumentCollection --->
<cfswitch expression=#arguments.functionName#> <cfswitch expression=#arguments.functionName#>
<cfcase value=""> <cfcase value="">
<cfreturn function(){}/> <cfreturn function(){}/>
@@ -916,19 +755,15 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
</cfdefaultcase> </cfdefaultcase>
</cfswitch> </cfswitch>
</cffunction> </cffunction>
<cffunction name="getRefFromRRealmConfig" returntype="any"> <cffunction name="getRefFromRRealmConfig" returntype="any">
<cfargument name="resourceRealm" type="string" required="true"/> <cfargument name="resourceRealm" type="string" required="true"/>
<cfargument name="config" type="string" required="true"/> <cfargument name="config" type="string" required="true"/>
<cfquery name="qResourceRealmConfig"> <cfquery name="qResourceRealmConfig">
select properties::text select properties::text
from resource_realm from resource_realm
where resource_realm='ngcloud.ru' where resource_realm='ngcloud.ru'
<!--- <cfqueryparam cfsqltype="cf_sql_varchar" value=#arguments.resourceRealm#/> --->
</cfquery> </cfquery>
<!--- паранойя... и есть шансы, что я неправильно понимаю эту химию скоупов--->
<!--- <cfset var local={}/> ---> <!--- паранойя... и есть шансы, что я неправильно понимаю эту химию скоупов--->
<cfset var props = deserializeJson(qResourceRealmConfig.properties)/> <cfset var props = deserializeJson(qResourceRealmConfig.properties)/>
<cfset var cfg = deserializeJson(arguments.config)/> <!--- удобнее было бы передавать сразу структуру впр ---> <cfset var cfg = deserializeJson(arguments.config)/> <!--- удобнее было бы передавать сразу структуру впр --->
<cfset cfg={"path":"vcd.providerVdc"}/><!--- *** временный пример для отладки ---> <cfset cfg={"path":"vcd.providerVdc"}/><!--- *** временный пример для отладки --->
@@ -940,12 +775,10 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
<cfset structInsert(result, containerName, structGet("props.#path#"))/> <cfset structInsert(result, containerName, structGet("props.#path#"))/>
<cfreturn result/> <cfreturn result/>
</cffunction> </cffunction>
<!--- duplicated in deck-tool ---> <!--- duplicated in deck-tool --->
<cffunction name="getListFromState" returntype="string" hint="returns list"> <cffunction name="getListFromState" returntype="string" hint="returns list">
<cfargument name="state" type="struct" required="true"/> <cfargument name="state" type="struct" required="true"/>
<cfargument name="path" type="string" required="true"/> <cfargument name="path" type="string" required="true"/>
<cftry> <cftry>
<cfreturn structKeyList(structGet("arguments.state.#arguments.path#"))/> <cfreturn structKeyList(structGet("arguments.state.#arguments.path#"))/>
<cfcatch type="any"> <cfcatch type="any">
@@ -954,20 +787,5 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
</cfcatch> </cfcatch>
</cftry> </cftry>
</cffunction> </cffunction>
</cfcomponent> </cfcomponent>
<!--- [{"b":"12","secret1":"preved"},{"b":"13","secret1":"preved404"},{"b":"14","secret1":"preved402"}] ---> <!--- [{"b":"12","secret1":"preved"},{"b":"13","secret1":"preved404"},{"b":"14","secret1":"preved402"}] --->
@@ -1,12 +1,8 @@
<cfcomponent extends="taffy.core.resource" taffy:uri="/instanceOperationCfsParams/{instanceOperationCfsParamUid}/subparams/{subparam}"> <cfcomponent extends="taffy.core.resource" taffy:uri="/instanceOperationCfsParams/{instanceOperationCfsParamUid}/subparams/{subparam}">
<cfsilent> <cfsilent>
<cfimport prefix="m" taglib="../lib"/> <cfimport prefix="m" taglib="../lib"/>
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/><!---*** странно, почему мы его видим?---><!---вынести в апп?---> <cfset this.helper=CreateObject("component","lib.rest_api_helper")/><!---*** странно, почему мы его видим?---><!---вынести в апп?--->
</cfsilent> </cfsilent>
<cffunction name="get" hint="Метаданные субпараметра CFS-параметра операции экземпляра (значение субпараметра находится в теле параметра)"><!--- *** спросить, может, метод не нужен, а если нужен - наверно, нужно значение ---> <cffunction name="get" hint="Метаданные субпараметра CFS-параметра операции экземпляра (значение субпараметра находится в теле параметра)"><!--- *** спросить, может, метод не нужен, а если нужен - наверно, нужно значение --->
<cfargument name="instanceOperationCfsParamUid" type="string" required=true hint="type:guid"/> <cfargument name="instanceOperationCfsParamUid" type="string" required=true hint="type:guid"/>
<cfargument name="subparam" type="string" required=true hint="type:string"/> <cfargument name="subparam" type="string" required=true hint="type:string"/>
@@ -16,9 +12,7 @@
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/> <cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
</cfcatch> </cfcatch>
</cftry> </cftry>
<cfset local={}/> <cfset local={}/>
<cfquery name="local.qRead" result="local.result"> <cfquery name="local.qRead" result="local.result">
select select
<m:field_set titleMapOut="local.titleMap" lengthOut="fieldCount"> <m:field_set titleMapOut="local.titleMap" lengthOut="fieldCount">
@@ -26,7 +20,6 @@
<m:field>ios.instance_operation_cfs_subparam</m:field> <m:field>ios.instance_operation_cfs_subparam</m:field>
<m:field formatter=#request.castToBool#>ios.is_sensitive</m:field> <m:field formatter=#request.castToBool#>ios.is_sensitive</m:field>
<m:field>ios.note</m:field> <m:field>ios.note</m:field>
<!--- <m:field>iop.data_type</m:field> --->
<m:field>to_char(ios.dt_created, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as dt_created</m:field> <m:field>to_char(ios.dt_created, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as dt_created</m:field>
</m:field_set> </m:field_set>
from instance_operation_cfs_subparam ios from instance_operation_cfs_subparam ios
@@ -38,45 +31,31 @@
AND ios.instance_operation_cfs_subparam=<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.subparam#"/> AND ios.instance_operation_cfs_subparam=<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.subparam#"/>
AND si.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/> /*tenant isolation, из конфиденциального тут заметки... может быть, имена переменных окружения*/ AND si.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/> /*tenant isolation, из конфиденциального тут заметки... может быть, имена переменных окружения*/
</cfquery> </cfquery>
<cfif local.qRead.recordCount EQ 0> <cfif local.qRead.recordCount EQ 0>
<cfreturn representationOf(this.helper.formatMessage("Not Found")).withStatus(404)/> <cfreturn representationOf(this.helper.formatMessage("Not Found")).withStatus(404)/>
</cfif> </cfif>
<!--- <cfif local.qRead.data_type NEQ 'map'>
<cfreturn representationOf(this.helper.formatMessage("Parent parameter type does not have subparameters")).withStatus(400)/>
</cfif> --->
<cfset var out=structNew("linked")/> <cfset var out=structNew("linked")/>
<cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/> <cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/>
<cfset "out.instanceOperationCfsSubparam" = this.helper.appendRecord( <cfset "out.instanceOperationCfsSubparam" = this.helper.appendRecord(
structNew("linked"), "", local.titleMap, local.qRead, this.helper.snake2camel structNew("linked"), "", local.titleMap, local.qRead, this.helper.snake2camel
)/> )/>
<cfset "out.runDurationMs"=getTickCount() - request.startTickCount/> <cfset "out.runDurationMs"=getTickCount() - request.startTickCount/>
<cfreturn representationOf(out) /> <cfreturn representationOf(out) />
</cffunction><!---/get ---> </cffunction><!---/get --->
<cffunction name="delete" hint="Удаление метаданных субпараметра CFS-параметра операции экземпляра по ключу."> <cffunction name="delete" hint="Удаление метаданных субпараметра CFS-параметра операции экземпляра по ключу.">
<cfargument name="instanceOperationCfsParamUid" type="string" required=true hint="type:guid"/> <cfargument name="instanceOperationCfsParamUid" type="string" required=true hint="type:guid"/>
<cfargument name="subparam" type="string" required=true hint="type:string"/> <cfargument name="subparam" type="string" required=true hint="type:string"/>
<cftry> <cftry>
<cfset this.helper.validateField(arguments, "instanceOperationCfsParamUid", "guid")/> <cfset this.helper.validateField(arguments, "instanceOperationCfsParamUid", "guid")/>
<cfcatch type="invalidParamValue"> <cfcatch type="invalidParamValue">
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/> <cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
</cfcatch> </cfcatch>
</cftry> </cftry>
<cfset local={}/> <cfset local={}/>
<cftry> <cftry>
<!--- проверка существования одновременно может служить для изоляции тенантов ---> <!--- проверка существования одновременно может служить для изоляции тенантов --->
<!--- без проверки стартовавшей операции ---> <!--- без проверки стартовавшей операции --->
<!--- нужна проверка на изоляцию тенантов ---> <!--- нужна проверка на изоляцию тенантов --->
<cfquery name="local.qCheckExistence" result="local.result"> <cfquery name="local.qCheckExistence" result="local.result">
select count(*) as cnt select count(*) as cnt
from instance_operation_cfs_subparam ios from instance_operation_cfs_subparam ios
@@ -86,7 +65,6 @@
<cfif local.qCheckExistence.cnt EQ 0> <cfif local.qCheckExistence.cnt EQ 0>
<cfreturn representationOf(this.helper.formatMessage("Not Found", "Subparameter specified does not exist")).withStatus(404)/> <cfreturn representationOf(this.helper.formatMessage("Not Found", "Subparameter specified does not exist")).withStatus(404)/>
</cfif> </cfif>
<cfquery name="local.qCheckAccess" result="local.result"> <cfquery name="local.qCheckAccess" result="local.result">
select count(*) as cnt select count(*) as cnt
from instance_operation_cfs_param iop from instance_operation_cfs_param iop
@@ -99,40 +77,31 @@
<cfif local.qCheckAccess.cnt EQ 0> <cfif local.qCheckAccess.cnt EQ 0>
<cfreturn representationOf(this.helper.formatMessage("Not Accessible", "CFS parameter specified is not accessible by the current user")).withStatus(403)/> <cfreturn representationOf(this.helper.formatMessage("Not Accessible", "CFS parameter specified is not accessible by the current user")).withStatus(403)/>
</cfif> </cfif>
<cfquery name="local.qSave"> <cfquery name="local.qSave">
delete from instance_operation_cfs_subparam delete from instance_operation_cfs_subparam
where instance_operation_cfs_param_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationCfsParamUid#" null=#!isValid('guid',arguments.instanceOperationCfsParamUid)#/> where instance_operation_cfs_param_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationCfsParamUid#" null=#!isValid('guid',arguments.instanceOperationCfsParamUid)#/>
AND instance_operation_cfs_subparam=<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.subparam#"/> AND instance_operation_cfs_subparam=<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.subparam#"/>
</cfquery> </cfquery>
<cfcatch type="any"> <cfcatch type="any">
<cfreturn representationOf(this.helper.formatException(cfcatch, "Internal Error")).withStatus(500)/><!--- *** это не нужно показывать в продуктиве ---> <cfreturn representationOf(this.helper.formatException(cfcatch, "Internal Error")).withStatus(500)/><!--- *** это не нужно показывать в продуктиве --->
</cfcatch> </cfcatch>
</cftry> </cftry>
<cfreturn noData().withStatus(204, "No Content") /> <cfreturn noData().withStatus(204, "No Content") />
</cffunction><!--- delete ---> </cffunction><!--- delete --->
<cffunction name="put" hint="запись метаданных субпараметра CFS-параметра операции инстанса"> <cffunction name="put" hint="запись метаданных субпараметра CFS-параметра операции инстанса">
<cfargument name="instanceOperationCfsParamUid" type="string" required=true hint="type:guid"/> <cfargument name="instanceOperationCfsParamUid" type="string" required=true hint="type:guid"/>
<cfargument name="subparam" type="string" required=true hint="type:string"/> <cfargument name="subparam" type="string" required=true hint="type:string"/>
<cfargument name="isSensitive" type="boolean" required=false default=false hint="type:boolean"/> <cfargument name="isSensitive" type="boolean" required=false default=false hint="type:boolean"/>
<cfargument name="note" type="string" required=false default=""/> <!--- *** XSS!!! ---> <cfargument name="note" type="string" required=false default=""/> <!--- *** XSS!!! --->
<cftry> <cftry>
<cfset this.helper.validateField(arguments, "instanceOperationCfsParamUid", "guid")/> <cfset this.helper.validateField(arguments, "instanceOperationCfsParamUid", "guid")/>
<cfset this.helper.validateField(arguments, "isSensitive", "boolean")/> <cfset this.helper.validateField(arguments, "isSensitive", "boolean")/>
<!--- *** Нужна проверка, что операция не была выполнена, иначе она становится архивной ---> <!--- *** Нужна проверка, что операция не была выполнена, иначе она становится архивной --->
<cfcatch type="invalidParamValue"> <cfcatch type="invalidParamValue">
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/> <cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
</cfcatch> </cfcatch>
</cftry> </cftry>
<cfset var local={}/> <cfset var local={}/>
<cfquery name="local.qCheckAccess" result="local.result"> <cfquery name="local.qCheckAccess" result="local.result">
select count(*) as cnt select count(*) as cnt
from instance_operation_cfs_param iop from instance_operation_cfs_param iop
@@ -145,7 +114,6 @@
<cfif local.qCheckAccess.cnt EQ 0> <cfif local.qCheckAccess.cnt EQ 0>
<cfreturn representationOf(this.helper.formatMessage("Not Accessible", "Instance CFS parameter not found or access denied")).withStatus(404)/> <cfreturn representationOf(this.helper.formatMessage("Not Accessible", "Instance CFS parameter not found or access denied")).withStatus(404)/>
</cfif> </cfif>
<cfquery name="local.qCheckExistence" result="local.result"> <cfquery name="local.qCheckExistence" result="local.result">
select count(*) as cnt select count(*) as cnt
from instance_operation_cfs_subparam iop from instance_operation_cfs_subparam iop
@@ -155,7 +123,6 @@
<cfif local.qCheckExistence.cnt EQ 0> <cfif local.qCheckExistence.cnt EQ 0>
<cfreturn representationOf(this.helper.formatMessage("Not Found", "Subparameter specified does not exist")).withStatus(404)/> <cfreturn representationOf(this.helper.formatMessage("Not Found", "Subparameter specified does not exist")).withStatus(404)/>
</cfif> </cfif>
<cfquery name="local.qSave" result="local.result"> <cfquery name="local.qSave" result="local.result">
update instance_operation_cfs_subparam set update instance_operation_cfs_subparam set
dt_updated=<cfqueryparam cfsqltype="cf_sql_timestamp" value="#Now()#" /> dt_updated=<cfqueryparam cfsqltype="cf_sql_timestamp" value="#Now()#" />
@@ -168,5 +135,4 @@
<!--- *** проверить существование - 404 ---> <!--- *** проверить существование - 404 --->
<cfreturn noData().withStatus(204, "No Content") /> <cfreturn noData().withStatus(204, "No Content") />
</cffunction><!--- put ---> </cffunction><!--- put --->
</cfcomponent> </cfcomponent>
@@ -1,25 +1,15 @@
<cfcomponent extends="taffy.core.resource" taffy:uri="/instanceOperationCfsParams/{instanceOperationCfsParamUid}/subparams"> <cfcomponent extends="taffy.core.resource" taffy:uri="/instanceOperationCfsParams/{instanceOperationCfsParamUid}/subparams">
<!--- забавно, что мы организуем эндпойнт коллекции только ради операции создания. Список (коллекция) отдельно не используется, а выгружается в составе более высокоуровневых сущностей ---> <!--- забавно, что мы организуем эндпойнт коллекции только ради операции создания. Список (коллекция) отдельно не используется, а выгружается в составе более высокоуровневых сущностей --->
<cfsilent> <cfsilent>
<cfimport prefix="m" taglib="../lib"/> <cfimport prefix="m" taglib="../lib"/>
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/> <cfset this.helper=CreateObject("component","lib.rest_api_helper")/>
</cfsilent> </cfsilent>
<cffunction name="post" hint="создание метаданных субпараметра CFS параметра операции инстанса"> <cffunction name="post" hint="создание метаданных субпараметра CFS параметра операции инстанса">
<cfargument name="instanceOperationCfsParamUid" type="string" required=true hint="type:guid"/> <cfargument name="instanceOperationCfsParamUid" type="string" required=true hint="type:guid"/>
<cfargument name="subparam" type="string" required=true hint="type:string"/> <cfargument name="subparam" type="string" required=true hint="type:string"/>
<cfargument name="isSensitive" type="boolean" required=false default=false hint="type:boolean"/> <cfargument name="isSensitive" type="boolean" required=false default=false hint="type:boolean"/>
<cfargument name="note" type="string" required=false default="" hint="type:string"/> <cfargument name="note" type="string" required=false default="" hint="type:string"/>
<!--- arguments.specificationId injected implicitly ---> <!--- arguments.specificationId injected implicitly --->
<!--- <cfargument name="instanceOperationCfsParamUid" type="string" required=true hint="type:guid"/>
<cfargument name="subparam" type="string" required=true hint="type:string"/>
<cfargument name="isSensitive" type="boolean" required=true/>
<cfargument name="note" type="string" required=false default=""/> --->
<cftry> <cftry>
<cfset this.helper.validateField(arguments, "instanceOperationCfsParamUid", "guid")/> <cfset this.helper.validateField(arguments, "instanceOperationCfsParamUid", "guid")/>
<cfset this.helper.validateField(arguments, "isSensitive", "boolean")/> <cfset this.helper.validateField(arguments, "isSensitive", "boolean")/>
@@ -27,9 +17,7 @@
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/> <cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
</cfcatch> </cfcatch>
</cftry> </cftry>
<cfset local={}/> <cfset local={}/>
<cfquery name="local.qCheckAccess" result="local.result"> <cfquery name="local.qCheckAccess" result="local.result">
select count(*) as cnt select count(*) as cnt
from instance_operation_cfs_param iop from instance_operation_cfs_param iop
@@ -42,7 +30,6 @@
<cfif local.qCheckAccess.cnt EQ 0> <cfif local.qCheckAccess.cnt EQ 0>
<cfreturn representationOf(this.helper.formatMessage("Instance CFS parameter not found or access denied")).withStatus(404)/> <cfreturn representationOf(this.helper.formatMessage("Instance CFS parameter not found or access denied")).withStatus(404)/>
</cfif> </cfif>
<cfquery name="local.qCheckDuplicates" result="local.result"> <cfquery name="local.qCheckDuplicates" result="local.result">
select count(*) as cnt select count(*) as cnt
from instance_operation_cfs_subparam ios from instance_operation_cfs_subparam ios
@@ -52,7 +39,6 @@
<cfif local.qCheckDuplicates.cnt GT 0> <cfif local.qCheckDuplicates.cnt GT 0>
<cfreturn representationOf(this.helper.formatMessage("Subparameter already exists")).withStatus(400)/> <cfreturn representationOf(this.helper.formatMessage("Subparameter already exists")).withStatus(400)/>
</cfif> </cfif>
<cfquery name="local.qSave" result="local.result"> <cfquery name="local.qSave" result="local.result">
insert into instance_operation_cfs_subparam insert into instance_operation_cfs_subparam
(instance_operation_cfs_param_uid, instance_operation_cfs_subparam, is_sensitive, note, dt_created, creator_id, dt_updated, updater_id) (instance_operation_cfs_param_uid, instance_operation_cfs_subparam, is_sensitive, note, dt_created, creator_id, dt_updated, updater_id)
@@ -68,14 +54,8 @@
,<cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.usrId#" /> ,<cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.usrId#" />
); );
</cfquery> </cfquery>
<cfreturn noData() <cfreturn noData()
.withStatus(201, "Created") .withStatus(201, "Created")
/> />
</cffunction><!--- get ---> </cffunction><!--- get --->
</cfcomponent> </cfcomponent>
@@ -1,28 +1,21 @@
<cfcomponent extends="taffy.core.resource" taffy:uri="/instanceOperations/{instanceUid}/{svcOperationId}" hint="template for default instance operation. Legacy URL: /instanceOperations/default/{svcOperationId}"> <cfcomponent extends="taffy.core.resource" taffy:uri="/instanceOperations/{instanceUid}/{svcOperationId}" hint="template for default instance operation. Legacy URL: /instanceOperations/default/{svcOperationId}">
<cfsilent> <cfsilent>
<cfimport prefix="m" taglib="../lib"/> <cfimport prefix="m" taglib="../lib"/>
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/> <cfset this.helper=CreateObject("component","lib.rest_api_helper")/>
</cfsilent> </cfsilent>
<cffunction name="get" hint="Шаблон операции экземпляра"> <cffunction name="get" hint="Шаблон операции экземпляра">
<cfargument name="instanceUid" type="string" required=true hint="type:guid|'default'"/> <cfargument name="instanceUid" type="string" required=true hint="type:guid|'default'"/>
<cfargument name="svcOperationId" type="string" required=true hint="type:integer"/> <cfargument name="svcOperationId" type="string" required=true hint="type:integer"/>
<cftry> <cftry>
<cfif arguments.instanceUid NEQ 'default'> <cfif arguments.instanceUid NEQ 'default'>
<cfset this.helper.validateField(arguments, "instanceUid", "guid")/> <cfset this.helper.validateField(arguments, "instanceUid", "guid")/>
</cfif> </cfif>
<cfset this.helper.validateField(arguments, "svcOperationId", "integer")/> <cfset this.helper.validateField(arguments, "svcOperationId", "integer")/>
<cfcatch type="invalidParamValue"> <cfcatch type="invalidParamValue">
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/> <cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
</cfcatch> </cfcatch>
</cftry> </cftry>
<cfset var local={}/> <cfset var local={}/>
<cfquery name="local.qSvcOperation" result="local.result"> <cfquery name="local.qSvcOperation" result="local.result">
select select
<m:field_set titleMapOut="local.titleMap" lengthOut="local.fieldCount"> <m:field_set titleMapOut="local.titleMap" lengthOut="local.fieldCount">
@@ -36,11 +29,9 @@
from svc_operation o from svc_operation o
where o.svc_operation_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.svcOperationId#" null=#!isValid('integer',arguments.svcOperationId)#/> where o.svc_operation_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.svcOperationId#" null=#!isValid('integer',arguments.svcOperationId)#/>
</cfquery> </cfquery>
<cfif local.qSvcOperation.recordCount EQ 0> <cfif local.qSvcOperation.recordCount EQ 0>
<cfreturn representationOf(this.helper.formatMessage("Not Found")).withStatus(404)/> <cfreturn representationOf(this.helper.formatMessage("Not Found")).withStatus(404)/>
</cfif> </cfif>
<!--- получаем параметры из свежего стейта ---> <!--- получаем параметры из свежего стейта --->
<cfset local.instanceDataParams = {}/> <cfset local.instanceDataParams = {}/>
<cfset var currentState = {}/> <cfset var currentState = {}/>
@@ -62,13 +53,10 @@
</cfcatch> </cfcatch>
</cftry> </cftry>
</cfif> </cfif>
<cfquery name="local.qCfsParam" result="local.result"> <cfquery name="local.qCfsParam" result="local.result">
select select
<m:field_set titleMapOut="local.cfsParamMap" lengthOut="local.fieldCount"> <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 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.svc_operation_cfs_param</m:field>
<m:field>p.label</m:field> <m:field>p.label</m:field>
<m:field>p.data_type</m:field> <m:field>p.data_type</m:field>
@@ -92,7 +80,6 @@
<m:field>p.man</m:field> <m:field>p.man</m:field>
<m:field>p.sort</m:field> <m:field>p.sort</m:field>
<m:field>p.nested_ref</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>p.config::text</m:field><!--- в таком виде конфиг доступен для кода, но не выводится в респонсе --->
<m:field>null as nested_ref_data</m:field> <m:field>null as nested_ref_data</m:field>
<m:field>p.state_path</m:field> <m:field>p.state_path</m:field>
@@ -114,8 +101,6 @@
AND p.is_actual AND p.is_actual
order by p.sort, p.svc_operation_cfs_param_id order by p.sort, p.svc_operation_cfs_param_id
</cfquery> </cfquery>
<cfloop query="local.qCfsParam"> <cfloop query="local.qCfsParam">
<cfif len(local.qCfsParam.func)><!--- приоритет отдается функции перед списком значений---> <cfif len(local.qCfsParam.func)><!--- приоритет отдается функции перед списком значений--->
<cfset var args = { <cfset var args = {
@@ -124,7 +109,6 @@
"contractId":#arguments.contractId# "contractId":#arguments.contractId#
}/> <!--- если появятся новые аргументы у новых функций, будем добавлять их сюда ---> }/> <!--- если появятся новые аргументы у новых функций, будем добавлять их сюда --->
<cfinvoke component="instance_operation_cfs_param" method="generateValueList" argumentCollection=#args# returnVariable="local.qCfsParam.value_list"/> <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> <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, но делаем это довольно часто ---> <cfset local.qCfsParam.default_value=local.qCfsParam.value_list/><!--- *** не очень красиво перетирать query, но делаем это довольно часто --->
</cfif> </cfif>
@@ -147,12 +131,10 @@
returnVariable="local.qCfsParam.value_list" returnVariable="local.qCfsParam.value_list"
/> />
</cfif> </cfif>
<cfif (len(local.qCfsParam.func) OR len(local.qCfsParam.expression) OR len(local.qCfsParam.state_path) OR len(local.qCfsParam.nested_ref)) <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> AND len(local.qCfsParam.value_list) EQ 0>
<cfset local.qCfsParam.value_list = []/> <cfset local.qCfsParam.value_list = []/>
</cfif> </cfif>
<cfif data_type EQ "map" OR data_type EQ "map-fixed" OR data_type EQ "array-map-fixed"><!--- *** частичное дублирование с instance_operation_cfs_param.processMap ---> <cfif data_type EQ "map" OR data_type EQ "map-fixed" OR data_type EQ "array-map-fixed"><!--- *** частичное дублирование с instance_operation_cfs_param.processMap --->
<!--- без полей инстанса, только шаблон ---> <!--- без полей инстанса, только шаблон --->
<cfquery name="local.qSubparam"> <cfquery name="local.qSubparam">
@@ -184,43 +166,31 @@
where sp.svc_operation_cfs_param_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#svc_operation_cfs_param_id#"/> where sp.svc_operation_cfs_param_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#svc_operation_cfs_param_id#"/>
order by sp.sort order by sp.sort
</cfquery> </cfquery>
<cfset var mapDescriptor=structNew("linked")/> <cfset var mapDescriptor=structNew("linked")/>
<!--- *** выдавать на фронт expression нам ни к чему, это временное явление ---> <!--- *** выдавать на фронт expression нам ни к чему, это временное явление --->
<cfloop query="local.qSubparam"> <cfloop query="local.qSubparam">
<cfif len(local.qSubparam.func)><!--- приоритет отдается функции перед списком значений---> <cfif len(local.qSubparam.func)><!--- приоритет отдается функции перед списком значений--->
<cfset var args = { <cfset var args = {
"functionName":"#local.qSubparam.func#", "functionName":"#local.qSubparam.func#",
"svcId":#local.qSvcOperation.svc_id#, "svcId":#local.qSvcOperation.svc_id#,
"contractId":#arguments.contractId# "contractId":#arguments.contractId#
}/> }/>
<cfinvoke component="instance_operation_cfs_param" method="generateValueList" argumentCollection=#args# returnVariable="local.qSubparam.value_list"/> <cfinvoke component="instance_operation_cfs_param" method="generateValueList" argumentCollection=#args# returnVariable="local.qSubparam.value_list"/>
<cfif len(trim(local.qSubparam.value_list)) AND listLen(local.qSubparam.value_list) EQ 1> <cfif len(trim(local.qSubparam.value_list)) AND listLen(local.qSubparam.value_list) EQ 1>
<cfset local.qSubparam.default_value=local.qSubparam.value_list/><!--- *** не очень красиво перетирать query, но делаем это довольно часто ---> <cfset local.qSubparam.default_value=local.qSubparam.value_list/><!--- *** не очень красиво перетирать query, но делаем это довольно часто --->
</cfif> </cfif>
</cfif> </cfif>
<cfif (len(local.qSubparam.func) OR len(local.qSubparam.expression) ) <cfif (len(local.qSubparam.func) OR len(local.qSubparam.expression) )
AND len(local.qSubparam.value_list) EQ 0> AND len(local.qSubparam.value_list) EQ 0>
<cfset local.qSubparam.value_list = []/> <cfset local.qSubparam.value_list = []/>
</cfif> </cfif>
<cfset var def = computeDefault(local.qSubparam.default_compute, local.qSubparam.default_value, qSvcOperation.svc_id, arguments.usrId)/> <cfset var def = computeDefault(local.qSubparam.default_compute, local.qSubparam.default_value, qSvcOperation.svc_id, arguments.usrId)/>
<!--- *** пока не пытаемся восстановить значения из стейта
<cfif len(local.qSubparam.default_value) EQ 0>
<!--- и вот наконец мы извлекаем старое значение из стейта --->
<cfset var paramName = this.helper.snake2camel(local.qSubparam.svc_operation_cfs_subparam)/> <cfset var paramName = this.helper.snake2camel(local.qSubparam.svc_operation_cfs_subparam)/>
<cfif structKeyExists(local.instanceDataParams, paramName)> <cfif structKeyExists(local.instanceDataParams, paramName)>
<cfset var oldValue = structFind(local.instanceDataParams, paramName)/> <cfset var oldValue = structFind(local.instanceDataParams, paramName)/>
<cfset def = isStruct(oldValue) ? serializeJson(oldValue) : oldValue/> <!--- потому что передаем строку, а не объект ---> <cfset def = isStruct(oldValue) ? serializeJson(oldValue) : oldValue/> <!--- потому что передаем строку, а не объект --->
</cfif> </cfif>
</cfif> ---> </cfif> --->
<cfset structInsert(mapDescriptor, local.qSubparam.svc_operation_cfs_subparam, <cfset structInsert(mapDescriptor, local.qSubparam.svc_operation_cfs_subparam,
{ {
"svcOperationCfsSubparamId":"#local.qSubparam.svc_operation_cfs_subparam_id#", "svcOperationCfsSubparamId":"#local.qSubparam.svc_operation_cfs_subparam_id#",
@@ -248,27 +218,17 @@
}, true }, true
) )
/><!--- *** вообще-то передавать в дескриптор func и default_compute не нужно, это для не забыть ---> /><!--- *** вообще-то передавать в дескриптор func и default_compute не нужно, это для не забыть --->
</cfloop> </cfloop>
<cfset local.qCfsParam.data_descriptor = mapDescriptor/> <cfset local.qCfsParam.data_descriptor = mapDescriptor/>
</cfif><!---/map ---> </cfif><!---/map --->
</cfloop> </cfloop>
<!--- <cfdump var=#local.qCfsParam# abort=true/> --->
<!--- <cfset queryDeleteColumn(local.qCfsParam, "func")/> --->
<cfset var out=structNew("linked")/> <cfset var out=structNew("linked")/>
<cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/> <cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/>
<cfset "out.svcOperation" = this.helper.appendRecord( <cfset "out.svcOperation" = this.helper.appendRecord(
structNew("linked"), "", local.titleMap, local.qSvcOperation, this.helper.snake2camel structNew("linked"), "", local.titleMap, local.qSvcOperation, this.helper.snake2camel
)/> )/>
<cfset "out.svcOperation.cfsParams"=[]/> <cfset "out.svcOperation.cfsParams"=[]/>
<!--- подставляем значение из стейта, если оно там есть (некорректно, потому что в стейте RFS параметры) ---> <!--- подставляем значение из стейта, если оно там есть (некорректно, потому что в стейте RFS параметры) --->
<cfloop query=#local.qCfsParam#> <cfloop query=#local.qCfsParam#>
<cfset local.qCfsParam.default_value = computeDefault(local.qCfsParam.default_compute, local.qCfsParam.default_value, qSvcOperation.svc_id, arguments.usrId)/><!--- *** не очень хорошо модифицировать запрос ---> <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> <cfif len(local.qCfsParam.default_value) EQ 0>
@@ -280,16 +240,11 @@
</cfif> </cfif>
</cfif> </cfif>
<cfset var rec = this.helper.appendRecord(structNew("linked"), "", local.cfsParamMap, local.qCfsParam, this.helper.snake2camel)/> <cfset var rec = this.helper.appendRecord(structNew("linked"), "", local.cfsParamMap, local.qCfsParam, this.helper.snake2camel)/>
<!--- <cfdump var=#rec# abort=true/> --->
<cfset arrayAppend(out.svcOperation.cfsParams, rec)/> <cfset arrayAppend(out.svcOperation.cfsParams, rec)/>
</cfloop> </cfloop>
<cfset "out.runDurationMs"=getTickCount() - request.startTickCount/> <cfset "out.runDurationMs"=getTickCount() - request.startTickCount/>
<cfreturn representationOf(out) /> <cfreturn representationOf(out) />
</cffunction> </cffunction>
<!--- *** выглядит ужасно, но красивый вариант не придумывается ряд месяцев ---> <!--- *** выглядит ужасно, но красивый вариант не придумывается ряд месяцев --->
<!--- *** Внимание! нужно учитывать скоуп уникальности ---> <!--- *** Внимание! нужно учитывать скоуп уникальности --->
<cffunction name="computeDefault"> <cffunction name="computeDefault">
@@ -297,7 +252,6 @@
<cfargument name="original"/> <cfargument name="original"/>
<cfargument name="service_id" type="numeric"/> <cfargument name="service_id" type="numeric"/>
<cfargument name="usr_id" type="numeric"/> <cfargument name="usr_id" type="numeric"/>
<cfswitch expression=#arguments.defaultCompute#> <cfswitch expression=#arguments.defaultCompute#>
<cfcase value="display_name"> <cfcase value="display_name">
<cfset var dnGenerator = CreateObject("component", "instance_ls")/> <cfset var dnGenerator = CreateObject("component", "instance_ls")/>
@@ -316,7 +270,5 @@
<cfreturn #arguments.original#/> <cfreturn #arguments.original#/>
</cfdefaultcase> </cfdefaultcase>
</cfswitch> </cfswitch>
</cffunction> </cffunction>
</cfcomponent> </cfcomponent>
+1 -50
View File
@@ -1,10 +1,8 @@
<cfcomponent extends="taffy.core.resource" taffy:uri="/instanceOperations"> <cfcomponent extends="taffy.core.resource" taffy:uri="/instanceOperations">
<cfsilent> <cfsilent>
<cfimport prefix="m" taglib="../lib"/> <cfimport prefix="m" taglib="../lib"/>
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/> <cfset this.helper=CreateObject("component","lib.rest_api_helper")/>
</cfsilent> </cfsilent>
<!---спецификация полей, пригодных для фильтрации (и сортировки)---> <!---спецификация полей, пригодных для фильтрации (и сортировки)--->
<cfset this.fieldsSpec = { <cfset this.fieldsSpec = {
"instance_operation_uid"={prefix="o", type="guid"}, "instance_operation_uid"={prefix="o", type="guid"},
@@ -31,27 +29,18 @@
"note"={prefix="o", type="string"}, "note"={prefix="o", type="string"},
"duration"={expression="extract('epoch' from coalesce(o.dt_finish,CURRENT_TIMESTAMP)- o.dt_start)", type="numeric"} "duration"={expression="extract('epoch' from coalesce(o.dt_finish,CURRENT_TIMESTAMP)- o.dt_start)", type="numeric"}
}/> }/>
<!--- <cffunction name="post" hint="Создание новой операции с параметрами. Принимаются CFS параметры, генерируются RFS параметры. Запускается операция отдельным вызовом. До запуска CFS параметры могут корректироваться (а надо?). Запущенная операция навсегда становится Read Only (при желании можем реализовать ее клонирование). Можем реализовать корректировку параметров, но непонятно, зачем. Когда мы конфигурируем инстанс, на самом деле мы задаем CFS параметры операции create. Можно править параметры, а можно пересоздать операцию с новыми параметрами. Предусмотреть удаление (метод DELETE) незапущенной операции?"> --->
<cffunction name="get" hint="Список операций"> <cffunction name="get" hint="Список операций">
<cfargument name="pageSize" type="string" hint="type:integer" default="100"/> <cfargument name="pageSize" type="string" hint="type:integer" default="100"/>
<cfargument name="page" type="string" hint="type:integer" default="1"/> <cfargument name="page" type="string" hint="type:integer" default="1"/>
<cfargument name="orderBy" type="string" hint="type:string, description:comma-separated list of fields to sort by, example:fld1.ASC,fld2.DESC,fld3.ASC" default=""/> <cfargument name="orderBy" type="string" hint="type:string, description:comma-separated list of fields to sort by, example:fld1.ASC,fld2.DESC,fld3.ASC" default=""/>
<cfset var local={}/> <cfset var local={}/>
<cftry> <cftry>
<!---разбор и проверка параметров запроса---> <!---разбор и проверка параметров запроса--->
<cftry> <cftry>
<cfset this.helper.validateField(arguments, "pageSize", "integer")/> <cfset this.helper.validateField(arguments, "pageSize", "integer")/>
<cfset this.helper.validateField(arguments, "page", "integer")/> <cfset this.helper.validateField(arguments, "page", "integer")/>
<!---мы мирно игнорируем поля, отсутствующие в спецификации, что позволяет не делать исключения для orderBy и т.п.---> <!---мы мирно игнорируем поля, отсутствующие в спецификации, что позволяет не делать исключения для orderBy и т.п.--->
<cfset var filter=this.helper.parseFilterParams(this.fieldsSpec)/> <cfset var filter=this.helper.parseFilterParams(this.fieldsSpec)/>
<cfcatch type="invalidParamValue"> <cfcatch type="invalidParamValue">
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/> <cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
</cfcatch> </cfcatch>
@@ -59,8 +48,6 @@
<cfreturn representationOf(cfcatch)/> <cfreturn representationOf(cfcatch)/>
</cfcatch> </cfcatch>
</cftry> </cftry>
<cfquery name="local.qRead" result="local.result"> <cfquery name="local.qRead" result="local.result">
select select
<m:field_set titleMapOut="local.titleMap" lengthOut="local.fieldCount"> <m:field_set titleMapOut="local.titleMap" lengthOut="local.fieldCount">
@@ -112,7 +99,6 @@
offset #arguments.pageSize*(arguments.page-1)# offset #arguments.pageSize*(arguments.page-1)#
</cfif> </cfif>
</cfquery> </cfquery>
<cfquery name="local.qCnt"> <cfquery name="local.qCnt">
select count(*) as cnt select count(*) as cnt
#local.fromClause# #local.fromClause#
@@ -120,60 +106,43 @@
s.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/> s.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/>
<m:filter_build filter=#filter#/> <m:filter_build filter=#filter#/>
</cfquery> </cfquery>
<cfquery name="local.qTotal"> <cfquery name="local.qTotal">
select count(*) as cnt select count(*) as cnt
#local.fromClause# #local.fromClause#
<!--- from instance_operation o
join instance e on (o.instance_uid=e.instance_uid)
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) --->
where where
s.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/> s.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/>
</cfquery> </cfquery>
<cfset var out=structNew("linked")/> <cfset var out=structNew("linked")/>
<cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/> <cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/>
<cfset "out.total"=#local.qTotal.cnt#/> <cfset "out.total"=#local.qTotal.cnt#/>
<cfset "out.resultSetSize"=#local.qCnt.cnt#/> <cfset "out.resultSetSize"=#local.qCnt.cnt#/>
<cfset "out.pageSize"=#arguments.pageSize*1#/> <cfset "out.pageSize"=#arguments.pageSize*1#/>
<cfset "out.page"=#arguments.page*1#/> <cfset "out.page"=#arguments.page*1#/>
<cfset "out.orderBy"=#arguments.orderBy#/> <cfset "out.orderBy"=#arguments.orderBy#/>
<cfset var resultCollection=[]/> <cfset var resultCollection=[]/>
<cfloop query=#local.qRead#> <cfloop query=#local.qRead#>
<cfset var rec=structNew("linked")/> <cfset var rec=structNew("linked")/>
<cfset this.helper.appendRecord(rec, "", local.titleMap, local.qRead, this.helper.snake2camel)/> <cfset this.helper.appendRecord(rec, "", local.titleMap, local.qRead, this.helper.snake2camel)/>
<cfset arrayAppend(resultCollection, rec)/> <cfset arrayAppend(resultCollection, rec)/>
</cfloop> </cfloop>
<cfset "out.size"=#arrayLen(resultCollection)#/> <cfset "out.size"=#arrayLen(resultCollection)#/>
<cfset "out.results"=#resultCollection#/> <cfset "out.results"=#resultCollection#/>
<cfset "out.runDurationMs"=getTickCount()-request.startTickCount/> <cfset "out.runDurationMs"=getTickCount()-request.startTickCount/>
<cfreturn representationOf(out)/> <cfreturn representationOf(out)/>
<cfcatch type="any"> <cfcatch type="any">
<cfreturn representationOf(cfcatch)/> <cfreturn representationOf(cfcatch)/>
</cfcatch> </cfcatch>
</cftry> </cftry>
</cffunction> </cffunction>
<cffunction name="post" hint="Создание новой операции. Отдельно загружаются CFS параметры, генерируются RFS параметры. Запускается операция отдельным вызовом. До запуска CFS параметры могут корректироваться (а надо?). Запущенная операция вместе с параметрами навсегда становится Read Only (при желании можем реализовать ее клонирование). Можем реализовать корректировку параметров, но непонятно, зачем. Когда мы конфигурируем инстанс, на самом деле мы задаем CFS параметры операции create. Можно править параметры, а можно пересоздать операцию с новыми параметрами. Предусмотреть удаление (метод DELETE) незапущенной операции?"> <cffunction name="post" hint="Создание новой операции. Отдельно загружаются CFS параметры, генерируются RFS параметры. Запускается операция отдельным вызовом. До запуска CFS параметры могут корректироваться (а надо?). Запущенная операция вместе с параметрами навсегда становится Read Only (при желании можем реализовать ее клонирование). Можем реализовать корректировку параметров, но непонятно, зачем. Когда мы конфигурируем инстанс, на самом деле мы задаем CFS параметры операции create. Можно править параметры, а можно пересоздать операцию с новыми параметрами. Предусмотреть удаление (метод DELETE) незапущенной операции?">
<cfargument name="instanceUid" type="string" required=true hint="type:guid"/> <cfargument name="instanceUid" type="string" required=true hint="type:guid"/>
<cfargument name="operation" type="string" required=true hint="type:string decsiption: operation name, e.g. create"/> <cfargument name="operation" type="string" required=true hint="type:string decsiption: operation name, e.g. create"/>
<cfargument name="note" type="string" required=false default="" hint="type:string decsiption: user notes"/> <cfargument name="note" type="string" required=false default="" hint="type:string decsiption: user notes"/>
<!--- <cfargument name="resourceRealmId" type="string" default=-1 hint="type:integer decsiption: идентификатор ресурсной платформы"/> ---><!--- *** ---> <!--- *** --->
<!--- *** полноценная валидация операции предполагает проверку, что операция поддерживается для данного сервиса и текущего состояния инстанса. Можно представить себе зависимость этого от параметров, но хотелось бы избежать такого усложнения ---> <!--- *** полноценная валидация операции предполагает проверку, что операция поддерживается для данного сервиса и текущего состояния инстанса. Можно представить себе зависимость этого от параметров, но хотелось бы избежать такого усложнения --->
<!--- Можно отметить, что, например, допустимость операции delete зависит от контекста - сколько времени сервис остановлен ---> <!--- Можно отметить, что, например, допустимость операции delete зависит от контекста - сколько времени сервис остановлен --->
<cftry> <cftry>
<cfset this.helper.validateField(arguments, "instanceUid", "guid")/> <cfset this.helper.validateField(arguments, "instanceUid", "guid")/>
<cfquery name="local.qCheckOperation" result="local.result"> <cfquery name="local.qCheckOperation" result="local.result">
select count(*) as cnt select count(*) as cnt
from svc_operation so from svc_operation so
@@ -185,7 +154,6 @@
<cfif local.qCheckOperation.cnt EQ 0> <cfif local.qCheckOperation.cnt EQ 0>
<cfthrow type="invalidParamValue" message="Operation unsupported for this service/instance" detail="#arguments.operation#"/> <cfthrow type="invalidParamValue" message="Operation unsupported for this service/instance" detail="#arguments.operation#"/>
</cfif> </cfif>
<cfquery name="local.qCheckAccess" result="local.result"> <cfquery name="local.qCheckAccess" result="local.result">
select count(*) as cnt select count(*) as cnt
from instance e from instance e
@@ -199,19 +167,12 @@
</cfif> </cfif>
<!--- *** Добавить проверку разрешенных переходов, например, create нельзя сделать на развернутом экземпляре <!--- *** Добавить проверку разрешенных переходов, например, create нельзя сделать на развернутом экземпляре
*** Вероятно, допустимые переходы нужно либо специфицировать в документации, либо явно опубликовать (инстанс может публиковать список допустимых операций) ---> *** Вероятно, допустимые переходы нужно либо специфицировать в документации, либо явно опубликовать (инстанс может публиковать список допустимых операций) --->
<!--- <cfif listFind("create,redeploy",arguments.operation)>
<cfset checkResourceRealmId(arguments.resourceRealmId, arguments.instanceUid)/>
</cfif> --->
<cfcatch type="invalidParamValue"> <cfcatch type="invalidParamValue">
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/> <cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
</cfcatch> </cfcatch>
</cftry> </cftry>
<cfset local={}/> <cfset local={}/>
<cfset local.instanceOperationUid=#createGUID()#/> <cfset local.instanceOperationUid=#createGUID()#/>
<cftry> <cftry>
<cfquery name="local.qSave"> <cfquery name="local.qSave">
insert into instance_operation insert into instance_operation
@@ -228,30 +189,24 @@
,<cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.usrId#" /> ,<cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.usrId#" />
); );
</cfquery> </cfquery>
<cfcatch type="any"> <cfcatch type="any">
<cfreturn representationOf(this.helper.formatException(cfcatch, "Internal Error")).withStatus(500)/><!--- это не нужно показывать в продуктиве ---> <cfreturn representationOf(this.helper.formatException(cfcatch, "Internal Error")).withStatus(500)/><!--- это не нужно показывать в продуктиве --->
</cfcatch> </cfcatch>
</cftry> </cftry>
<cfreturn noData() <cfreturn noData()
.withHeaders({location: "./#local.instanceOperationUid#"}) .withHeaders({location: "./#local.instanceOperationUid#"})
.withStatus(201, "Created") .withStatus(201, "Created")
/> />
</cffunction> </cffunction>
<!--- *** NOT USED ---> <!--- *** NOT USED --->
<cffunction name="checkResourceRealmId" returntype="void" hint="deprecated"> <cffunction name="checkResourceRealmId" returntype="void" hint="deprecated">
<!--- В данном случае мы проверяем соответствие платформы сервису, а не операции, поэтому вопрос, нужен ли для данной операции параметр resourceRealm, надо решать вне этой функции ---> <!--- В данном случае мы проверяем соответствие платформы сервису, а не операции, поэтому вопрос, нужен ли для данной операции параметр resourceRealm, надо решать вне этой функции --->
<cfargument name="resourceRealmId" type="numeric" required=true/> <cfargument name="resourceRealmId" type="numeric" required=true/>
<cfargument name="instanceUid" type="guid" required=true/> <cfargument name="instanceUid" type="guid" required=true/>
<cfset var local={}/> <cfset var local={}/>
<cfif NOT resourceRealmId GT 0> <cfif NOT resourceRealmId GT 0>
<cfthrow type="InvalidParamValue" message="Resource realm undefined" detail="Не выбрана ресурсная платформа"/><!--- *** для многих операций она и не нужна ---> <cfthrow type="InvalidParamValue" message="Resource realm undefined" detail="Не выбрана ресурсная платформа"/><!--- *** для многих операций она и не нужна --->
</cfif> </cfif>
<cfquery name="local.qContract"> <cfquery name="local.qContract">
select c.contract_id select c.contract_id
from instance e from instance e
@@ -260,7 +215,6 @@
join contract c on (s.contract_id=c.contract_id) join contract c on (s.contract_id=c.contract_id)
where e.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceUid#" null=#!isValid("guid",arguments.instanceUid)#/> where e.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceUid#" null=#!isValid("guid",arguments.instanceUid)#/>
</cfquery> </cfquery>
<cfquery name="local.qCheckResourceRealmType"> <cfquery name="local.qCheckResourceRealmType">
select r.resource_realm_type_id select r.resource_realm_type_id
from resource_realm r from resource_realm r
@@ -273,7 +227,6 @@
<cfif local.qCheckResourceRealmType.recordCount EQ 0> <cfif local.qCheckResourceRealmType.recordCount EQ 0>
<cfthrow type="InvalidParamValue" message="Resource realm does not match service" detail="Ресурсная платформа не соответствует сервису"/> <cfthrow type="InvalidParamValue" message="Resource realm does not match service" detail="Ресурсная платформа не соответствует сервису"/>
</cfif> </cfif>
<cfquery name="local.qCheckResourceRealmAccess"> <cfquery name="local.qCheckResourceRealmAccess">
select r.resource_realm_id select r.resource_realm_id
from resource_realm r from resource_realm r
@@ -283,7 +236,6 @@
OR a.contract_id=0) OR a.contract_id=0)
AND a.is_enabled AND a.is_enabled
</cfquery> </cfquery>
<cfif local.qCheckResourceRealmAccess.recordCount EQ 0> <cfif local.qCheckResourceRealmAccess.recordCount EQ 0>
<cfthrow type="InvalidParamValue" message="Access to the resource realm denied for current contract" detail="У текущего договора id=#local.qContract.contract_id# нет доступа к выбранной ресурсной платформе"/> <cfthrow type="InvalidParamValue" message="Access to the resource realm denied for current contract" detail="У текущего договора id=#local.qContract.contract_id# нет доступа к выбранной ресурсной платформе"/>
</cfif> </cfif>
@@ -297,5 +249,4 @@
---> --->
<cfreturn/> <cfreturn/>
</cffunction> </cffunction>
</cfcomponent> </cfcomponent>
@@ -1,24 +1,15 @@
<cfcomponent extends="taffy.core.resource" taffy:uri="/instanceOperations/{instanceOperationUid}/validate-cfs"> <cfcomponent extends="taffy.core.resource" taffy:uri="/instanceOperations/{instanceOperationUid}/validate-cfs">
<cfsilent> <cfsilent>
<cfimport prefix="m" taglib="../lib"/> <cfimport prefix="m" taglib="../lib"/>
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/><!---*** странно, почему мы его видим?---><!---вынести в апп?---> <cfset this.helper=CreateObject("component","lib.rest_api_helper")/><!---*** странно, почему мы его видим?---><!---вынести в апп?--->
</cfsilent> </cfsilent>
<cffunction name="get" hint="Проверка корректности CFS"> <cffunction name="get" hint="Проверка корректности CFS">
<cfargument name="instanceOperationUid" type="string" required=true hint="type:guid"/> <cfargument name="instanceOperationUid" type="string" required=true hint="type:guid"/>
<!--- <cfset var local={}/> --->
<!--- *** мы не проверяем доступ к инстансу и существование инстанса 2DO ---> <!--- *** мы не проверяем доступ к инстансу и существование инстанса 2DO --->
<cfset var validationMessage = createObject("component","instance_operation").validateCfsParams(arguments.instanceOperationUid)/> <cfset var validationMessage = createObject("component","instance_operation").validateCfsParams(arguments.instanceOperationUid)/>
<cfif len(validationMessage)> <cfif len(validationMessage)>
<cfreturn representationOf(this.helper.formatMessage("Inconsistent CFS parameters", #validationMessage#)).withStatus(422)/> <cfreturn representationOf(this.helper.formatMessage("Inconsistent CFS parameters", #validationMessage#)).withStatus(422)/>
</cfif> </cfif>
<cfreturn noData().withStatus(204, "OK") /> <cfreturn noData().withStatus(204, "OK") />
</cffunction> </cffunction>
</cfcomponent> </cfcomponent>
-18
View File
@@ -1,11 +1,8 @@
<cfcomponent extends="taffy.core.resource" taffy:uri="/services/{svcId}"> <cfcomponent extends="taffy.core.resource" taffy:uri="/services/{svcId}">
<cfsilent> <cfsilent>
<cfimport prefix="m" taglib="../lib"/> <cfimport prefix="m" taglib="../lib"/>
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/> <cfset this.helper=CreateObject("component","lib.rest_api_helper")/>
</cfsilent> </cfsilent>
<cffunction name="get" hint="Сервис"><!--- *** TODO проверка принадлежности тенанту ---> <cffunction name="get" hint="Сервис"><!--- *** TODO проверка принадлежности тенанту --->
<cfargument name="svcId" type="string" required=true hint="type:integer"/> <cfargument name="svcId" type="string" required=true hint="type:integer"/>
<cftry> <cftry>
@@ -14,10 +11,6 @@
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/> <cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
</cfcatch> </cfcatch>
</cftry> </cftry>
<!--- <cfdump var=#arguments#/> <cfabort/> --->
<cfquery name="local.qSvc" result="local.result"> <cfquery name="local.qSvc" result="local.result">
select select
<m:field_set titleMapOut="local.titleMap" lengthOut="local.fieldCount"> <m:field_set titleMapOut="local.titleMap" lengthOut="local.fieldCount">
@@ -37,7 +30,6 @@
from svc s from svc s
where svc_id=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.svcId#" null=#!isValid('integer',arguments.svcId)#/> where svc_id=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.svcId#" null=#!isValid('integer',arguments.svcId)#/>
</cfquery> </cfquery>
<cfquery name="local.qSvcOperation" result="local.result"> <cfquery name="local.qSvcOperation" result="local.result">
select select
<m:field_set titleMapOut="local.operationsMap" lengthOut="local.fieldCount"> <m:field_set titleMapOut="local.operationsMap" lengthOut="local.fieldCount">
@@ -50,29 +42,19 @@
from svc_operation j from svc_operation j
where j.svc_id=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.svcId#" null=#!isValid('integer',arguments.svcId)#/> where j.svc_id=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.svcId#" null=#!isValid('integer',arguments.svcId)#/>
</cfquery> </cfquery>
<cfif local.qSvc.recordCount EQ 0> <cfif local.qSvc.recordCount EQ 0>
<cfreturn representationOf(this.helper.formatMessage("Not Found")).withStatus(404)/> <cfreturn representationOf(this.helper.formatMessage("Not Found")).withStatus(404)/>
</cfif> </cfif>
<cfset var out=structNew("linked")/> <cfset var out=structNew("linked")/>
<cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/> <cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/>
<!--- <cfset var rec={}/>
<cfset this.helper.appendRecord(rec, "", local.titleMap, local.qSvc, this.helper.snake2camel)/>
<cfset "out.svc"=rec/> --->
<cfset "out.svc" = this.helper.appendRecord( <cfset "out.svc" = this.helper.appendRecord(
structNew("linked"), "", local.titleMap, local.qSvc, this.helper.snake2camel structNew("linked"), "", local.titleMap, local.qSvc, this.helper.snake2camel
)/> )/>
<cfset "out.svc.operations"=[]/> <cfset "out.svc.operations"=[]/>
<cfloop query=#local.qSvcOperation#> <cfloop query=#local.qSvcOperation#>
<cfset arrayAppend(out.svc.operations, this.helper.appendRecord(structNew("linked"), "", local.operationsMap, local.qSvcOperation, this.helper.snake2camel))/> <cfset arrayAppend(out.svc.operations, this.helper.appendRecord(structNew("linked"), "", local.operationsMap, local.qSvcOperation, this.helper.snake2camel))/>
</cfloop> </cfloop>
<cfset "out.runDurationMs"=getTickCount() - request.startTickCount/> <cfset "out.runDurationMs"=getTickCount() - request.startTickCount/>
<cfreturn representationOf(out) /> <cfreturn representationOf(out) />
</cffunction> </cffunction>
</cfcomponent> </cfcomponent>
+3 -52
View File
@@ -1,12 +1,9 @@
<cfcomponent extends="taffy.core.resource" taffy:uri="/servicesGrouped"> <cfcomponent extends="taffy.core.resource" taffy:uri="/servicesGrouped">
<!--- Внимание! Дублирование семантики с svc_ls (как правило, вносить изменения параллельно ---> <!--- Внимание! Дублирование семантики с svc_ls (как правило, вносить изменения параллельно --->
<cfsilent> <cfsilent>
<cfimport prefix="m" taglib="../lib"/> <cfimport prefix="m" taglib="../lib"/>
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/><!---*** странно, почему мы его видим?---><!---вынести в апп?---> <cfset this.helper=CreateObject("component","lib.rest_api_helper")/><!---*** странно, почему мы его видим?---><!---вынести в апп?--->
</cfsilent> </cfsilent>
<!---спецификация полей, пригодных для фильтрации (?и сортировки)---> <!---спецификация полей, пригодных для фильтрации (?и сортировки)--->
<cfset this.fieldsSpec={ <cfset this.fieldsSpec={
dt_created={prefix="s", type="date"}, dt_created={prefix="s", type="date"},
@@ -28,41 +25,26 @@
resource_realm_cnt={type="integer"} resource_realm_cnt={type="integer"}
} }
/> />
<cffunction name="get" hint="Список сервисов с группами для каталога. Без управления страницами и сортировкой (сортировка по порядку группы, сервисы вне групп в конце списка). Если сервис входит в несколько групп, он будет повторяться"> <cffunction name="get" hint="Список сервисов с группами для каталога. Без управления страницами и сортировкой (сортировка по порядку группы, сервисы вне групп в конце списка). Если сервис входит в несколько групп, он будет повторяться">
<!--- <cfargument name="pageSize" type="string" hint="type:integer" default=500/>
<cfargument name="page" type="string" hint="type:integer" default="1"/>
<cfargument name="orderBy" type="string" hint="type:string, description:comma-separated list of fields to sort by, example:fld1.ASC,fld2.DESC,fld3.ASC" default=""/> --->
<cfset var local={}/> <cfset var local={}/>
<!---parse and validate request parameters---> <!---parse and validate request parameters--->
<cftry> <cftry>
<!--- <cfset this.helper.validateField(arguments, "pageSize", "integer")/>
<cfset this.helper.validateField(arguments, "page", "integer")/> --->
<!---мы мирно игнорируем поля, отсутствующие в спецификации, что позволяет не делать исключения для orderBy и т.п.---> <!---мы мирно игнорируем поля, отсутствующие в спецификации, что позволяет не делать исключения для orderBy и т.п.--->
<cfset var filter=this.helper.parseFilterParams(this.fieldsSpec)/> <cfset var filter=this.helper.parseFilterParams(this.fieldsSpec)/>
<!--- <cfset var order=this.helper.parseOrderBy(this.fieldsSpec, arguments.orderBy)/> ---> <cfcatch type="invalidParamValue">
<cfcatch type="invalidParamValue"><!--- <cfreturn representationOf("Проверка связи 3")> --->
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/> <cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
</cfcatch> </cfcatch>
<cfcatch type="any"> <cfcatch type="any">
<cfreturn representationOf(cfcatch)/> <cfreturn representationOf(cfcatch)/>
</cfcatch> </cfcatch>
</cftry> </cftry>
<cfset var out=structNew("linked")/> <cfset var out=structNew("linked")/>
<!--- <cfset var maxrows=arguments.pageSize*arguments.page/>
<cfset var startrow=arguments.pageSize*(arguments.page-1)+1/> --->
<cfquery name="local.qRead" result="local.result"> <cfquery name="local.qRead" result="local.result">
select select
<m:field_set titleMapOut="local.titleMap" lengthOut="local.fieldCount"> <m:field_set titleMapOut="local.titleMap" lengthOut="local.fieldCount">
<m:field title="ID" cfSqlType="CF_SQL_INTEGER">s.svc_id</m:field> <m:field title="ID" cfSqlType="CF_SQL_INTEGER">s.svc_id</m:field>
<m:field title="Сервис">s.svc</m:field> <m:field title="Сервис">s.svc</m:field>
<m:field title="Сокращение">s.svc_short</m:field> <m:field title="Сокращение">s.svc_short</m:field>
<!--- <m:field>s.orchestrator_name</m:field> --->
<m:field title="Код">s.code</m:field> <m:field title="Код">s.code</m:field>
<m:field title="URL создания">(select url from svc_operation so where so.operation='create' AND so.svc_id=s.svc_id limit 1) as create_url</m:field> <m:field title="URL создания">(select url from svc_operation so where so.operation='create' AND so.svc_id=s.svc_id limit 1) as create_url</m:field>
<m:field formatter=#function(x){return x NEQ 0}#>s.is_production_ready</m:field> <m:field formatter=#function(x){return x NEQ 0}#>s.is_production_ready</m:field>
@@ -98,72 +80,41 @@
) )
where 1=1 <m:filter_build filter=#filter#/> where 1=1 <m:filter_build filter=#filter#/>
order by g.sort, g.svc_group_id order by g.sort, g.svc_group_id
<!--- <m:order_build sortCollection=#this.helper.parseNumericOrder(local.titleMap, arguments.orderBy)# fieldCount=0/><!---no sort --->length limit---> length limit--->
<!--- limit #maxrows# ---> <!--- limit #maxrows# --->
</cfquery> </cfquery>
<!--- <cftry>
<cfquery name="local.qTotal">
select count(*) as cnt
from svc
where 1=1
</cfquery>
<cfcatch type="any">
<cfreturn representationOf(cfcatch)/>
</cfcatch>
</cftry> --->
<!--- <cfdump var=#qRead#/><cfabort/> --->
<cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/> <cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/>
<!--- <cfset "out.total"=#local.qTotal.cnt#/> --->
<cfset "out.resultSetSize"=#local.qRead.recordCount#/> <cfset "out.resultSetSize"=#local.qRead.recordCount#/>
<!--- <cfset "out.pageSize"=#arguments.pageSize*1#/>
<cfset "out.page"=#arguments.page*1#/>
<cfset "out.orderBy"=#arguments.orderBy#/> --->
<cfset var resultCollection=[]/> <cfset var resultCollection=[]/>
<cfset var svcMap = structCopy(local.titleMap)/><!--- ради аккуратности, дальше local.titleMap все равно не используем ---> <cfset var svcMap = structCopy(local.titleMap)/><!--- ради аккуратности, дальше local.titleMap все равно не используем --->
<cfset var groupMap = withdrawStructKeys(svcMap, "svc_group_id,svc_group")/> <cfset var groupMap = withdrawStructKeys(svcMap, "svc_group_id,svc_group")/>
<cfloop query=#local.qRead# group="svc_group_id"<!--- startRow=#startrow# endRow=#(startrow+maxrows-1)# --->> <cfloop query=#local.qRead# group="svc_group_id"<!--- startRow=#startrow# endRow=#(startrow+maxrows-1)# --->>
<cfset var grp = structNew("linked")/> <cfset var grp = structNew("linked")/>
<cfset this.helper.appendRecord(grp, "", groupMap, local.qRead, this.helper.snake2camel)/> <cfset this.helper.appendRecord(grp, "", groupMap, local.qRead, this.helper.snake2camel)/>
<cfset "grp.services"=[]/> <cfset "grp.services"=[]/>
<cfset var svcRec = structNew("linked")/> <cfset var svcRec = structNew("linked")/>
<cfloop> <cfloop>
<cfset this.helper.appendRecord(svcRec, "", svcMap, local.qRead, this.helper.snake2camel)/> <cfset this.helper.appendRecord(svcRec, "", svcMap, local.qRead, this.helper.snake2camel)/>
<cfset arrayAppend(grp.services, structCopy(svcRec))/> <cfset arrayAppend(grp.services, structCopy(svcRec))/>
<!--- <cfdump var=#svcRec#/> --->
</cfloop> </cfloop>
<cfset arrayAppend(resultCollection, structCopy(grp))/>почему-то здесь работает без structCopy <cfset arrayAppend(resultCollection, structCopy(grp))/>почему-то здесь работает без structCopy
</cfloop> </cfloop>
<cfset "out.size"=#arrayLen(resultCollection)#/> <cfset "out.size"=#arrayLen(resultCollection)#/>
<cfset "out.results"=#resultCollection#/> <cfset "out.results"=#resultCollection#/>
<cfset "out.runDurationMs"=getTickCount()-request.startTickCount/> <!--- <cfabort/> ---> <cfset "out.runDurationMs"=getTickCount()-request.startTickCount/>
<!---<cfset "out.sql"=#local.result.sql#/>--->
<cfreturn representationOf(out)/> <cfreturn representationOf(out)/>
</cffunction> </cffunction>
<cffunction name="withdrawStructKeys" access="private" returntype="struct"> <cffunction name="withdrawStructKeys" access="private" returntype="struct">
<!--- переносим ключи из входной структуры в возвращаемую (во входной удаляем) ---> <!--- переносим ключи из входной структуры в возвращаемую (во входной удаляем) --->
<cfargument name="structFrom" type="struct"/> <cfargument name="structFrom" type="struct"/>
<cfargument name="keyList" type="string"/> <cfargument name="keyList" type="string"/>
<cfset var structOut = {}/> <cfset var structOut = {}/>
<cfloop list=#arguments.keyList# item="key"> <cfloop list=#arguments.keyList# item="key">
<cfif structKeyExists(arguments.structFrom, key)> <cfif structKeyExists(arguments.structFrom, key)>
<cfset structInsert(structOut, key, structFind(structFrom, key))/> <cfset structInsert(structOut, key, structFind(structFrom, key))/>
<cfset structDelete(arguments.structFrom, key)/> <cfset structDelete(arguments.structFrom, key)/>
</cfif> </cfif>
</cfloop> </cfloop>
<cfreturn structOut/> <cfreturn structOut/>
</cffunction> </cffunction>
</cfcomponent> </cfcomponent>
+1 -39
View File
@@ -1,10 +1,8 @@
<cfcomponent extends="taffy.core.resource" taffy:uri="/services"> <cfcomponent extends="taffy.core.resource" taffy:uri="/services">
<cfsilent> <cfsilent>
<cfimport prefix="m" taglib="../lib"/> <cfimport prefix="m" taglib="../lib"/>
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/><!---*** странно, почему мы его видим?---><!---вынести в апп?---> <cfset this.helper=CreateObject("component","lib.rest_api_helper")/><!---*** странно, почему мы его видим?---><!---вынести в апп?--->
</cfsilent> </cfsilent>
<!---спецификация полей, пригодных для фильтрации (?и сортировки)---> <!---спецификация полей, пригодных для фильтрации (?и сортировки)--->
<!---здесь для простоты без префикса, потому что мы используем вложенный селект, чтобы сделать композитное поле---> <!---здесь для простоты без префикса, потому что мы используем вложенный селект, чтобы сделать композитное поле--->
<cfset this.fieldsSpec={ <cfset this.fieldsSpec={
@@ -27,7 +25,6 @@
"resource_realm_cnt"={prefix="sv", type="integer"} "resource_realm_cnt"={prefix="sv", type="integer"}
} }
/> />
<!--- *** пока сортировка, пагинация и состав полей компонуются так, что приходится добавлять поле сортировки в резалтсет ---> <!--- *** пока сортировка, пагинация и состав полей компонуются так, что приходится добавлять поле сортировки в резалтсет --->
<cffunction name="get" hint="Список сервисов"> <cffunction name="get" hint="Список сервисов">
<cfargument name="pageSize" type="string" hint="type:integer" default=100/> <cfargument name="pageSize" type="string" hint="type:integer" default=100/>
@@ -35,24 +32,17 @@
<cfargument name="orderBy" type="string" hint="type:string, description:comma-separated list of fields to sort by, example:fld1.ASC,fld2.DESC,fld3.ASC" default=""/> <cfargument name="orderBy" type="string" hint="type:string, description:comma-separated list of fields to sort by, example:fld1.ASC,fld2.DESC,fld3.ASC" default=""/>
<cfargument name="fields" type="string" hint="type:string, description:comma-separated list of fields to limit output to, empty string or omitted for default field set" required=false default=""/> <cfargument name="fields" type="string" hint="type:string, description:comma-separated list of fields to limit output to, empty string or omitted for default field set" required=false default=""/>
<cfargument name="search" type="string" hint="type:string, free search (black box)" required=false default=""/> <cfargument name="search" type="string" hint="type:string, free search (black box)" required=false default=""/>
<cfset local={}/> <cfset local={}/>
<!--- Фильтрация не униицирована (разница с instance_ls) ---> <!--- Фильтрация не униицирована (разница с instance_ls) --->
<!---parse and validate request parameters---> <!---parse and validate request parameters--->
<cftry> <cftry>
<cfset this.helper.validateField(arguments, "pageSize", "integer")/> <cfset this.helper.validateField(arguments, "pageSize", "integer")/>
<cfset this.helper.validateField(arguments, "page", "integer")/> <cfset this.helper.validateField(arguments, "page", "integer")/>
<!---мы мирно игнорируем поля, отсутствующие в спецификации, что позволяет не делать исключения для orderBy и т.п.---> <!---мы мирно игнорируем поля, отсутствующие в спецификации, что позволяет не делать исключения для orderBy и т.п.--->
<cfset var filter=this.helper.parseFilterParams(this.fieldsSpec)/> <cfset var filter=this.helper.parseFilterParams(this.fieldsSpec)/>
<cfset var order=this.helper.parseOrderBy(this.fieldsSpec, arguments.orderBy)/> <cfset var order=this.helper.parseOrderBy(this.fieldsSpec, arguments.orderBy)/>
<cfset local.fieldsToOutput=""/> <cfset local.fieldsToOutput=""/>
<cfloop collection=#this.fieldsSpec# item="fld"> <cfloop collection=#this.fieldsSpec# item="fld">
<!--- <cfoutput>#this.helper.snake2camel(trim(fld))#</cfoutput> --->
<!--- *** в данном случае мы некорректно ограничиваем состав выводимых полей <!--- *** в данном случае мы некорректно ограничиваем состав выводимых полей
полями, перечисленными в fieldSpec ---> полями, перечисленными в fieldSpec --->
<cfif listFindNoCase(arguments.fields, this.helper.snake2camel(trim(fld))) <cfif listFindNoCase(arguments.fields, this.helper.snake2camel(trim(fld)))
@@ -60,13 +50,10 @@
<cfset local.fieldsToOutput=listAppend(local.fieldsToOutput,trim(fld))/> <cfset local.fieldsToOutput=listAppend(local.fieldsToOutput,trim(fld))/>
</cfif> </cfif>
</cfloop> </cfloop>
<cfset local.fieldsToQueryFor = local.fieldsToOutput/> <cfset local.fieldsToQueryFor = local.fieldsToOutput/>
<cfset local.fieldsShortList=""/> <cfset local.fieldsShortList=""/>
<!--- теперь добавим в перечень полей, которые нужно оставить, поля для фильтрации и сортировки ---> <!--- теперь добавим в перечень полей, которые нужно оставить, поля для фильтрации и сортировки --->
<cfloop array=#filter# index="fltr"> <cfloop array=#filter# index="fltr">
<!--- <cfset var fltr = structFind(filter,item)/> --->
<cfif listLen(fltr.field,".") EQ 2> <cfif listLen(fltr.field,".") EQ 2>
<cfset var fld = listGetAt(fltr.field,2,".")/> <cfset var fld = listGetAt(fltr.field,2,".")/>
<cfelseif listLen(fltr.field,".") EQ 1> <cfelseif listLen(fltr.field,".") EQ 1>
@@ -81,8 +68,6 @@
<cfset local.fieldsShortList=listAppend(local.fieldsShortList,fld)/> <cfset local.fieldsShortList=listAppend(local.fieldsShortList,fld)/>
</cfif> </cfif>
</cfloop> </cfloop>
<!--- *** Не нужно ли сохранять префикс? (на случай одноименных полей) ---> <!--- *** Не нужно ли сохранять префикс? (на случай одноименных полей) --->
<cfloop collection=#order# item="item"> <cfloop collection=#order# item="item">
<cfset var ord = structFind(order,item)/> <cfset var ord = structFind(order,item)/>
@@ -101,21 +86,16 @@
<cfset local.fieldsShortList=listAppend(local.fieldsShortList,fld)/> <cfset local.fieldsShortList=listAppend(local.fieldsShortList,fld)/>
</cfif> </cfif>
</cfloop> </cfloop>
<cfcatch type="invalidParamValue">
<cfcatch type="invalidParamValue"><!--- <cfreturn representationOf("Проверка связи 3")> --->
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/> <cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
</cfcatch> </cfcatch>
<cfcatch type="any"> <cfcatch type="any">
<cfreturn representationOf(cfcatch)/> <cfreturn representationOf(cfcatch)/>
</cfcatch> </cfcatch>
</cftry> </cftry>
<cfset var out=structNew("linked")/> <cfset var out=structNew("linked")/>
<cfset var maxrows=arguments.pageSize*arguments.page/> <cfset var maxrows=arguments.pageSize*arguments.page/>
<cfset var startrow=arguments.pageSize*(arguments.page-1)+1/> <cfset var startrow=arguments.pageSize*(arguments.page-1)+1/>
<m:field_set <m:field_set
titleMapOut="local.titleMap" titleMapOut="local.titleMap"
lengthOut="local.fieldCount" lengthOut="local.fieldCount"
@@ -152,14 +132,6 @@
<m:field>to_char(s.dt_updated, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as dt_updated</m:field> <m:field>to_char(s.dt_updated, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as dt_updated</m:field>
<m:field>(coalesce(s.svc,'') ||' '|| coalesce(s.svc_short,'') ||' '|| coalesce(s.synonyms,'')) as svc_extended_name</m:field> <m:field>(coalesce(s.svc,'') ||' '|| coalesce(s.svc_short,'') ||' '|| coalesce(s.synonyms,'')) as svc_extended_name</m:field>
</m:field_set> </m:field_set>
<!--- <cfdump var=#local.titleMap#/>
<cfdump var=#arguments.orderBy#/>
<cfdump var=#this.helper.parseNumericOrder(local.titleMap, arguments.orderBy)#/>
<cfdump var=#local.fieldsToOutput#/>
<m:order_build sortCollection=#this.helper.parseNumericOrder(local.titleMap, arguments.orderBy)# fieldCount=1/>
<cfabort/> --->
<!--- *** проблема: сортировка строится некорректно. пока добавим поля сортировки в резалтсет ---> <!--- *** проблема: сортировка строится некорректно. пока добавим поля сортировки в резалтсет --->
<cfquery name="local.qRead" result="local.result"> <cfquery name="local.qRead" result="local.result">
select <cfif listLen(local.definedRecordFields)>#local.definedRecordFields#<cfelse>*</cfif> from select <cfif listLen(local.definedRecordFields)>#local.definedRecordFields#<cfelse>*</cfif> from
@@ -184,8 +156,6 @@
where 1=1 <m:filter_build filter=#filter#/> where 1=1 <m:filter_build filter=#filter#/>
order by <m:order_build sortCollection=#this.helper.parseNumericOrder(local.titleMap, arguments.orderBy)# fieldCount=1/> order by <m:order_build sortCollection=#this.helper.parseNumericOrder(local.titleMap, arguments.orderBy)# fieldCount=1/>
</cfquery> </cfquery>
<cftry> <cftry>
<cfquery name="local.qTotal"> <cfquery name="local.qTotal">
select count(*) as cnt select count(*) as cnt
@@ -196,29 +166,21 @@
<cfreturn representationOf(cfcatch)/> <cfreturn representationOf(cfcatch)/>
</cfcatch> </cfcatch>
</cftry> </cftry>
<!--- <cfreturn representationOf("Проверка связи 7")/> --->
<cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/> <cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/>
<cfset "out.total"=#local.qTotal.cnt#/> <cfset "out.total"=#local.qTotal.cnt#/>
<cfset "out.resultSetSize"=#local.qRead.recordCount#/> <cfset "out.resultSetSize"=#local.qRead.recordCount#/>
<cfset "out.pageSize"=#arguments.pageSize*1#/> <cfset "out.pageSize"=#arguments.pageSize*1#/>
<cfset "out.page"=#arguments.page*1#/> <cfset "out.page"=#arguments.page*1#/>
<cfset "out.orderBy"=#arguments.orderBy#/> <cfset "out.orderBy"=#arguments.orderBy#/>
<cfset var resultCollection=[]/> <cfset var resultCollection=[]/>
<cfloop query=#local.qRead# startRow=#startrow# endRow=#(startrow+maxrows-1)#> <cfloop query=#local.qRead# startRow=#startrow# endRow=#(startrow+maxrows-1)#>
<cfset var rec={}/> <cfset var rec={}/>
<cfset this.helper.appendRecord(rec, "", local.titleMap, local.qRead, this.helper.snake2camel)/> <cfset this.helper.appendRecord(rec, "", local.titleMap, local.qRead, this.helper.snake2camel)/>
<cfset arrayAppend(resultCollection, rec)/> <cfset arrayAppend(resultCollection, rec)/>
</cfloop> </cfloop>
<cfset "out.size"=#arrayLen(resultCollection)#/> <cfset "out.size"=#arrayLen(resultCollection)#/>
<cfset "out.results"=#resultCollection#/> <cfset "out.results"=#resultCollection#/>
<cfset "out.runDurationMs"=getTickCount()-request.startTickCount/> <cfset "out.runDurationMs"=getTickCount()-request.startTickCount/>
<!---<cfset "out.sql"=#local.result.sql#/>--->
<cfreturn representationOf(out)/> <cfreturn representationOf(out)/>
</cffunction> </cffunction>
</cfcomponent> </cfcomponent>
-15
View File
@@ -1,11 +1,8 @@
<cfcomponent extends="taffy.core.resource" taffy:uri="/serviceOperation/{svcOperationId}"> <cfcomponent extends="taffy.core.resource" taffy:uri="/serviceOperation/{svcOperationId}">
<cfsilent> <cfsilent>
<cfimport prefix="m" taglib="../lib"/> <cfimport prefix="m" taglib="../lib"/>
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/> <cfset this.helper=CreateObject("component","lib.rest_api_helper")/>
</cfsilent> </cfsilent>
<cffunction name="get" hint="Операция сервиса"><!--- *** TODO проверка принадлежности тенанту ---> <cffunction name="get" hint="Операция сервиса"><!--- *** TODO проверка принадлежности тенанту --->
<cfargument name="svcOperationId" type="string" required=true hint="type:integer"/> <cfargument name="svcOperationId" type="string" required=true hint="type:integer"/>
<cftry> <cftry>
@@ -14,7 +11,6 @@
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/> <cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
</cfcatch> </cfcatch>
</cftry> </cftry>
<cfquery name="local.qSvcOperation" result="local.result"> <cfquery name="local.qSvcOperation" result="local.result">
select select
<m:field_set titleMapOut="local.titleMap" lengthOut="local.fieldCount"> <m:field_set titleMapOut="local.titleMap" lengthOut="local.fieldCount">
@@ -27,12 +23,10 @@
from svc_operation o from svc_operation o
where o.svc_operation_id=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.svcOperationId#" null=#!isValid('integer',arguments.svcOperationId)#/> where o.svc_operation_id=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.svcOperationId#" null=#!isValid('integer',arguments.svcOperationId)#/>
</cfquery> </cfquery>
<cfquery name="local.qCfsParam" result="local.result"> <cfquery name="local.qCfsParam" result="local.result">
select select
<m:field_set titleMapOut="local.cfsParamMap" lengthOut="local.fieldCount"> <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 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.svc_operation_cfs_param</m:field>
<m:field>p.label</m:field> <m:field>p.label</m:field>
<m:field>p.data_type</m:field> <m:field>p.data_type</m:field>
@@ -73,18 +67,14 @@
AND p.is_actual AND p.is_actual
order by p.sort, p.svc_operation_cfs_param_id order by p.sort, p.svc_operation_cfs_param_id
</cfquery> </cfquery>
<cfif local.qSvcOperation.recordCount EQ 0> <cfif local.qSvcOperation.recordCount EQ 0>
<cfreturn representationOf(this.helper.formatMessage("Not Found")).withStatus(404)/> <cfreturn representationOf(this.helper.formatMessage("Not Found")).withStatus(404)/>
</cfif> </cfif>
<cfset var out=structNew("linked")/> <cfset var out=structNew("linked")/>
<cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/> <cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/>
<cfset "out.svcOperation" = this.helper.appendRecord( <cfset "out.svcOperation" = this.helper.appendRecord(
structNew("linked"), "", local.titleMap, local.qSvcOperation, this.helper.snake2camel structNew("linked"), "", local.titleMap, local.qSvcOperation, this.helper.snake2camel
)/> )/>
<cfset "out.svcOperation.cfsParams"=[]/> <cfset "out.svcOperation.cfsParams"=[]/>
<cfloop query=#local.qCfsParam#> <cfloop query=#local.qCfsParam#>
<cfif (len(local.qCfsParam.func) OR len(local.qCfsParam.expression) OR len(local.qCfsParam.state_path) OR len(local.qCfsParam.nested_ref)) <cfif (len(local.qCfsParam.func) OR len(local.qCfsParam.expression) OR len(local.qCfsParam.state_path) OR len(local.qCfsParam.nested_ref))
@@ -93,16 +83,13 @@
</cfif> </cfif>
<cfset arrayAppend(out.svcOperation.cfsParams, this.helper.appendRecord(structNew("linked"), "", local.cfsParamMap, local.qCfsParam, this.helper.snake2camel))/> <cfset arrayAppend(out.svcOperation.cfsParams, this.helper.appendRecord(structNew("linked"), "", local.cfsParamMap, local.qCfsParam, this.helper.snake2camel))/>
</cfloop> </cfloop>
<cfset "out.runDurationMs"=getTickCount() - request.startTickCount/> <cfset "out.runDurationMs"=getTickCount() - request.startTickCount/>
<cfreturn representationOf(out) /> <cfreturn representationOf(out) />
</cffunction> </cffunction>
<!--- *** выглядит ужасно, но красивый вариант не придумывается ряд месяцев ---> <!--- *** выглядит ужасно, но красивый вариант не придумывается ряд месяцев --->
<cffunction name="computeDefault"> <cffunction name="computeDefault">
<cfargument name="defaultCompute"/> <cfargument name="defaultCompute"/>
<cfargument name="original"/> <cfargument name="original"/>
<cfswitch expression=#arguments.defaultCompute#> <cfswitch expression=#arguments.defaultCompute#>
<cfcase value="display_name"> <cfcase value="display_name">
</cfcase> </cfcase>
@@ -110,7 +97,5 @@
<cfreturn #arguments.original#/> <cfreturn #arguments.original#/>
</cfdefaultcase> </cfdefaultcase>
</cfswitch> </cfswitch>
</cffunction> </cffunction>
</cfcomponent> </cfcomponent>
-41
View File
@@ -1,44 +1,21 @@
<cfcomponent extends="taffy.core.resource" taffy:uri="/user"> <cfcomponent extends="taffy.core.resource" taffy:uri="/user">
<cfsilent> <cfsilent>
<cfimport prefix="m" taglib="../lib"/> <cfimport prefix="m" taglib="../lib"/>
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/><!---*** странно, почему мы его видим?---><!---вынести в апп?---> <cfset this.helper=CreateObject("component","lib.rest_api_helper")/><!---*** странно, почему мы его видим?---><!---вынести в апп?--->
</cfsilent> </cfsilent>
<!--- *** Внимание! Особая обработка в Application.cfc по имени user.cfc ---> <!--- *** Внимание! Особая обработка в Application.cfc по имени user.cfc --->
<cffunction name="get" hint="Контрольная информация по текущему пользователю для проверки контекста. Предполагается использовать только для интеграционной отладки. Исключения перехватываются, всегда возвращается код 200, структура ответа при этом не предназначена для разбора"> <cffunction name="get" hint="Контрольная информация по текущему пользователю для проверки контекста. Предполагается использовать только для интеграционной отладки. Исключения перехватываются, всегда возвращается код 200, структура ответа при этом не предназначена для разбора">
<cftry> <cftry>
<cfset var local={}/><!--- *** а точно нужно var? ---> <cfset var local={}/><!--- *** а точно нужно var? --->
<cfset var out=structNew("linked")/> <cfset var out=structNew("linked")/>
<cfset "out.usrId"=#ARGUMENTS.usrId#/> <cfset "out.usrId"=#ARGUMENTS.usrId#/>
<!--- <cfset "out.iamServiceUrl"=request.locateIamService()/> --->
<cfset "out.serviceLocationDurationMs"=getTickCount() - request.startTickCount/> <cfset "out.serviceLocationDurationMs"=getTickCount() - request.startTickCount/>
<!--- <cftry>
<cfset var sAuth=listGetAt(request.ORCHESTRATOR_AUTH,2," ")/>
<cfset "out.svcAccount"=listGetAt(toString(ToBinary(sAuth)),1,":")/>
<cfcatch type="any"></cfcatch>
</cftry>
<cfset "out.environmentVariables"=structKeyArray(createObject("java", "java.lang.System").getEnv()).sort("textnocase")/> --->
<!--- <cfdump var=#arguments#/>
<cfabort/> --->
<cfquery name="local.qSpec"> <cfquery name="local.qSpec">
select select
<m:field_set titleMapOut="local.specTitleMap" lengthOut="local.fieldCount"> <m:field_set titleMapOut="local.specTitleMap" lengthOut="local.fieldCount">
<m:field cfSqlType="CF_SQL_INTEGER">s.specification_id</m:field> <m:field cfSqlType="CF_SQL_INTEGER">s.specification_id</m:field>
<!--- <m:field>s.specification</m:field>
<m:field>(select count(*) from specification_item i where i.specification_id=s.specification_id) as specification_item_count</m:field> --->
<m:field>c.contract_id</m:field> <m:field>c.contract_id</m:field>
<m:field>c.contragent_id</m:field> <m:field>c.contragent_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_set> </m:field_set>
from specification s from specification s
join contract c on (s.contract_id=c.contract_id) join contract c on (s.contract_id=c.contract_id)
@@ -47,44 +24,26 @@
order by specification_id desc order by specification_id desc
limit 1; limit 1;
</cfquery> </cfquery>
<cfquery name="local.qRead" result="local.result"> <cfquery name="local.qRead" result="local.result">
select select
<m:field_set titleMapOut="local.titleMap" lengthOut="local.fieldCount"> <m:field_set titleMapOut="local.titleMap" lengthOut="local.fieldCount">
<m:field cfSqlType="CF_SQL_INTEGER">u.usr_id</m:field> <m:field cfSqlType="CF_SQL_INTEGER">u.usr_id</m:field>
<!--- <m:field>u.login</m:field> --->
<m:field>k.contragent_id</m:field> <m:field>k.contragent_id</m:field>
<!--- <m:field><cfqueryparam cfsqltype="cf_sql_other" value=#arguments.companyUid#/> as arguments_company_uid</m:field> --->
<!--- <m:field>k.external_uid::text as external_uid</m:field> --->
<!--- <m:field>k.contragent</m:field> --->
</m:field_set> </m:field_set>
from usr u from usr u
left outer join contragent k on u.contragent_id=k.contragent_id left outer join contragent k on u.contragent_id=k.contragent_id
where u.usr_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#ARGUMENTS.usrId#/> where u.usr_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#ARGUMENTS.usrId#/>
</cfquery> </cfquery>
<cfset "out.queryDurationMs"=getTickCount() - request.startTickCount- out.serviceLocationDurationMs/> <cfset "out.queryDurationMs"=getTickCount() - request.startTickCount- out.serviceLocationDurationMs/>
<cfset var resultCollection=[]/> <cfset var resultCollection=[]/>
<cfset "out.usr" = (local.qRead.recordCount GT 0) ? this.helper.appendRecord(structNew("linked"), "", local.titleMap, local.qRead, this.helper.snake2camel) : {}/> <cfset "out.usr" = (local.qRead.recordCount GT 0) ? this.helper.appendRecord(structNew("linked"), "", local.titleMap, local.qRead, this.helper.snake2camel) : {}/>
<cfset "out.arguments" = #arguments#/> <cfset "out.arguments" = #arguments#/>
<cfset "out.defaultSpecification" = (local.qSpec.recordCount GT 0) ? this.helper.appendRecord(structNew("linked"), "", local.specTitleMap, local.qSpec, this.helper.snake2camel) : {}/> <cfset "out.defaultSpecification" = (local.qSpec.recordCount GT 0) ? this.helper.appendRecord(structNew("linked"), "", local.specTitleMap, local.qSpec, this.helper.snake2camel) : {}/>
<cfset "out.runDurationMs"=getTickCount()-request.startTickCount/> <cfset "out.runDurationMs"=getTickCount()-request.startTickCount/>
<!---<cfset "out.sql"=#local.result.sql#/>--->
<cfreturn representationOf(out)/> <cfreturn representationOf(out)/>
<cfcatch type="any"> <cfcatch type="any">
<cfreturn representationOf(cfcatch)/> <cfreturn representationOf(cfcatch)/>
</cfcatch> </cfcatch>
</cftry> </cftry>
</cffunction> </cffunction>
<!--- <cffunction name="get" hint="проверка">
<cfreturn representationOf("Проверка связи")/>
</cffunction> --->
</cfcomponent> </cfcomponent>
-61
View File
@@ -1,41 +1,21 @@
<cfcomponent extends="taffy.core.resource" taffy:uri="/instances/{instanceUid}/vault/{secretName}" hint="getting secrets from the vault"> <cfcomponent extends="taffy.core.resource" taffy:uri="/instances/{instanceUid}/vault/{secretName}" hint="getting secrets from the vault">
<cfsilent> <cfsilent>
<cfimport prefix="m" taglib="../lib"/> <cfimport prefix="m" taglib="../lib"/>
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/> <cfset this.helper=CreateObject("component","lib.rest_api_helper")/>
</cfsilent> </cfsilent>
<cffunction name="get" hint="Получить секрет"> <cffunction name="get" hint="Получить секрет">
<cfargument name="instanceUid" type="string" required=true hint="type:UUID"/> <cfargument name="instanceUid" type="string" required=true hint="type:UUID"/>
<cfargument name="secretName" type="string" required=true hint="type:string"/> <cfargument name="secretName" type="string" required=true hint="type:string"/>
<!--- <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 ---> <!--- arguments.usrId неявно вбрасывается из Application.cfm --->
<cftry> <cftry>
<cfset this.helper.validateField(arguments, "instanceUid", "guid")/> <cfset this.helper.validateField(arguments, "instanceUid", "guid")/>
<cfcatch type="invalidParamValue"> <cfcatch type="invalidParamValue">
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/> <cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
</cfcatch> </cfcatch>
</cftry> </cftry>
<cfset var local={}/> <cfset var local={}/>
<cfset local.vaultData={}/> <cfset local.vaultData={}/>
<!--- <cfset logVaultAccess(
"#request.iam_service_url#/events",
request.auth_header,
request.stand,
arguments.instanceUid,
arguments.secretName,
"",
arguments.login,
arguments.clientID,
arguments.usrId,
arguments.contragentId,
arguments.isImpersonated)/> --->
<!--- *** Добавить проверку, что секрет перечислен в fields - стало быть, доступен пользователю ---> <!--- *** Добавить проверку, что секрет перечислен в fields - стало быть, доступен пользователю --->
<!--- тут необходимо проконтролировать, что мы смотрим не чужие данные ---> <!--- тут необходимо проконтролировать, что мы смотрим не чужие данные --->
<!--- в других местах мы молча возврашаем пустой резалтсет на запрос чужих данных ---> <!--- в других местах мы молча возврашаем пустой резалтсет на запрос чужих данных --->
<!--- варианты: 403, 404, пустой набор данных ---> <!--- варианты: 403, 404, пустой набор данных --->
@@ -59,16 +39,12 @@
order by st.version desc order by st.version desc
limit 1 limit 1
</cfquery> </cfquery>
<cfif local.qCurrentState.recordCount EQ 0> <cfif local.qCurrentState.recordCount EQ 0>
<cfreturn representationOf("Cannot find instance current state or no permission to view").withStatus(404)/> <cfreturn representationOf("Cannot find instance current state or no permission to view").withStatus(404)/>
</cfif> </cfif>
<cfif len(local.qCurrentState.instance_data) EQ 0> <cfif len(local.qCurrentState.instance_data) EQ 0>
<cfreturn representationOf("Instance current state is empty").withStatus(404)/> <cfreturn representationOf("Instance current state is empty").withStatus(404)/>
</cfif> </cfif>
<!--- <cfdump var=#local.qCurrentState#/><cfabort/> --->
<cfset var vaultUrl=""/> <cfset var vaultUrl=""/>
<cftry> <cftry>
<cfset var instanceData=#deserializeJson(local.qCurrentState.instance_data)#/> <cfset var instanceData=#deserializeJson(local.qCurrentState.instance_data)#/>
@@ -82,7 +58,6 @@
<cfelse> <cfelse>
<cfreturn representationOf("Instance data do not contain vault url").withStatus(422)/> <cfreturn representationOf("Instance data do not contain vault url").withStatus(422)/>
</cfif> </cfif>
<cfhttp method="post" <cfhttp method="post"
url="#request.vault_login_url#" url="#request.vault_login_url#"
timeout="3" timeout="3"
@@ -92,14 +67,11 @@
<cfhttpparam type="HEADER" name="User-Agent" value="#request.USER_AGENT#"/> <cfhttpparam type="HEADER" name="User-Agent" value="#request.USER_AGENT#"/>
<cfhttpparam type="BODY" value='{"role_id":"#request.vault_role_id#","secret_id":"#request.vault_secret_id#"}'/> <cfhttpparam type="BODY" value='{"role_id":"#request.vault_role_id#","secret_id":"#request.vault_secret_id#"}'/>
</cfhttp> </cfhttp>
<cfif local.res.status_code NEQ 200> <cfif local.res.status_code NEQ 200>
<cfreturn representationOf(local.res).withStatus(422)/> <cfreturn representationOf(local.res).withStatus(422)/>
</cfif> </cfif>
<cfset resData=#deserializeJson(local.res.filecontent)#/> <cfset resData=#deserializeJson(local.res.filecontent)#/>
<cfset client_token=#resData.auth.client_token#/> <cfset client_token=#resData.auth.client_token#/>
<cftry> <cftry>
<cfhttp method="get" <cfhttp method="get"
url="#vaultUrl#" url="#vaultUrl#"
@@ -112,7 +84,6 @@
<cfif local.cred.status_code NEQ 200> <cfif local.cred.status_code NEQ 200>
<cfreturn representationOf(local.cred).withStatus(422)/> <cfreturn representationOf(local.cred).withStatus(422)/>
</cfif> </cfif>
<!--- <cfdump var=#cred#/><cfabort/> --->
<!--- *** костыль для перехода от формата v001 к v002 ---> <!--- *** костыль для перехода от формата v001 к v002 --->
<cfif structKeyExists(instanceData,"vault") <cfif structKeyExists(instanceData,"vault")
AND structKeyExists(instanceData.vault,"fields") AND structKeyExists(instanceData.vault,"fields")
@@ -125,18 +96,14 @@
<cfelse> <cfelse>
<cfreturn representationOf("Secret not found or no permission to view").withStatus(404)/> <cfreturn representationOf("Secret not found or no permission to view").withStatus(404)/>
</cfif> </cfif>
<cfcatch type="ANY"> <cfcatch type="ANY">
<cfreturn representationOf(cfcatch).withStatus(500)/> <cfreturn representationOf(cfcatch).withStatus(500)/>
</cfcatch> </cfcatch>
</cftry> </cftry>
<cfcatch type="ANY"> <cfcatch type="ANY">
<cfreturn representationOf(cfcatch).withStatus(500)/> <cfreturn representationOf(cfcatch).withStatus(500)/>
</cfcatch> </cfcatch>
</cftry> </cftry>
<!--- логируем успешную попытку доступа. (если логировать сначала - неизвестен результат. *** Можно в catch логировать неуспешный ---> <!--- логируем успешную попытку доступа. (если логировать сначала - неизвестен результат. *** Можно в catch логировать неуспешный --->
<cfset logVaultAccess( <cfset logVaultAccess(
"#request.iam_service_url#/events", "#request.iam_service_url#/events",
@@ -150,7 +117,6 @@
arguments.usrId, arguments.usrId,
arguments.contragentId, arguments.contragentId,
arguments.isImpersonated)/> arguments.isImpersonated)/>
<cfset var out = structNew("linked")/> <cfset var out = structNew("linked")/>
<cfset "out.name" = #arguments.secretName#/> <cfset "out.name" = #arguments.secretName#/>
<cfset "out.value" = #isSimpleValue(local.vaultData)? local.vaultData : serializeJson(local.vaultData)#/><!--- cast any to string ---> <cfset "out.value" = #isSimpleValue(local.vaultData)? local.vaultData : serializeJson(local.vaultData)#/><!--- cast any to string --->
@@ -158,7 +124,6 @@
<cfset "out.runDurationMs"=getTickCount() - request.startTickCount/> <cfset "out.runDurationMs"=getTickCount() - request.startTickCount/>
<cfreturn representationOf(out) /> <cfreturn representationOf(out) />
</cffunction> </cffunction>
<cffunction name="logVaultAccess" returntype="void"> <cffunction name="logVaultAccess" returntype="void">
<cfargument name="loggerUrl" type="string" required=true hint=""/> <cfargument name="loggerUrl" type="string" required=true hint=""/>
<cfargument name="authHeader" type="string" required=true hint="type:string"/> <cfargument name="authHeader" type="string" required=true hint="type:string"/>
@@ -171,25 +136,10 @@
<cfargument name="usrId" type="string" required=true hint="type:string WZ"/> <cfargument name="usrId" type="string" required=true hint="type:string WZ"/>
<cfargument name="contragentId" type="string" required=true hint="type:string WZ"/> <cfargument name="contragentId" type="string" required=true hint="type:string WZ"/>
<cfargument name="isImpersonated" type="string" required=true hint="type:boolean"/> <cfargument name="isImpersonated" type="string" required=true hint="type:boolean"/>
<cftry> <cftry>
<cfset var local={}/> <cfset var local={}/>
<!--- расшифруем некоторые данные пользователя для читабельности ---> <!--- расшифруем некоторые данные пользователя для читабельности --->
<!--- нужно еще учесть имперсонирование ---> <!--- нужно еще учесть имперсонирование --->
<!--- <cfquery name="local.qUsr" result="local.result">
select
u.usr_id
u.login
u.email
k.contragent_id
k.external_uid::text as external_uid
k.contragent
from usr u
left outer join contragent k on (u.contragent_id=k.contragent_id)
where u.usr_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#ARGUMENTS.usrId#/>
</cfquery> --->
<cfset var msg = { <cfset var msg = {
"event_type": "credentials_access", "event_type": "credentials_access",
"ip_address": "#CGI.REMOTE_ADDR#", "ip_address": "#CGI.REMOTE_ADDR#",
@@ -208,7 +158,6 @@
"isImpersonated": "#arguments.isImpersonated#" "isImpersonated": "#arguments.isImpersonated#"
} }
}/> }/>
<!--- <!---
https://cfguide.io/logging-observability https://cfguide.io/logging-observability
https://www.bennadel.com/blog/4150-writing-to-the-standard-out-console-using-writedump-in-adobe-coldfusion-2021.htm https://www.bennadel.com/blog/4150-writing-to-the-standard-out-console-using-writedump-in-adobe-coldfusion-2021.htm
@@ -218,7 +167,6 @@
<cfset SystemOutput(serializeJson(msg))/><!--- *** lucee specific incompatible syntax ---> <cfset SystemOutput(serializeJson(msg))/><!--- *** lucee specific incompatible syntax --->
<cfcatch type="ANY"></cfcatch> <cfcatch type="ANY"></cfcatch>
</cftry> </cftry>
<cfhttp method="post" <cfhttp method="post"
url="#arguments.loggerUrl#" url="#arguments.loggerUrl#"
timeout="3" timeout="3"
@@ -229,18 +177,9 @@
<cfhttpparam type="HEADER" name="Content-Type" value="application/json"/> <cfhttpparam type="HEADER" name="Content-Type" value="application/json"/>
<cfhttpparam type="BODY" value="#serializeJson(msg)#"/> <cfhttpparam type="BODY" value="#serializeJson(msg)#"/>
</cfhttp> </cfhttp>
<!---
arguments:<cfdump var=#arguments#/>
msg:<cfdump var=#msg#/>
local.res:<cfdump var=#local.res#/>
<cfabort/>
--->
<cfcatch type="any"> <cfcatch type="any">
<cfrethrow/><!--- на этапе отладки лучше тут падать ---> <cfrethrow/><!--- на этапе отладки лучше тут падать --->
</cfcatch> </cfcatch>
</cftry> </cftry>
</cffunction> </cffunction>
</cfcomponent> </cfcomponent>