Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06230fd6af | ||
|
|
c753f14990 | ||
|
|
1497940812 | ||
|
|
e78a930ab4 | ||
|
|
eb0f2f178b |
@@ -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
@@ -7,9 +7,16 @@
|
||||
3. Строит DOCX:
|
||||
- Титульная страница (название, подзаголовок, дата)
|
||||
- Оглавление (поле 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
|
||||
|
||||
@@ -39,8 +46,8 @@ from docx.enum.text import WD_ALIGN_PARAGRAPH
|
||||
from docx.oxml.ns import qn
|
||||
from docx.oxml import OxmlElement
|
||||
|
||||
BUNDLE_PATH = '/home/naeel/svc-api-x/results/source-bundle.md' # входной файл
|
||||
OUTPUT_PATH = '/home/naeel/svc-api-x/results/svc-api-x.docx' # выходной файл
|
||||
BUNDLE_PATH = 'results/source-bundle.md' # входной файл
|
||||
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.size = Pt(size)
|
||||
run.font.bold = bold
|
||||
@@ -259,11 +320,13 @@ def build(sections):
|
||||
|
||||
for idx, line in enumerate(lines):
|
||||
if idx > 0:
|
||||
run = code_para.add_run()
|
||||
br_run = code_para.add_run()
|
||||
br = OxmlElement('w:br')
|
||||
run._r.append(br)
|
||||
run = code_para.add_run(line)
|
||||
set_font(run, name='Courier New', size=8)
|
||||
br_run._r.append(br)
|
||||
set_font(br_run)
|
||||
for text, color in tokenize_cfml(line):
|
||||
run = code_para.add_run(text)
|
||||
set_font(run, color=color)
|
||||
|
||||
doc.save(OUTPUT_PATH)
|
||||
print(f'Готово: {OUTPUT_PATH}')
|
||||
|
||||
+116
-783
File diff suppressed because it is too large
Load Diff
+48
-61
@@ -1,68 +1,55 @@
|
||||
# Оглавление исходников svc-api-x
|
||||
|
||||
Дата сборки: 2026-04-30
|
||||
Дата сборки: 2026-05-19
|
||||
|
||||
|
||||
## Прикладной слой
|
||||
|
||||
```text
|
||||
health.cfm ........................................ 7
|
||||
v1/Application.cfc ................................ 12
|
||||
v1/index.cfm ...................................... 761
|
||||
v1/lib/JsonSerializer.cfc .......................... 767
|
||||
v1/lib/TokenGenerator.cfc .......................... 1286
|
||||
v1/lib/encodingUtils.cfc ........................... 1348
|
||||
v1/lib/expression_parser.cfc ....................... 1636
|
||||
v1/lib/field.cfm ................................... 1795
|
||||
v1/lib/field_set.cfm .............................. 1860
|
||||
v1/lib/filter_build.cfm ........................... 1929
|
||||
v1/lib/index.cfm .................................. 1996
|
||||
v1/lib/jwt.cfc .................................... 2002
|
||||
v1/lib/notifier.cfc ................................ 2269
|
||||
v1/lib/order_build.cfm ............................ 2307
|
||||
v1/lib/rest_api_helper.cfc ........................ 2353
|
||||
v1/resources/available_resource_realms.cfc .......... 2816
|
||||
v1/resources/bookmark.cfc .......................... 2910
|
||||
v1/resources/bookmark_ls.cfc ....................... 3021
|
||||
v1/resources/catalog_service_ls.cfc ................ 3205
|
||||
v1/resources/catalog_service_param_ls.cfc .......... 3378
|
||||
v1/resources/err.cfc ............................... 3574
|
||||
v1/resources/instance.cfc .......................... 3589
|
||||
v1/resources/instance_default.cfc .................. 4120
|
||||
v1/resources/instance_ls.cfc ....................... 4176
|
||||
v1/resources/instance_operation.cfc ............... 4725
|
||||
v1/resources/instance_operation_cfs_param.cfc ...... 5026
|
||||
v1/resources/instance_operation_cfs_param_ls.cfc ... 6004
|
||||
v1/resources/instance_operation_cfs_subparam.cfc ... 6449
|
||||
v1/resources/instance_operation_cfs_subparam_ls.cfc . 6626
|
||||
v1/resources/instance_operation_default.cfc ........ 6712
|
||||
v1/resources/instance_operation_ls.cfc ............. 7039
|
||||
v1/resources/instance_operation_run.cfc ............ 7345
|
||||
v1/resources/instance_operation_validate.cfc ....... 7791
|
||||
v1/resources/notification_ls.cfc ................... 7820
|
||||
v1/resources/param_value_list.cfc .................. 7928
|
||||
v1/resources/resource_realm.cfc .................... 7958
|
||||
v1/resources/resource_realm_ls.cfc ................. 8038
|
||||
v1/resources/resource_realm_type_ls.cfc ............ 8148
|
||||
v1/resources/svc.cfc ................................ 8239
|
||||
v1/resources/svc_default.cfc ........................ 8322
|
||||
v1/resources/svc_grouped_ls.cfc .................... 8367
|
||||
v1/resources/svc_ls.cfc ............................ 8541
|
||||
v1/resources/svc_operation.cfc ..................... 8770
|
||||
v1/resources/svc_operation_cfs_param_compute.cfc ... 8891
|
||||
v1/resources/svc_operation_cfs_subparam_compute.cfc . 8968
|
||||
v1/resources/user.cfc .............................. 9045
|
||||
v1/resources/vault_record.cfc ...................... 9140
|
||||
```
|
||||
|
||||
## Backup-слой, исключенный из основного bundle
|
||||
|
||||
```text
|
||||
отсутствует
|
||||
```
|
||||
|
||||
## Исключено из bundle
|
||||
|
||||
```text
|
||||
v1/resources/bk/* .......................... удаленные backup-сериализаторы
|
||||
v1/taffy/* ................................ vendor framework, примеры и тесты
|
||||
v1/Application.cfc .................................... 8
|
||||
v1/index.cfm ........................................ 767
|
||||
v1/lib/JsonSerializer.cfc ........................... 775
|
||||
v1/lib/TokenGenerator.cfc .......................... 1296
|
||||
v1/lib/encodingUtils.cfc ........................... 1360
|
||||
v1/lib/expression_parser.cfc ....................... 1650
|
||||
v1/lib/field.cfm ................................... 1811
|
||||
v1/lib/field_set.cfm ............................... 1878
|
||||
v1/lib/filter_build.cfm ............................ 1949
|
||||
v1/lib/index.cfm ................................... 2018
|
||||
v1/lib/jwt.cfc ..................................... 2026
|
||||
v1/lib/notifier.cfc ................................ 2295
|
||||
v1/lib/order_build.cfm ............................. 2335
|
||||
v1/lib/rest_api_helper.cfc ......................... 2383
|
||||
v1/resources/available_resource_realms.cfc ......... 2848
|
||||
v1/resources/bookmark.cfc .......................... 2944
|
||||
v1/resources/bookmark_ls.cfc ....................... 3057
|
||||
v1/resources/catalog_service_ls.cfc ................ 3243
|
||||
v1/resources/catalog_service_param_ls.cfc .......... 3418
|
||||
v1/resources/err.cfc ............................... 3616
|
||||
v1/resources/instance.cfc .......................... 3633
|
||||
v1/resources/instance_default.cfc .................. 4081
|
||||
v1/resources/instance_ls.cfc ....................... 4139
|
||||
v1/resources/instance_operation.cfc ................ 4577
|
||||
v1/resources/instance_operation_cfs_param.cfc ...... 4880
|
||||
v1/resources/instance_operation_cfs_param_ls.cfc ... 5678
|
||||
v1/resources/instance_operation_cfs_subparam.cfc ... 6125
|
||||
v1/resources/instance_operation_cfs_subparam_ls.cfc . 6270
|
||||
v1/resources/instance_operation_default.cfc ........ 6338
|
||||
v1/resources/instance_operation_ls.cfc ............. 6619
|
||||
v1/resources/instance_operation_run.cfc ............ 6878
|
||||
v1/resources/instance_operation_validate.cfc ....... 7326
|
||||
v1/resources/notification_ls.cfc ................... 7348
|
||||
v1/resources/param_value_list.cfc .................. 7458
|
||||
v1/resources/resource_realm.cfc .................... 7490
|
||||
v1/resources/resource_realm_ls.cfc ................. 7572
|
||||
v1/resources/resource_realm_type_ls.cfc ............ 7684
|
||||
v1/resources/svc.cfc ............................... 7777
|
||||
v1/resources/svc_default.cfc ....................... 7844
|
||||
v1/resources/svc_grouped_ls.cfc .................... 7891
|
||||
v1/resources/svc_ls.cfc ............................ 8018
|
||||
v1/resources/svc_operation.cfc ..................... 8211
|
||||
v1/resources/svc_operation_cfs_param_compute.cfc ... 8319
|
||||
v1/resources/svc_operation_cfs_subparam_compute.cfc . 8398
|
||||
v1/resources/user.cfc .............................. 8477
|
||||
v1/resources/vault_record.cfc ...................... 8533
|
||||
```
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,11 +1,8 @@
|
||||
<cfcomponent extends="taffy.core.resource" taffy:uri="/instances/{instanceUid}">
|
||||
|
||||
<cfsilent>
|
||||
<cfimport prefix="m" taglib="../lib"/>
|
||||
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/><!---*** странно, почему мы его видим?---><!---вынести в апп?--->
|
||||
</cfsilent>
|
||||
|
||||
|
||||
<cffunction name="get" hint="Экземпляр сервиса"><!--- *** TODO проверка принадлежности тенанту --->
|
||||
<cfargument name="instanceUid" type="string" required=true hint="type:guid"/>
|
||||
<cftry>
|
||||
@@ -14,9 +11,7 @@
|
||||
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfset var local={}/>
|
||||
|
||||
<cfquery name="local.qInstance" result="local.result">
|
||||
select
|
||||
<m:field_set titleMapOut="local.titleMap" lengthOut="local.fieldCount">
|
||||
@@ -36,7 +31,6 @@
|
||||
<m:field>v.svc</m:field>
|
||||
<m:field>v.code</m:field>
|
||||
<m:field>v.man
|
||||
|
||||
</m:field>
|
||||
<m:field>e.updater_id</m:field>
|
||||
<m:field>u.login as updater_login</m:field>
|
||||
@@ -71,7 +65,6 @@
|
||||
AND a.is_enabled)
|
||||
where r.resource_realm_type_id=v.resource_realm_type_id) as resource_realm_cnt
|
||||
</m:field>
|
||||
<!--- <m:field>st.version</m:field> --->
|
||||
</m:field_set>
|
||||
from instance e
|
||||
left outer join specification_item i on (e.specification_item_id=i.specification_item_id)
|
||||
@@ -94,16 +87,13 @@
|
||||
where e.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceUid#" null=#!isValid('guid',arguments.instanceUid)#/>
|
||||
AND s.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/><!--- access protection --->
|
||||
</cfquery> <!--- *** правильнее при попытке доступа к чужому инстансу (НСД) выбрасывать 403, а тут будет 404, но так тоже делают, например, в gitea --->
|
||||
|
||||
<cfif local.qInstance.recordCount EQ 0>
|
||||
<cfreturn representationOf("Instance not found or no permission to view").withStatus(404)/>
|
||||
</cfif>
|
||||
|
||||
<!--- instanceData?.suspended
|
||||
instanceData?.out?.monitoring?.allDashboards
|
||||
instanceData?.params
|
||||
instanceData?.out --->
|
||||
|
||||
<cfquery name="local.qCurrentState" result="local.result">
|
||||
select
|
||||
<m:field_set titleMapOut="local.currentStateTitleMap" lengthOut="local.fieldCount">
|
||||
@@ -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 formatter=#request.castToBool#>st.is_test</m:field>
|
||||
<m:field>st.instance_operation_uid::text as instance_operation_uid</m:field>
|
||||
<!--- <m:field formatter=#function(x){return (deserializeJson(x))}#>st.instance_data::text as instance_data</m:field> --->
|
||||
<m:field formatter=#function(x){return (deserializeJson(x))}#>st.instance_data->>'out' as out</m:field>
|
||||
<m:field formatter=#function(x){return (deserializeJson(x))}#>st.instance_data->>'params' as params</m:field>
|
||||
<m:field formatter=#function(x){return (deserializeJson(x))}#>st.instance_data->>'vault' as vault</m:field>
|
||||
@@ -125,13 +114,8 @@
|
||||
order by st.version desc
|
||||
limit 1
|
||||
</cfquery><!--- берем local.qInstance.instance_uid ради изоляции (access protection) --->
|
||||
|
||||
|
||||
<cfset local.isCreated = (local.qCurrentState.recordCount GT 0)/>
|
||||
<cfset local.isDeleted = (local.qCurrentState.is_deleted GT 0)/>
|
||||
|
||||
<!--- <cfdump var=#local.qInstance#/><cfabort/> --->
|
||||
|
||||
<!--- операция, создавшая текущее состояние --->
|
||||
<!--- *** странноватый селект --->
|
||||
<cfquery name="local.qOperation" result="local.result">
|
||||
@@ -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> --->
|
||||
|
||||
<!--- *** Отработать блокировку --->
|
||||
<cfquery name="local.qAvailableOperation" result="local.result">
|
||||
select
|
||||
@@ -204,17 +184,12 @@
|
||||
</cfif>
|
||||
order by so.svc_operation_id
|
||||
</cfquery>
|
||||
|
||||
<!--- Проблема зависимостей. Чтобы их увидеть, нам нужно состояние, а его нет в реляционном виде.
|
||||
Значит, придется парсить стейт
|
||||
но чтобы получить все сервисы, которые зависят от данного, придется им отпарсить все стейты, что нереально
|
||||
Значит, придется заняться нормализаций стейта (приведением в реляционный вид) - впрочем, ничего сильно сложного в этом нет
|
||||
А есть смысл делать это в одну строну? наверно, есть - чтобы не забираться в операцию
|
||||
--->
|
||||
|
||||
|
||||
|
||||
|
||||
<!--- *** здесь уместна параноидальная проверка прав --->
|
||||
<cfquery name="local.qDependency">
|
||||
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_cfs_param sop on (so.svc_operation_id=sop.svc_operation_id AND p.param=sop.svc_operation_cfs_param)
|
||||
left outer join svc s on (sop.ref_svc_id=s.svc_id)
|
||||
|
||||
join instance r on (p.param_value=r.instance_uid::text)
|
||||
left outer join specification_item si on (r.specification_item_id=si.specification_item_id)
|
||||
left outer join specification sp on (si.specification_id=sp.specification_id)
|
||||
@@ -250,7 +224,6 @@
|
||||
AND sop.ref_svc_id > 0
|
||||
order by sop.sort, p.param
|
||||
</cfquery>
|
||||
|
||||
<!--- *** здесь уместна параноидальная проверка прав
|
||||
потому что можно сослаться на чужой инстанс и увидеть какие-то лишние детали--->
|
||||
<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)#/>
|
||||
)
|
||||
</cfquery>
|
||||
|
||||
|
||||
|
||||
<!--- ---------------------------------------------------------------------------------- --->
|
||||
<!--- маскируем секреты *** это не очень похоже на то же самое в списке, там мы просто удаляем параметры --->
|
||||
<!--- *** подгоняем запрос под структуру из instance_operation_cfs_param --->
|
||||
<!--- а мы тут упускаем, что может быть несколько операций create, как правило из-за сломавшихся. Но параметры мы берем из текущего стейта, и операцию возьмем оттуда же --->
|
||||
|
||||
<cfquery name="local.qCfsParam" result="local.result">
|
||||
select
|
||||
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)#/>
|
||||
AND o.operation='create'
|
||||
</cfquery>
|
||||
|
||||
<!--- *** сделано не так, как в instance_operation_cfs_param (а там тоже сделано так себе) --->
|
||||
<cfset local.params = structNew("linked")/>
|
||||
<cftry>
|
||||
@@ -333,7 +301,7 @@
|
||||
<cfset local.params[paramName]="********"/>
|
||||
<cfelseif local.qCfsParam.data_type EQ "map" OR local.qCfsParam.data_type EQ "map-fixed" OR local.qCfsParam.data_type EQ "array-map-fixed">
|
||||
<!--- Не разбираем вариант "sensitive map" --->
|
||||
<!--- <cfset processMap(local.qCfsParam)/> ---><!--- query passed by reference --->
|
||||
<!--- query passed by reference --->
|
||||
<!--- маскируем секреты в map --->
|
||||
<!--- *** сделано ненадежно, с расчетом на структуру qCfsParam (ради этого ее пришлось дополнить) --->
|
||||
<!--- что характерно, мы передаем запрос (с фокусом, установленным на текущую строку) по ссылке и прямо там ее патчим --->
|
||||
@@ -341,70 +309,42 @@
|
||||
</cfif>
|
||||
</cfif>
|
||||
</cfloop>
|
||||
|
||||
<!--- грубо и цинично патчим запрос --->
|
||||
<cfset local.qCurrentState.params = serializeJson(local.params)/>
|
||||
<cfcatch type="ANY"><!--- *** <cfrethrow/>---></cfcatch>
|
||||
<cfcatch type="ANY"></cfcatch>
|
||||
</cftry>
|
||||
|
||||
<!--- ---------------------------------------------------------------------------------- --->
|
||||
|
||||
|
||||
<cfset var out=structNew("linked")/>
|
||||
|
||||
|
||||
<cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/>
|
||||
|
||||
<cfset "out.instance" = this.helper.appendRecord(
|
||||
structNew("linked"), "", local.titleMap, local.qInstance, this.helper.snake2camel
|
||||
)/>
|
||||
<!--- <cfset "out.instance.uptime"=(local.qOperation.is_successful GT 0) ? local.qOperation.seconds_passed : 0/> --->
|
||||
<cfset "out.instance.isCreated"=local.isCreated/>
|
||||
<cfset "out.instance.isDeleted"=local.qCurrentState.is_deleted GT 0/>
|
||||
<!--- <cfset "out.instance.vaultData"=local.vaultData/> --->
|
||||
|
||||
<cfset "out.instance.state" = (local.qCurrentState.recordCount GT 0) ? this.helper.appendRecord(structNew("linked"), "", local.currentStateTitleMap, local.qCurrentState, this.helper.snake2camel) : {}/>
|
||||
|
||||
<cfset "out.instance.operations"=[]/>
|
||||
<cfloop query=#local.qOperation#>
|
||||
<cfset arrayAppend(out.instance.operations, this.helper.appendRecord(structNew("linked"), "", local.operationTitleMap, local.qOperation, this.helper.snake2camel))/>
|
||||
</cfloop>
|
||||
|
||||
<cfset "out.instance.availableOperations"=[]/>
|
||||
<cfloop query=#local.qAvailableOperation#>
|
||||
<cfset arrayAppend(out.instance.availableOperations, this.helper.appendRecord(structNew("linked"), "", local.availableOperationTitleMap, local.qAvailableOperation, this.helper.snake2camel))/>
|
||||
</cfloop>
|
||||
|
||||
<!--- <cfset "out.instance.dependencies0"=#dependencies#/> --->
|
||||
|
||||
<cfset "out.instance.dependentInstances"=[]/>
|
||||
<cfloop query=#local.qDependentInstance#>
|
||||
<cfset arrayAppend(out.instance.dependentInstances, this.helper.appendRecord(structNew("linked"), "", local.dependentInstanceTitleMap, local.qDependentInstance, this.helper.snake2camel))/>
|
||||
</cfloop>
|
||||
|
||||
<cfset "out.instance.dependencies"=[]/>
|
||||
<cfloop query=#local.qDependency#>
|
||||
<cfset arrayAppend(out.instance.dependencies, this.helper.appendRecord(structNew("linked"), "", local.dependencyTitleMap, local.qDependency, this.helper.snake2camel))/>
|
||||
</cfloop>
|
||||
<!--- <cfset "out.instance.availableResourceRealms"=[]/>
|
||||
<cfloop query=#local.qAvailableResourceRealm#>
|
||||
<cfset arrayAppend(out.instance.availableResourceRealms, this.helper.appendRecord(structNew("linked"), "", local.realmTitleMap, local.qAvailableResourceRealm, this.helper.snake2camel))/>
|
||||
</cfloop> --->
|
||||
|
||||
<cfset "out.runDurationMs"=getTickCount() - request.startTickCount/>
|
||||
<!--- <cfdump var=#local.qCurrentState#/>
|
||||
<cfdump var=#out#/>
|
||||
<cfabort/> --->
|
||||
<cfreturn representationOf(out) />
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="patch">
|
||||
<cfargument name="instanceUid" type="string" required=true hint="type:guid"/>
|
||||
<cfargument name="displayName" type="string" required=false hint="type:string"/>
|
||||
<!--- <cfargument name="resourceRealmId" type="string" required=false hint="type:integer"/> --->
|
||||
<cfargument name="descr" type="string" required=false default="" hint="type:varchar (no cleanup here!)"/>
|
||||
|
||||
<!--- ****** проверка уникальности --->
|
||||
<cftry>
|
||||
<cfset checkDisplayName(arguments.displayName, arguments.usrId, arguments.instanceUid)/><!--- как идея - офорить как обертку, возвращающую то же значение. Но будет соблазн еще оттримить иначе пофиксить, а это уже избыточная функция и должно усложнить название --->
|
||||
@@ -416,42 +356,28 @@
|
||||
<cfif structKeyExists(arguments,"displayName")>
|
||||
,display_name=<cfqueryparam cfsqltype="cf_sql_varchar" value="#htmlEditFormat(arguments.displayName)#" />
|
||||
</cfif>
|
||||
<!--- <cfif structKeyExists(arguments,"displayName")>
|
||||
,resource_realm_id=<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.resourceRealmId#" />
|
||||
</cfif> --->
|
||||
<cfif structKeyExists(arguments,"descr")>
|
||||
,descr=<cfqueryparam cfsqltype="cf_sql_varchar" value="#htmlEditFormat(arguments.descr)#" />
|
||||
</cfif>
|
||||
where instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceUid#" />;
|
||||
--select @@rowcount as cnt;
|
||||
</cfquery>
|
||||
|
||||
<!--- <cfif local.qSave.cnt EQ 0>
|
||||
<cfreturn noData().withStatus(404, "Record Not Found") />
|
||||
</cfif> --->
|
||||
|
||||
<cfcatch type="invalidParamValue">
|
||||
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfreturn noData().withStatus(204, "No Content") />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="delete" hint="Удаление экземпляра сервиса по ключу. Допускается в статусе not configured">
|
||||
<cfargument name="instanceUid" type="string" required=true hint="type:guid"/>
|
||||
|
||||
<cftry>
|
||||
<cfset this.helper.validateField(arguments, "instanceUid", "guid")/>
|
||||
|
||||
<cfcatch type="invalidParamValue">
|
||||
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfset local={}/>
|
||||
<cftry>
|
||||
|
||||
<cfquery name="local.qCheckAccess" result="local.result">
|
||||
select count(*) as cnt
|
||||
from instance e
|
||||
@@ -465,7 +391,6 @@
|
||||
"Instance is not accessible for the current user (possibly does not belong to the default specification)")
|
||||
).withStatus(404)/>
|
||||
</cfif>
|
||||
|
||||
<!--- халява какая-то --->
|
||||
<cfquery name="local.qCheckOperation" result="local.result">
|
||||
select count(*) as cnt
|
||||
@@ -479,7 +404,6 @@
|
||||
"Operation already started", "Instance deletion disabled when operation is started")
|
||||
).withStatus(422)/>
|
||||
</cfif>
|
||||
|
||||
<cfquery name="local.qCheckState" result="local.result">
|
||||
select count(*) as cnt
|
||||
from instance_state st
|
||||
@@ -491,7 +415,6 @@
|
||||
"Instance has a state", "Instance deletion disabled when having state")
|
||||
).withStatus(422)/>
|
||||
</cfif>
|
||||
|
||||
<!--- мы не включаем проверку доступа в саму операцию удаления, а выполняем отдельно --->
|
||||
<cfquery name="local.qSave">
|
||||
delete from instance_state
|
||||
@@ -501,26 +424,18 @@
|
||||
delete from instance
|
||||
where instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceUid#" null=#!isValid('guid',arguments.instanceUid)#/>;
|
||||
</cfquery>
|
||||
|
||||
<cfcatch type="any">
|
||||
<cfreturn representationOf(this.helper.formatException(cfcatch, "Internal Error")).withStatus(500)/><!--- это не нужно показывать в продуктиве --->
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfreturn noData().withStatus(204, "No Content") />
|
||||
</cffunction><!--- delete --->
|
||||
|
||||
|
||||
|
||||
<!--- неудобно бегать из одного компонента в соседний при том, что разделение ответственности между ними получается довольно странное
|
||||
Решил, что логичнее повесить проверки уникальности и генерацию дефолтов на коллекцию, тем более и связей так меньше --->
|
||||
|
||||
<cffunction name="checkDisplayName">
|
||||
<cfargument name="displayName" required=true/>
|
||||
<cfargument name="usrId" type="numeric" required=true/>
|
||||
<cfargument name="instanceUid" type="guid" required=true/>
|
||||
|
||||
<cfset CreateObject("component", "instance_ls").checkDisplayName(arguments.displayName, arguments.usrId, arguments.instanceUid)/>
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
@@ -1,10 +1,8 @@
|
||||
<cfcomponent extends="taffy.core.resource" taffy:uri="/instances">
|
||||
|
||||
<cfsilent>
|
||||
<cfimport prefix="m" taglib="../lib"/>
|
||||
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/><!---*** странно, почему мы его видим?---><!---вынести в апп?--->
|
||||
</cfsilent>
|
||||
|
||||
<!---спецификация полей, пригодных для фильтрации (?и сортировки)--->
|
||||
<cfset this.fieldsSpec={
|
||||
"instance_uid"={prefix="inr", type="guid"},
|
||||
@@ -48,8 +46,6 @@
|
||||
"st_instance_uid"={prefix="inr", type="integer"} --->
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
<cffunction name="get" hint="Список экземпляров сервисов, принадлежащих данному клиенту">
|
||||
<cfargument name="pageSize" type="string" hint="type:integer" required=false default="100"/>
|
||||
<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="search" type="string" hint="type:string, free search (black box)" required=false default=""/>
|
||||
<!---сюда можно воткнуть спецификацию полей для сортировки и фильтрации, но только ручками, идея компактного кода еще более отдаляется--->
|
||||
|
||||
<!---parse and validate request parameters--->
|
||||
<cfset local={}/>
|
||||
<cftry>
|
||||
<cfset this.helper.validateField(arguments, "pageSize", "integer")/>
|
||||
<cfset this.helper.validateField(arguments, "page", "integer")/>
|
||||
|
||||
<!---мы мирно игнорируем поля, отсутствующие в спецификации, что позволяет не делать исключения для orderBy и т.п.--->
|
||||
<cfset var filter=this.helper.parseFilterParams(this.fieldsSpec)/>
|
||||
<cfset var order=this.helper.parseOrderBy(this.fieldsSpec, arguments.orderBy)/>
|
||||
|
||||
<cfset local.fieldsToOutput=""/>
|
||||
<!--- <cfif listLen(arguments.fields)> ---><!--- *** если идти от arguments.fields, будет лаконичнее --->
|
||||
<!--- *** если идти от arguments.fields, будет лаконичнее --->
|
||||
<cfloop collection=#this.fieldsSpec# item="fld">
|
||||
<!--- <cfoutput>#this.helper.snake2camel(trim(fld))#</cfoutput> --->
|
||||
<!--- *** в данном случае мы некорректно ограничиваем состав выводимых полей
|
||||
полями, перечисленными в fieldSpec --->
|
||||
<cfif listFind(arguments.fields, this.helper.snake2camel(trim(fld)))
|
||||
@@ -81,13 +73,10 @@
|
||||
</cfif>
|
||||
</cfloop>
|
||||
<!--- </cfif> --->
|
||||
|
||||
<cfset local.fieldsToQueryFor = local.fieldsToOutput/>
|
||||
<cfset local.fieldsShortList=""/>
|
||||
|
||||
<!--- теперь добавим в перечень полей, которые нужно оставить, поля для фильтрации и сортировки --->
|
||||
<cfloop array=#filter# index="fltr">
|
||||
<!--- <cfset var fltr = structFind(filter,item)/> --->
|
||||
<cfif listLen(fltr.field,".") EQ 2>
|
||||
<cfset var fld = listGetAt(fltr.field,2,".")/>
|
||||
<cfelseif listLen(fltr.field,".") EQ 1>
|
||||
@@ -120,12 +109,10 @@
|
||||
<cfset local.fieldsShortList=listAppend(local.fieldsShortList,fld)/>
|
||||
</cfif>
|
||||
</cfloop>
|
||||
|
||||
<cfcatch type="invalidParamValue">
|
||||
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cftry><!--- *** времянка, пока глотается ошибка 500 --->
|
||||
<!--- Такая бодяга. Кастомные сериализаторы не умеют вложенных структур (поразительно, или я не нашел как).
|
||||
Стандартный сериализатор не умеет выводить дату в ISO 8601.
|
||||
@@ -133,7 +120,6 @@
|
||||
Также на стороне БД приходится конвертировать GUID, потому что драйвер pg jdbc его представляет как структуру из 2 чисел.
|
||||
Еще jsonb как-то странно сериализуется, в 3 поля, вместо одного Value (решается преобразованием ::text)
|
||||
--->
|
||||
|
||||
<m:field_set titleMapOut="local.titleMap"
|
||||
lengthOut="local.fieldCount"
|
||||
nameListOut="local.definedRecordFields"
|
||||
@@ -154,29 +140,24 @@
|
||||
<m:field>v.svc</m:field>
|
||||
<m:field>v.code</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>u.login as updater_login</m:field>
|
||||
<m:field>u.shortname as updater_shortname</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.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 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_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>case
|
||||
when io.operation IN ('delete', 'suspend') AND io.is_successful then 0 /*null*/
|
||||
when io.is_successful then extract('epoch' from CURRENT_TIMESTAMP - coalesce(io.dt_finish,CURRENT_TIMESTAMP))
|
||||
else 0 end
|
||||
as uptime</m:field>
|
||||
|
||||
<m:field>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 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 --->
|
||||
@@ -185,8 +166,6 @@
|
||||
<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>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
|
||||
when st.instance_uid IS NULL then 'not created'
|
||||
when job_is_pending = 'true' then 'pending'
|
||||
@@ -198,8 +177,6 @@
|
||||
) as explained_status</m:field>
|
||||
<m:field>st.version</m:field>
|
||||
</m:field_set>
|
||||
|
||||
|
||||
<cfquery name="local.qCnt" result="local.result">
|
||||
select count(*) as cnt
|
||||
from (
|
||||
@@ -242,10 +219,6 @@
|
||||
) inr
|
||||
where 1=1 <m:filter_build filter=#filter#/>
|
||||
</cfquery>
|
||||
|
||||
<!--- <cfdump var=#filter#/><cfabort/> --->
|
||||
|
||||
|
||||
<cfquery name="local.qRead" result="local.result">
|
||||
select
|
||||
<cfif listLen(local.fieldsToOutput)>#local.fieldsToOutput#<cfelse>*</cfif>
|
||||
@@ -273,23 +246,19 @@
|
||||
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') --->
|
||||
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)>
|
||||
AND (
|
||||
(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#%'/>)
|
||||
)
|
||||
</cfif>
|
||||
|
||||
) inr
|
||||
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--->
|
||||
limit #arguments.pageSize#
|
||||
offset #arguments.pageSize*(arguments.page-1)#
|
||||
</cfquery>
|
||||
<!---<cfdump var=#arguments#/><cfdump var=#local.qRead#/><cfabort/> --->
|
||||
|
||||
<cfquery name="local.qTotal">
|
||||
select count(*) as cnt
|
||||
from instance e
|
||||
@@ -298,7 +267,6 @@
|
||||
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 (select ist.instance_state_uid, ist.instance_uid, ist.version, ist.dt_state, ist.is_test
|
||||
,(ist.instance_data->>'isSuspended') as is_suspended
|
||||
,(ist.instance_data->>'isDeleted') as is_deleted
|
||||
@@ -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
|
||||
on (o.instance_uid=lastv.instance_uid AND o.dt_submit=lastv.dt_submit) ) io
|
||||
on (e.instance_uid=io.instance_uid)
|
||||
|
||||
<!--- specificationId инжектируется в arguments scope в Application.cfc --->
|
||||
where s.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/>
|
||||
<!--- u.usr_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.usrId#/> --->
|
||||
</cfquery>
|
||||
|
||||
<cfset var out=structNew("linked")/>
|
||||
|
||||
<cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/>
|
||||
<cfset "out.total"=#local.qTotal.cnt#/>
|
||||
<cfset "out.resultSetSize"=#local.qCnt.cnt#/>
|
||||
<cfset "out.pageSize"=#arguments.pageSize*1#/>
|
||||
<cfset "out.page"=#arguments.page*1#/>
|
||||
<cfset "out.orderBy"=#arguments.orderBy#/>
|
||||
|
||||
<cfset var resultCollection=[]/>
|
||||
<cfloop query=#local.qRead# <!--- startRow=#startrow# endRow=#(startrow+maxrows-1)# --->>
|
||||
<cfset var rec=structNew("linked")/>
|
||||
<cfset this.helper.appendRecord(rec, "", local.titleMap, local.qRead, this.helper.snake2camel)/>
|
||||
<cfset arrayAppend(resultCollection, rec)/>
|
||||
</cfloop>
|
||||
|
||||
<cfset "out.size"=#arrayLen(resultCollection)#/>
|
||||
<cfset "out.results"=#resultCollection#/>
|
||||
<cfset "out.runDurationMs"=getTickCount()-request.startTickCount/>
|
||||
<!---<cfset "out.sql"=#local.result.sql#/>--->
|
||||
<cfreturn representationOf(out)/>
|
||||
|
||||
<cfcatch type="any"> <!--- {"message"=cfcatch.message, "detail"=cfcatch.detail} --->
|
||||
<cfreturn representationOf(cfcatch).withStatus(500)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
</cffunction><!--- get --->
|
||||
|
||||
|
||||
<cffunction name="post" hint="ВНИМАНИЕ! У текущего контрагента должна быть спецификация, в которую будет вписан создаваемый экземпляр. Новая пустая запись экземпляра. Фактическое развертывание выполняется отдельно,асинхронной операцией create сконфигурированного экземпляра. Одновременно мы создаем строку в спецификации по умолчанию и связываем экземпляр с этой строкой. Первичный ключ генерируется. Текущий пользователь, контракт, спецификация получаются из контекста.">
|
||||
<cfargument name="displayName" type="string" required=true hint="type:string"/>
|
||||
<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="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")>
|
||||
<cfreturn representationOf("arguments.specificationId not defined").withStatus(500)/>
|
||||
</cfif>
|
||||
@@ -365,16 +318,11 @@
|
||||
<cfif !(arguments.specificationId GT 0)>
|
||||
<cfreturn representationOf("specification not defined (arguments.specificationId should be a posititve integer)").withStatus(500)/>
|
||||
</cfif>
|
||||
|
||||
<cfset var local={}/>
|
||||
|
||||
|
||||
<cfset local.instanceUid=#createGUID()#/>
|
||||
|
||||
<cftry>
|
||||
<cfset this.helper.keyExistsAndValid(arguments, "serviceId", "integer")/>
|
||||
<cfset checkDisplayName(arguments.displayName, arguments.usrId, local.instanceUid)/>
|
||||
|
||||
<!--- делаем вставку в спецификацию и таблицу экземпляров --->
|
||||
<cfquery name="local.qSpecItem">
|
||||
insert into specification_item
|
||||
@@ -392,7 +340,6 @@
|
||||
,<cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.usrId#" />
|
||||
) returning specification_item_id;
|
||||
</cfquery>
|
||||
|
||||
<cfquery name="local.qSave">
|
||||
insert into instance
|
||||
(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#" />
|
||||
);
|
||||
</cfquery>
|
||||
|
||||
<cfcatch type="invalidParamValue">
|
||||
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfreturn noData()
|
||||
.withHeaders({location: "./#local.instanceUid#"})
|
||||
.withStatus(201, "Created")
|
||||
/>
|
||||
</cffunction><!--- post --->
|
||||
|
||||
|
||||
|
||||
<cffunction name="checkDisplayName">
|
||||
<cfargument name="displayName" required=true/>
|
||||
<cfargument name="usrId" type="numeric" required=true/>
|
||||
<cfargument name="instanceUid" type="guid" required=true/>
|
||||
|
||||
<cfset var local={}/>
|
||||
<cfset var display_name=trim(lcase(arguments.displayName))/>
|
||||
|
||||
<cfif len(display_name) LT 3>
|
||||
<cfthrow type="InvalidParamValue" message="Instance Display Name too short" detail="Имя должно быть не короче 3 символов"/>
|
||||
<cfelseif len(display_name) GT 80>
|
||||
@@ -454,20 +394,16 @@
|
||||
</cfif>
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="generateDefaultName" returnType="string">
|
||||
<!--- *** Это некорректно, потому что имя может содержать пробелы и т.п. --->
|
||||
<!--- *** Неуклюже и медленно --->
|
||||
<!--- Эти валидации и генерации занимают удивительно много рабочего времени --->
|
||||
<cfargument name="service_id" type="numeric"/>
|
||||
<cfargument name="usr_id" type="numeric"/>
|
||||
|
||||
<cfset var local={}/>
|
||||
|
||||
<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#/>
|
||||
</cfquery>
|
||||
|
||||
<cfquery name="local.qInst">
|
||||
select display_name
|
||||
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 service_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.service_id#/>
|
||||
</cfquery>
|
||||
|
||||
<cfset var prefixLen=len(local.qSvc.svc_short)+1/>
|
||||
<cfset var i=1/>
|
||||
<cfloop query="local.qInst">
|
||||
@@ -491,54 +426,6 @@
|
||||
</cfif>
|
||||
</cfif>
|
||||
</cfloop>
|
||||
|
||||
<cfreturn "#local.qSvc.svc_short#-#i+1#"/>
|
||||
</cffunction>
|
||||
|
||||
</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
|
||||
--->
|
||||
@@ -4,25 +4,21 @@
|
||||
Но: мы не хотели бы менять положение сущности в дереве. Либо она в корне, либо она ниже. И получится, когда мы выбираем один параметр, нам ни к чему контекст - мы к нему однозначно адресуемся.
|
||||
Проголосуем против избыточности?
|
||||
--->
|
||||
|
||||
<!--- Все методы неявно получают
|
||||
arguments.usrId
|
||||
arguments.contragentId
|
||||
arguments.contractId
|
||||
arguments.specificationId
|
||||
|
||||
arguments.requestArguments.usrId=usrCustomerInfo.usrId; //Integer!
|
||||
arguments.requestArguments.contragentId=usrCustomerInfo.contragentId; //Integer
|
||||
arguments.requestArguments.contractId=usrCustomerInfo.contractId; //Integer
|
||||
arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //Integer
|
||||
--->
|
||||
|
||||
<cfsilent>
|
||||
<cfimport prefix="m" taglib="../lib"/>
|
||||
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/><!---*** странно, почему мы его видим?---><!---вынести в апп?--->
|
||||
</cfsilent>
|
||||
<!--- cfproperty использовать не надо, это для веб сервисов --->
|
||||
|
||||
<cffunction name="init">
|
||||
<!--- *** ---------------- !!! note camelCase in keys naming!!! ----------------- --->
|
||||
<!--- для нового инстанса нам нужно знать хотя бы его класс (сервис) --->
|
||||
@@ -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_uid = "00000000-0000-0000-0000-000000000000"/><!--- *** костыль default=--->
|
||||
<cfset this.instance_uid = "00000000-0000-0000-0000-000000000000"/><!--- *** костыль default=--->
|
||||
|
||||
<cfif structKeyExists(arguments.keys,"instanceOperationCfsParamUid") AND isValid("guid", arguments.keys.instanceOperationCfsParamUid)>
|
||||
<cfset this.instance_operation_cfs_param_uid=arguments.keys.instanceOperationCfsParamUid/>
|
||||
<cfquery name="local.qResolve">
|
||||
@@ -66,20 +61,15 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
<cfif structKeyExists(arguments.params,"resourceRealm")>
|
||||
<cfset this.resourceRealm=arguments.params.resourceRealm/>
|
||||
</cfif>
|
||||
<!--- <cfdump var=#this# abort=true/> --->
|
||||
<!--- <cfdump var=#this#/> --->
|
||||
<cfreturn this>
|
||||
</cffunction>
|
||||
|
||||
<!--- ---------------------------------------------------------------------- --->
|
||||
<!--- Прикладные функции, которые можно использовать в составе выражений. Аргументами им могут служить параметры, от которых мы зависим --->
|
||||
<!--- Добавить обработку исключений --->
|
||||
|
||||
<cffunction name="dummy" returntype="any" access="public">
|
||||
<cfargument name="arg" type="any"/>
|
||||
<cfreturn arg/>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="concat" returntype="string" access="public">
|
||||
<cfset var local={}/>
|
||||
<cfset var s=""/>
|
||||
@@ -88,7 +78,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
</cfloop>
|
||||
<cfreturn s/>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getValue"><!--- используем пока только для параметров, в принципе может видеть больше, чем положено --->
|
||||
<cfargument name="token" type="string"/>
|
||||
<!--- тут такой странный синтаксис: для скоупа params подставляем getCfsParam --->
|
||||
@@ -103,7 +92,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
</cfif>
|
||||
<cfreturn variables[scope][name]/><!--- *** вряд ли это отработает для субпараметров --->
|
||||
</cffunction>
|
||||
|
||||
<!--- может быть, обобщить для наследуемых параметров... или для всех вообще --->
|
||||
<cffunction name="getResourceRealm">
|
||||
<!--- нужна отдельная функция, потому что resourceRealm может браться из параметров операции, а может наследоваться от родительского инстанса --->
|
||||
@@ -111,11 +99,10 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
<!--- если операция не сохранена - мы как узнаем, есть у нее параметр resourceRealm, или нет? наверно, простой джойн тут не поможет
|
||||
но никто не мешает спросить отдельно--->
|
||||
<!--- *** тут возникает определенная путаница из-за того, что часть данных берется из параметров операции, а часть из параметров инстанса (кумулятивных) --->
|
||||
<!--- <cfdump var=#this#/> --->
|
||||
<cfif structKeyExists(this,"resourceRealm") AND len(this.resourceRealm)><!--- может быть, понятнее было бы брать прямо из параметров --->
|
||||
<cfreturn this.resourceRealm/>
|
||||
</cfif>
|
||||
<!--- ищем у даннной операции CFS параметр resourceRealm ---><!--- <cfdump var=#this#/><cfabort/> --->
|
||||
<!--- ищем у даннной операции CFS параметр resourceRealm --->
|
||||
<cfquery name="local.qCfsParam">
|
||||
select p.param_value
|
||||
from svc_operation_cfs_param s
|
||||
@@ -123,7 +110,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
where s.svc_operation_cfs_param = 'resourceRealm'
|
||||
AND p.instance_operation_uid = <cfqueryparam cfsqltype="cf_sql_other" value=#this.instance_operation_uid# null=#!isValid('guid',this.instance_operation_uid)#/>
|
||||
</cfquery>
|
||||
<!--- <cfdump var=#local.qCfsParam#/> --->
|
||||
<!--- --->
|
||||
<cfif local.qCfsParam.recordCount>
|
||||
<!--- параметр определен в операции сервиса. Если его не нашли - значит, не судьба --->
|
||||
@@ -136,7 +122,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
и инстанс-операцию-параметр (регулярная реляционная иерархия)
|
||||
хотя инстанс и операция есть в параметрах (некоторое дублирование, потому что оркестратору все передается через параметры)
|
||||
--->
|
||||
|
||||
<cfset local.instance_uid = this.instance_uid/>
|
||||
<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)#/>
|
||||
AND r.ref_svc_id > 0
|
||||
</cfquery>
|
||||
<!--- <cfdump var=#local.qRefParam#/> --->
|
||||
<cfloop query="local.qRefParam">
|
||||
<cfif structKeyExists(this.params, local.qRefParam.svc_operation_cfs_param) AND isValid('guid', this.params[local.qRefParam.svc_operation_cfs_param])>
|
||||
<cfset local.instance_uid = this.params[local.qRefParam.svc_operation_cfs_param]/>
|
||||
@@ -163,7 +147,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
Можно сделать дополнительную фильтрацию по типу справочника (resourceRealm)
|
||||
--->
|
||||
</cfif>
|
||||
|
||||
<!--- внимание! мы тут опрашиваем параметры инстанса, а не операции! --->
|
||||
<!--- *** тут возникает непонятная ссылка на себя, впрочем, она не мешает --->
|
||||
<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 ri on (rp.instance_uid=ri.instance_uid)
|
||||
WHERE e.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value=#local.instance_uid# null=#!isValid('guid',local.instance_uid)#/>
|
||||
|
||||
UNION
|
||||
|
||||
SELECT
|
||||
i+1 AS i
|
||||
,e.display_name
|
||||
@@ -202,7 +183,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
select param, param_value from r
|
||||
order by r.i desc
|
||||
</cfquery>
|
||||
|
||||
<cfif local.qCfsParam.recordCount EQ 0>
|
||||
<!--- тогда зайдем от параметров операции (только в данном экземпляре, зависимости все должны быть уже созданы) --->
|
||||
<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 ri on (rp.instance_uid=ri.instance_uid)
|
||||
WHERE e.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value=#local.instance_uid# null=#!isValid('guid',local.instance_uid)#/>
|
||||
|
||||
UNION
|
||||
|
||||
SELECT
|
||||
i+1 AS i
|
||||
,e.display_name
|
||||
@@ -243,17 +221,14 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
order by r.i desc
|
||||
</cfquery>
|
||||
</cfif>
|
||||
<!--- <cfdump var=#local.qCfsParam#/>--->
|
||||
<cfloop query="local.qCfsParam">
|
||||
<cfif local.qCfsParam.param EQ "resourceRealm">
|
||||
<cfreturn local.qCfsParam.param_value/>
|
||||
</cfif>
|
||||
</cfloop>
|
||||
<cfreturn "Resource Realm Not Found"/>
|
||||
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getCfsParam">
|
||||
<cfargument name="param" type="string"/>
|
||||
<cfargument name="subparam" type="string" required=false/>
|
||||
@@ -264,12 +239,10 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
при этом мы ожидаем в параметрах структуру paramName:{subparamName:subparamValue}
|
||||
но почему не находим в сохраненных? возможно такое совпадение, что в сценарии у нас как раз надо выбрать svcId а они не --->
|
||||
<!--- {"startupConfiguration":{"vdcUid":"ea81db31-2197-407d-b32b-e60577c2671c"}} --->
|
||||
<!--- this.params <cfdump var=#this.params#/>
|
||||
arguments <cfdump var=#arguments# /> --->
|
||||
<cfif structKeyExists(this.params,arguments.param)><!--- AND len(this.params[arguments.param]) --->
|
||||
<cfif structKeyExists(arguments,"subparam")><!--- *** не изящно, но просто и понятно --->
|
||||
<cfreturn (this.params[arguments.param])[arguments.subparam]/>
|
||||
<cfelse>this.params[arguments.param] <!--- <cfdump var=#this.params[arguments.param]#/> --->
|
||||
<cfelse>this.params[arguments.param]
|
||||
<cfreturn this.params[arguments.param]/>
|
||||
</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)#/>
|
||||
AND s.svc_operation_cfs_param = <cfqueryparam cfsqltype="cf_sql_varchar" value=#arguments.param#/>
|
||||
</cfquery>
|
||||
<!--- <cfdump var=#this.keys#/> --->
|
||||
<cfif structKeyExists(arguments,"subparam")><!--- *** не изящно, но просто и понятно --->
|
||||
<cfset var value = deserializeJson(local.qCfsParam.param_value)/>
|
||||
<cfif isStruct(value) AND structKeyExists(value, arguments.subparam)>
|
||||
@@ -293,24 +265,13 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
<cfreturn local.qCfsParam.param_value/>
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<!--- <cffunction name="getValueFromStruct" returntype="string" hint="returns scalar">
|
||||
<cfargument name="struct" type="struct" required="true"/>
|
||||
<cfargument name="path" type="string" required="true"/>
|
||||
|
||||
<cftry>
|
||||
<cfreturn structGet("arguments.struct.#arguments.path#")/>
|
||||
<cfcatch type="any">
|
||||
<!--- можно ожидать ошибки, если по указанному пути расположена не структура --->
|
||||
<cfreturn cfcatch.message/><!--- халява, для упрощения диагностики --->
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
</cffunction> --->
|
||||
|
||||
<cffunction name="getValueFromStruct" returntype="any">
|
||||
<cfargument name="struct" type="struct" required="true"/>
|
||||
<cfargument name="path" type="string" required="true"/>
|
||||
|
||||
<cftry>
|
||||
<cfreturn structGet("arguments.struct.#arguments.path#")/>
|
||||
<cfcatch type="any">
|
||||
@@ -319,24 +280,18 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getStringFromStruct" returntype="string" hint="returns scalar">
|
||||
<cfargument name="struct" type="struct" required="true"/>
|
||||
<cfargument name="path" type="string" required="true"/>
|
||||
|
||||
<cfset var value = getValueFromStruct(arguments.struct,arguments.path)/>
|
||||
<cfif isStruct(value) OR isArray(value)>
|
||||
<cfreturn serializeJson(value)/>
|
||||
</cfif>
|
||||
<cfreturn toString(value)/>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getKeyListFromStruct" returntype="string" hint="returns list">
|
||||
<cfargument name="struct" type="struct" required="true"/>
|
||||
<cfargument name="path" type="string" required="true"/>
|
||||
|
||||
<cftry>
|
||||
<cfreturn structKeyList(structGet("arguments.struct.#arguments.path#"))/>
|
||||
<cfcatch type="any">
|
||||
@@ -346,12 +301,9 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getArrayAsListFromStruct" returntype="string" hint="returns list">
|
||||
<cfargument name="struct" type="struct" required="true"/>
|
||||
<cfargument name="path" type="string" required="true"/>
|
||||
|
||||
<cftry>
|
||||
<cfreturn arrayToList(structGet("arguments.struct.#arguments.path#"))/>
|
||||
<cfcatch type="any">
|
||||
@@ -361,39 +313,11 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<!--- <cffunction name="getInstanceState" returntype="struct">
|
||||
<cfargument name="instanceUid" type="guid" required="true"/>
|
||||
|
||||
<cfset var local={}/>
|
||||
<cfquery name="local.qInstance" datasource="cmdb">
|
||||
select g.instance_state_uid, g.version, g.dt_state, g.instance_data, g.is_test, g.instance_uid
|
||||
from instance_state g
|
||||
where g.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value=#arguments.instanceUid#/>
|
||||
order by g.version desc
|
||||
limit 1
|
||||
</cfquery>
|
||||
<cfreturn deserializeJson(local.qInstance.instance_data)/>
|
||||
<cftry>
|
||||
<cfset var structConfig = deserializeJson(local.qInstance.instance_data)/>
|
||||
<cfcatch type="ANY">
|
||||
<cfreturn {"error":"error parsing state"}/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
<cfif len(structConfig)>
|
||||
<cfreturn structConfig/>
|
||||
</cfif>
|
||||
<cfreturn {}/>
|
||||
</cffunction> --->
|
||||
|
||||
<cffunction name="getInstanceState" returntype="struct">
|
||||
<cfargument name="instanceUid" default=#this.instance_uid#/><!--- type="guid" --->
|
||||
|
||||
<cfif !isValid("guid",arguments.instanceUid)>
|
||||
<cfreturn {}/><!--- иначе при неопределенном параметре мы получаем исключение --->
|
||||
</cfif>
|
||||
|
||||
<cfset var local={}/>
|
||||
<cfquery name="local.qInstance" datasource="cmdb">
|
||||
select g.instance_state_uid, g.version, g.dt_state, g.instance_data, g.is_test, g.instance_uid
|
||||
@@ -402,7 +326,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
order by g.version desc
|
||||
limit 1
|
||||
</cfquery>
|
||||
<!--- <cfreturn deserializeJson(local.qInstance.instance_data)/><cfabort/> --->
|
||||
<cftry>
|
||||
<cfset var structConfig = deserializeJson(local.qInstance.instance_data)/>
|
||||
<cfcatch type="ANY">
|
||||
@@ -414,19 +337,14 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
</cfif>
|
||||
<cfreturn structConfig/>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getResourceRealmConfig" returntype="struct">
|
||||
<cfargument name="resourceRealm" type="string" default=#getResourceRealm()#/><!--- платформа может быть определена для родительского инстанса где то в иерархии --->
|
||||
|
||||
<cfset var local={}/>
|
||||
<cfquery name="local.qResourceRealm" datasource="cmdb">
|
||||
select r.resource_realm_id, r.properties
|
||||
from resource_realm r
|
||||
where r.resource_realm=<cfqueryparam cfsqltype="cf_sql_varchar" value=#arguments.resourceRealm#/>
|
||||
</cfquery>
|
||||
<!--- <cfdump var=#arguments#/>
|
||||
<cfdump var=#local.qResourceRealm#/> --->
|
||||
<cftry>
|
||||
<cfset var structConfig = deserializeJson(local.qResourceRealm.properties)/>
|
||||
<cfcatch type="ANY">
|
||||
@@ -439,17 +357,10 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
</cfif>
|
||||
<cfreturn {}/>
|
||||
</cffunction>
|
||||
|
||||
|
||||
|
||||
|
||||
<!--- ReST methods --->
|
||||
|
||||
<!--- ----------------------------------------------------------------------------------------- --->
|
||||
<!--- ----------------------------------------------------------------------------------------- --->
|
||||
<!--- ----------------------------------------------------------------------------------------- --->
|
||||
|
||||
|
||||
<cffunction name="get" hint="CFS параметр операции инстанса">
|
||||
<cfargument name="instanceOperationCfsParamUid" type="string" required=true hint="type:guid"/>
|
||||
<cftry>
|
||||
@@ -458,16 +369,13 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfset local={}/>
|
||||
|
||||
<cfquery name="local.qCfsParam" result="local.result">
|
||||
select
|
||||
<m:field_set titleMapOut="local.titleMap" lengthOut="fieldCount">
|
||||
<m:field>iop.instance_operation_cfs_param_uid::text as instance_operation_cfs_param_uid</m:field>
|
||||
<m:field>iop.instance_operation_uid::text as instance_operation_uid</m:field>
|
||||
<m:field>iop.svc_operation_cfs_param_id</m:field>
|
||||
<!--- <m:field>iop.param_value</m:field> --->
|
||||
<m:field>case when sop.is_sensitive then '********' else iop.param_value end as param_value </m:field><!--- внимание! если параметр типа MAP, то значение нужно разобрать и замаскировать секреты --->
|
||||
<m:field>iop.note</m:field>
|
||||
<m:field>to_char(iop.dt_created, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as dt_created</m:field>
|
||||
@@ -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_disabled</m:field>
|
||||
<m:field>sop.man</m:field>
|
||||
|
||||
<m:field>sop.func</m:field>
|
||||
<m:field>sop.expression</m:field>
|
||||
<m:field>sop.nested_ref</m:field>
|
||||
<m:field>sop.state_path</m:field>
|
||||
<m:field>sop.depends_on_cfs_params</m:field>
|
||||
|
||||
|
||||
<m:field>sop.config::text as config</m:field>
|
||||
<m:field>e.service_id</m:field>
|
||||
<m:field>e.instance_uid::text as instance_uid</m:field>
|
||||
@@ -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)#/>
|
||||
AND si.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/>
|
||||
</cfquery>
|
||||
|
||||
<cfif local.qCfsParam.recordCount EQ 0>
|
||||
<cfreturn representationOf(this.helper.formatMessage("Not Found")).withStatus(404)/>
|
||||
</cfif>
|
||||
|
||||
<cfif len(local.qCfsParam.func)><!--- приоритет отдается функции перед списком значений--->
|
||||
<cfset var args = {
|
||||
"functionName":"#local.qCfsParam.func#",
|
||||
@@ -515,7 +418,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
"contractId":#arguments.contractId#
|
||||
}/> <!--- если появятся новые аргументы у новых функций, будем добавлять их сюда --->
|
||||
<cfset local.qCfsParam.value_list=generateValueList(argumentCollection=#args#)/> <!--- можно перечислить именованные аргументы обычным порядком, но с коллекцией потенциально более гибко --->
|
||||
<!--- <cfdump var=#local.qCfsParam#/><cfabort/> --->
|
||||
<cfif len(trim(local.qCfsParam.value_list)) AND listLen(local.qCfsParam.value_list) EQ 1>
|
||||
<cfset local.qCfsParam.default_value=local.qCfsParam.value_list/>
|
||||
</cfif>
|
||||
@@ -538,43 +440,32 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
</cftry>
|
||||
<cfset local.qCfsParam.value_list = getListFromState(currentState, local.qCfsParam.state_path)/>
|
||||
</cfif>
|
||||
|
||||
<cfif (len(local.qCfsParam.func) OR len(local.qCfsParam.expression) OR len(local.qCfsParam.state_path) OR len(local.qCfsParam.nested_ref))
|
||||
AND len(local.qCfsParam.value_list) EQ 0>
|
||||
<cfset local.qCfsParam.value_list = []/>
|
||||
</cfif>
|
||||
|
||||
<cfif local.qCfsParam.data_type EQ "map" OR local.qCfsParam.data_type EQ "map-fixed" OR local.qCfsParam.data_type EQ "array-map-fixed">
|
||||
<cfset processMap(local.qCfsParam)/><!--- query passed by reference --->
|
||||
</cfif>
|
||||
|
||||
<cfset var out=structNew("linked")/>
|
||||
<cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/>
|
||||
|
||||
<cfset "out.instanceOperationCfsParam" = this.helper.appendRecord(
|
||||
structNew("linked"), "", local.titleMap, local.qCfsParam, this.helper.snake2camel
|
||||
)/>
|
||||
|
||||
<cfset "out.runDurationMs"=getTickCount() - request.startTickCount/>
|
||||
<cfreturn representationOf(out) />
|
||||
</cffunction><!--- get --->
|
||||
|
||||
|
||||
<cffunction name="delete" hint="Удаление CFS параметра операции по ключу.">
|
||||
<cfargument name="instanceOperationCfsParamUid" type="string" required=true hint="type:guid"/>
|
||||
|
||||
<cftry>
|
||||
<cfset this.helper.validateField(arguments, "instanceOperationCfsParamUid", "guid")/>
|
||||
<!--- *** Нужна проверка, что операция не была выполнена, иначе она становится архивной --->
|
||||
|
||||
<cfcatch type="invalidParamValue">
|
||||
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfset local={}/>
|
||||
<cftry><!--- *** без проверок существования --->
|
||||
|
||||
<cfquery name="local.qCheck" result="local.result">
|
||||
select
|
||||
io.dt_submit, io.submit_result
|
||||
@@ -585,19 +476,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
<cfif left(local.qCheck.submit_result,1) EQ "2"><!--- 201 etc --->
|
||||
<cfreturn representationOf(this.helper.formatMessage("Operation already started", "Parameter deletion disabled for started operation")).withStatus(422)/>
|
||||
</cfif>
|
||||
|
||||
<!--- <cfquery name="local.qCheckSpecification" result="local.result">
|
||||
select si.specification_id
|
||||
from instance_operation_cfs_param iop
|
||||
join instance_operation io on iop.instance_operation_uid=io.instance_operation_uid
|
||||
join instance e on (io.instance_uid=e.instance_uid)
|
||||
left outer join specification_item si on (e.specification_item_id=si.specification_item_id)
|
||||
where iop.instance_operation_cfs_param_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationCfsParamUid#" null=#!isValid('guid',arguments.instanceOperationCfsParamUid)#/>
|
||||
AND si.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/>
|
||||
</cfquery>
|
||||
<cfif local.qCheckSpecification.recordCount EQ 0>
|
||||
<cfreturn representationOf(this.helper.formatMessage("Instance not accessible", "Instance does not belong to the current specification, contract or contragent")).withStatus(403)/>
|
||||
</cfif> --->
|
||||
<cfquery name="local.qCheckAccess" result="local.result">
|
||||
select count(*) as cnt
|
||||
from instance_operation_cfs_param iop
|
||||
@@ -610,26 +488,20 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
<cfif local.qCheckAccess.cnt EQ 0>
|
||||
<cfreturn representationOf(this.helper.formatMessage("Instance not accessible", "Instance of this CFS parameter is not accessible to the current user (at least does not belong to the default specification)")).withStatus(403)/>
|
||||
</cfif>
|
||||
|
||||
<cfquery name="local.qSave">
|
||||
delete from instance_operation_cfs_param
|
||||
where instance_operation_cfs_param_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceOperationCfsParamUid#" null=#!isValid('guid',arguments.instanceOperationCfsParamUid)#/>
|
||||
</cfquery>
|
||||
|
||||
<cfcatch type="any">
|
||||
<cfreturn representationOf(this.helper.formatException(cfcatch, "Internal Error")).withStatus(500)/><!--- это не нужно показывать в продуктиве --->
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfreturn noData().withStatus(204, "No Content") />
|
||||
</cffunction><!--- delete --->
|
||||
|
||||
|
||||
<cffunction name="put" hint="запись CFS параметра операции инстанса">
|
||||
<cfargument name="instanceOperationCfsParamUid" type="string" required=true hint="type:guid"/>
|
||||
<cfargument name="paramValue" type="string" required=true/>
|
||||
<cfargument name="note" type="string" required=false default=""/>
|
||||
|
||||
<cfset var local={}/>
|
||||
<cftry>
|
||||
<cfset checkInstanceParam(arguments.instanceOperationCfsParamUid, arguments.paramValue, arguments.usrId)/>
|
||||
@@ -637,7 +509,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfquery name="local.qSave" result="local.result">
|
||||
update instance_operation_cfs_param set
|
||||
dt_created=<cfqueryparam cfsqltype="cf_sql_timestamp" value="#Now()#" />
|
||||
@@ -649,14 +520,10 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
<!--- *** проверить существование - 404 --->
|
||||
<cfreturn noData().withStatus(204, "No Content") />
|
||||
</cffunction><!--- put --->
|
||||
|
||||
|
||||
|
||||
<cffunction name="checkInstanceParam">
|
||||
<cfargument name="instanceOperationCfsParamUid" type="guid" required=true/>
|
||||
<cfargument name="paramValue" required=true/>
|
||||
<cfargument name="usrId" type="numeric" required=true/>
|
||||
|
||||
<cfset var local={}/>
|
||||
<cfquery name="local.qCheck" result="local.result">
|
||||
select svc_operation_cfs_param_id
|
||||
@@ -666,11 +533,8 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
<cfif local.qCheck.recordCount EQ 0>
|
||||
<cfthrow type="invalidParamValue" message="Cannot find CFS parameter by instanceOperationCfsParamUid=#arguments.instanceOperationCfsParamUid#"/>
|
||||
</cfif>
|
||||
|
||||
<cfset CreateObject("component", "instance_operation_cfs_param_ls").checkParam(local.qCheck.svc_operation_cfs_param_id, arguments.paramValue, arguments.usrId, arguments.instanceOperationCfsParamUid)/>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="processMap" returntype="void" access="public">
|
||||
<cfargument name="qParam" type="query" required=true/><!--- работаем с текущей строкой query. передача query это скорее колхоз, всего-то надо 4 понятных аргумента.
|
||||
Конечно, то, что часть из них - id, не упрощает восприяие кода --->
|
||||
@@ -678,7 +542,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
- сформировать дескриптор
|
||||
- замаскировать секреты --->
|
||||
<!--- здесь могут использоваться 2 критерия: формат аргумента, array/struct, либо тип --->
|
||||
|
||||
<cfset local.spContainer = {}/><!--- может быть map или array of map --->
|
||||
<cfset local.spMapArray = []/>
|
||||
<!--- мы хотим обработать и случай array-map-fixed --->
|
||||
@@ -693,7 +556,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
<cfset local.spMapArray = [{"error":"#cfcatch.message#"}]/><!--- теряем все данные --->
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfquery name="local.qSubparam">
|
||||
select
|
||||
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#"/>
|
||||
order by sp.sort
|
||||
</cfquery>
|
||||
<!--- <cfdump var=#local.qSubparam#/><cfabort/> --->
|
||||
|
||||
<cfquery name="local.qInstSubparam">
|
||||
select
|
||||
sp.instance_operation_cfs_param_uid::text as instance_operation_cfs_param_uid
|
||||
@@ -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)#/>
|
||||
order by sp.sort
|
||||
</cfquery>
|
||||
|
||||
<!--- формируем дескриптор --->
|
||||
<cfset var mapDescriptor=structNew("linked")/>
|
||||
<cfset var parser=createObject("component","lib.expression_parser")/>
|
||||
|
||||
<cfloop query="local.qSubparam">
|
||||
<cfset structInsert(mapDescriptor, local.qSubparam.svc_operation_cfs_subparam,
|
||||
{
|
||||
@@ -776,12 +634,10 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
"uniqueScope":"#local.qSubparam.unique_scope#",
|
||||
"defaultCompute":"#local.qSubparam.default_compute#",
|
||||
"isModifiableDefinition":false
|
||||
|
||||
}, true
|
||||
)
|
||||
/>
|
||||
</cfloop>
|
||||
|
||||
<cfloop index="local.i" from=1 to=#arrayLen(local.spMapArray)#><!--- *** искусственное оборачивание в массив вот для этого, не придумал ничего умнее
|
||||
чтобы не дублировать цикл по субпараметрам. Сделано некрасиво, но работать должно.
|
||||
Ну а как сделать? Если массив - делать цикл по массиву, а если map-сразу обрабатыввать map. При этом запрос к таблице сабпараметров не хочется делать лишний раз.
|
||||
@@ -799,7 +655,6 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
</cfloop>
|
||||
</cfif>
|
||||
</cfloop>
|
||||
|
||||
<!--- *** проверку, что это не map-fixed, можно добавить здесь --->
|
||||
<!--- чтобы не вставляли в параметр что попало --->
|
||||
<!--- здесь мы не делаем цикл по массиву, поскольку не поддерживаем массив расширяемых map --->
|
||||
@@ -818,21 +673,16 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
</cfif>
|
||||
</cfloop>
|
||||
</cfif>
|
||||
|
||||
<cfset arguments.qParam.data_descriptor = mapDescriptor/>
|
||||
|
||||
<cfif (arguments.qParam.data_type EQ "array-map-fixed")>
|
||||
<cfset arguments.qParam.param_value = serializeJson(local.spMapArray)/><!--- как есть --->
|
||||
<cfelse>
|
||||
<cfset arguments.qParam.param_value = arrayLen(local.spMapArray) ? serializeJson(local.spMapArray[1]) : ""/><!--- вытаскиваем из массива-обертки --->
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="generateValueList" returntype="string" access="public">
|
||||
<cfargument name="functionName" type="string" required="true"/>
|
||||
<!--- остальные атрибуты необязательные, в argumentCollection (еще вопрос, насколько безопасно объявлять один из аргументов без остальных) --->
|
||||
|
||||
<cfswitch expression=#arguments.functionName#>
|
||||
<cfcase value="">
|
||||
<cfreturn ""/>
|
||||
@@ -848,14 +698,10 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
</cfdefaultcase>
|
||||
</cfswitch>
|
||||
</cffunction>
|
||||
|
||||
|
||||
<cffunction name="getAvailableResourceRealms" returnType="string" access="public">
|
||||
<cfargument name="svcId"/>
|
||||
<cfargument name="contractId"/>
|
||||
|
||||
<cfset var local={}/>
|
||||
|
||||
<cfquery name="local.qAvailableResourceRealm"><!--- *** distinct халява, но придумывать корректную формулировку времени мало --->
|
||||
select distinct r.resource_realm, r.sort
|
||||
from resource_realm r
|
||||
@@ -867,21 +713,16 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
join svc s on r.resource_realm_type_id=s.resource_realm_type_id
|
||||
where s.svc_id=<cfqueryparam cfsqltype="CF_SQL_INTEGER" value=#arguments.svcId# null=#!isValid("integer", arguments.svcId)#/>
|
||||
order by r.sort, r.resource_realm
|
||||
</cfquery> <!--- <cfdump var=#arguments#/> cfdump здесь провоцирует NPE --->
|
||||
</cfquery>
|
||||
<cfif local.qAvailableResourceRealm.recordCount>
|
||||
<cfreturn valueList(local.qAvailableResourceRealm.resource_realm)/>
|
||||
<cfelse>
|
||||
<cfreturn ""/><!--- иначе для пустого резалтсета генерируется null --->
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
|
||||
|
||||
<!--- для вложенных справочников --->
|
||||
<!--- дублировано: deck-tool/instance_operation.cfm --->
|
||||
|
||||
<cffunction name="getSelectedResourceRealm" returnType="string">
|
||||
|
||||
<cfset var local={}/>
|
||||
<cfquery name="local.qSelectedResourceRealm">
|
||||
select iop.param_value
|
||||
@@ -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)#/>
|
||||
AND sop.svc_operation_cfs_param='resourceRealm'
|
||||
order by 1
|
||||
</cfquery> <!--- <cfdump var=#arguments#/> cfdump здесь провоцирует NPE --->
|
||||
</cfquery>
|
||||
<cfreturn local.qSelectedResourceRealm.param_value/>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="generateClosure" returntype="function">
|
||||
<cfargument name="functionName" type="string" required="true"/>
|
||||
<cfargument name="config" type="string" required="true"/>
|
||||
<!--- остальные атрибуты необязательные, в argumentCollection --->
|
||||
|
||||
<cfswitch expression=#arguments.functionName#>
|
||||
<cfcase value="">
|
||||
<cfreturn function(){}/>
|
||||
@@ -916,19 +755,15 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
</cfdefaultcase>
|
||||
</cfswitch>
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="getRefFromRRealmConfig" returntype="any">
|
||||
<cfargument name="resourceRealm" type="string" required="true"/>
|
||||
<cfargument name="config" type="string" required="true"/>
|
||||
|
||||
<cfquery name="qResourceRealmConfig">
|
||||
select properties::text
|
||||
from resource_realm
|
||||
where resource_realm='ngcloud.ru'
|
||||
<!--- <cfqueryparam cfsqltype="cf_sql_varchar" value=#arguments.resourceRealm#/> --->
|
||||
</cfquery>
|
||||
|
||||
<!--- <cfset var local={}/> ---> <!--- паранойя... и есть шансы, что я неправильно понимаю эту химию скоупов--->
|
||||
<!--- паранойя... и есть шансы, что я неправильно понимаю эту химию скоупов--->
|
||||
<cfset var props = deserializeJson(qResourceRealmConfig.properties)/>
|
||||
<cfset var cfg = deserializeJson(arguments.config)/> <!--- удобнее было бы передавать сразу структуру впр --->
|
||||
<cfset cfg={"path":"vcd.providerVdc"}/><!--- *** временный пример для отладки --->
|
||||
@@ -940,12 +775,10 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
<cfset structInsert(result, containerName, structGet("props.#path#"))/>
|
||||
<cfreturn result/>
|
||||
</cffunction>
|
||||
|
||||
<!--- duplicated in deck-tool --->
|
||||
<cffunction name="getListFromState" returntype="string" hint="returns list">
|
||||
<cfargument name="state" type="struct" required="true"/>
|
||||
<cfargument name="path" type="string" required="true"/>
|
||||
|
||||
<cftry>
|
||||
<cfreturn structKeyList(structGet("arguments.state.#arguments.path#"))/>
|
||||
<cfcatch type="any">
|
||||
@@ -954,20 +787,5 @@ arguments.requestArguments.specificationId=usrCustomerInfo.specificationId; //In
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
</cffunction>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</cfcomponent>
|
||||
<!--- [{"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}">
|
||||
|
||||
|
||||
<cfsilent>
|
||||
<cfimport prefix="m" taglib="../lib"/>
|
||||
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/><!---*** странно, почему мы его видим?---><!---вынести в апп?--->
|
||||
</cfsilent>
|
||||
|
||||
|
||||
<cffunction name="get" hint="Метаданные субпараметра CFS-параметра операции экземпляра (значение субпараметра находится в теле параметра)"><!--- *** спросить, может, метод не нужен, а если нужен - наверно, нужно значение --->
|
||||
<cfargument name="instanceOperationCfsParamUid" type="string" required=true hint="type:guid"/>
|
||||
<cfargument name="subparam" type="string" required=true hint="type:string"/>
|
||||
@@ -16,9 +12,7 @@
|
||||
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfset local={}/>
|
||||
|
||||
<cfquery name="local.qRead" result="local.result">
|
||||
select
|
||||
<m:field_set titleMapOut="local.titleMap" lengthOut="fieldCount">
|
||||
@@ -26,7 +20,6 @@
|
||||
<m:field>ios.instance_operation_cfs_subparam</m:field>
|
||||
<m:field formatter=#request.castToBool#>ios.is_sensitive</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_set>
|
||||
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 si.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/> /*tenant isolation, из конфиденциального тут заметки... может быть, имена переменных окружения*/
|
||||
</cfquery>
|
||||
|
||||
<cfif local.qRead.recordCount EQ 0>
|
||||
<cfreturn representationOf(this.helper.formatMessage("Not Found")).withStatus(404)/>
|
||||
</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 "out.queryDurationMs"=getTickCount() - request.startTickCount/>
|
||||
|
||||
<cfset "out.instanceOperationCfsSubparam" = this.helper.appendRecord(
|
||||
structNew("linked"), "", local.titleMap, local.qRead, this.helper.snake2camel
|
||||
)/>
|
||||
|
||||
<cfset "out.runDurationMs"=getTickCount() - request.startTickCount/>
|
||||
<cfreturn representationOf(out) />
|
||||
</cffunction><!---/get --->
|
||||
|
||||
|
||||
<cffunction name="delete" hint="Удаление метаданных субпараметра CFS-параметра операции экземпляра по ключу.">
|
||||
<cfargument name="instanceOperationCfsParamUid" type="string" required=true hint="type:guid"/>
|
||||
<cfargument name="subparam" type="string" required=true hint="type:string"/>
|
||||
|
||||
<cftry>
|
||||
<cfset this.helper.validateField(arguments, "instanceOperationCfsParamUid", "guid")/>
|
||||
|
||||
<cfcatch type="invalidParamValue">
|
||||
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfset local={}/>
|
||||
<cftry>
|
||||
<!--- проверка существования одновременно может служить для изоляции тенантов --->
|
||||
<!--- без проверки стартовавшей операции --->
|
||||
<!--- нужна проверка на изоляцию тенантов --->
|
||||
|
||||
<cfquery name="local.qCheckExistence" result="local.result">
|
||||
select count(*) as cnt
|
||||
from instance_operation_cfs_subparam ios
|
||||
@@ -86,7 +65,6 @@
|
||||
<cfif local.qCheckExistence.cnt EQ 0>
|
||||
<cfreturn representationOf(this.helper.formatMessage("Not Found", "Subparameter specified does not exist")).withStatus(404)/>
|
||||
</cfif>
|
||||
|
||||
<cfquery name="local.qCheckAccess" result="local.result">
|
||||
select count(*) as cnt
|
||||
from instance_operation_cfs_param iop
|
||||
@@ -99,40 +77,31 @@
|
||||
<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)/>
|
||||
</cfif>
|
||||
|
||||
<cfquery name="local.qSave">
|
||||
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)#/>
|
||||
AND instance_operation_cfs_subparam=<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.subparam#"/>
|
||||
</cfquery>
|
||||
|
||||
<cfcatch type="any">
|
||||
<cfreturn representationOf(this.helper.formatException(cfcatch, "Internal Error")).withStatus(500)/><!--- *** это не нужно показывать в продуктиве --->
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfreturn noData().withStatus(204, "No Content") />
|
||||
</cffunction><!--- delete --->
|
||||
|
||||
|
||||
<cffunction name="put" hint="запись метаданных субпараметра CFS-параметра операции инстанса">
|
||||
<cfargument name="instanceOperationCfsParamUid" type="string" required=true hint="type:guid"/>
|
||||
<cfargument name="subparam" type="string" required=true hint="type:string"/>
|
||||
<cfargument name="isSensitive" type="boolean" required=false default=false hint="type:boolean"/>
|
||||
<cfargument name="note" type="string" required=false default=""/> <!--- *** XSS!!! --->
|
||||
|
||||
<cftry>
|
||||
<cfset this.helper.validateField(arguments, "instanceOperationCfsParamUid", "guid")/>
|
||||
<cfset this.helper.validateField(arguments, "isSensitive", "boolean")/>
|
||||
<!--- *** Нужна проверка, что операция не была выполнена, иначе она становится архивной --->
|
||||
|
||||
<cfcatch type="invalidParamValue">
|
||||
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfset var local={}/>
|
||||
|
||||
<cfquery name="local.qCheckAccess" result="local.result">
|
||||
select count(*) as cnt
|
||||
from instance_operation_cfs_param iop
|
||||
@@ -145,7 +114,6 @@
|
||||
<cfif local.qCheckAccess.cnt EQ 0>
|
||||
<cfreturn representationOf(this.helper.formatMessage("Not Accessible", "Instance CFS parameter not found or access denied")).withStatus(404)/>
|
||||
</cfif>
|
||||
|
||||
<cfquery name="local.qCheckExistence" result="local.result">
|
||||
select count(*) as cnt
|
||||
from instance_operation_cfs_subparam iop
|
||||
@@ -155,7 +123,6 @@
|
||||
<cfif local.qCheckExistence.cnt EQ 0>
|
||||
<cfreturn representationOf(this.helper.formatMessage("Not Found", "Subparameter specified does not exist")).withStatus(404)/>
|
||||
</cfif>
|
||||
|
||||
<cfquery name="local.qSave" result="local.result">
|
||||
update instance_operation_cfs_subparam set
|
||||
dt_updated=<cfqueryparam cfsqltype="cf_sql_timestamp" value="#Now()#" />
|
||||
@@ -168,5 +135,4 @@
|
||||
<!--- *** проверить существование - 404 --->
|
||||
<cfreturn noData().withStatus(204, "No Content") />
|
||||
</cffunction><!--- put --->
|
||||
|
||||
</cfcomponent>
|
||||
@@ -1,25 +1,15 @@
|
||||
<cfcomponent extends="taffy.core.resource" taffy:uri="/instanceOperationCfsParams/{instanceOperationCfsParamUid}/subparams">
|
||||
<!--- забавно, что мы организуем эндпойнт коллекции только ради операции создания. Список (коллекция) отдельно не используется, а выгружается в составе более высокоуровневых сущностей --->
|
||||
|
||||
|
||||
<cfsilent>
|
||||
<cfimport prefix="m" taglib="../lib"/>
|
||||
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/>
|
||||
</cfsilent>
|
||||
|
||||
|
||||
<cffunction name="post" hint="создание метаданных субпараметра CFS параметра операции инстанса">
|
||||
<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=false default=false hint="type:boolean"/>
|
||||
<cfargument name="note" type="string" required=false default="" hint="type:string"/>
|
||||
<!--- 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>
|
||||
<cfset this.helper.validateField(arguments, "instanceOperationCfsParamUid", "guid")/>
|
||||
<cfset this.helper.validateField(arguments, "isSensitive", "boolean")/>
|
||||
@@ -27,9 +17,7 @@
|
||||
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfset local={}/>
|
||||
|
||||
<cfquery name="local.qCheckAccess" result="local.result">
|
||||
select count(*) as cnt
|
||||
from instance_operation_cfs_param iop
|
||||
@@ -42,7 +30,6 @@
|
||||
<cfif local.qCheckAccess.cnt EQ 0>
|
||||
<cfreturn representationOf(this.helper.formatMessage("Instance CFS parameter not found or access denied")).withStatus(404)/>
|
||||
</cfif>
|
||||
|
||||
<cfquery name="local.qCheckDuplicates" result="local.result">
|
||||
select count(*) as cnt
|
||||
from instance_operation_cfs_subparam ios
|
||||
@@ -52,7 +39,6 @@
|
||||
<cfif local.qCheckDuplicates.cnt GT 0>
|
||||
<cfreturn representationOf(this.helper.formatMessage("Subparameter already exists")).withStatus(400)/>
|
||||
</cfif>
|
||||
|
||||
<cfquery name="local.qSave" result="local.result">
|
||||
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)
|
||||
@@ -68,14 +54,8 @@
|
||||
,<cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.usrId#" />
|
||||
);
|
||||
</cfquery>
|
||||
|
||||
|
||||
|
||||
<cfreturn noData()
|
||||
.withStatus(201, "Created")
|
||||
/>
|
||||
</cffunction><!--- get --->
|
||||
|
||||
|
||||
|
||||
</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}">
|
||||
|
||||
<cfsilent>
|
||||
<cfimport prefix="m" taglib="../lib"/>
|
||||
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/>
|
||||
</cfsilent>
|
||||
|
||||
|
||||
<cffunction name="get" hint="Шаблон операции экземпляра">
|
||||
<cfargument name="instanceUid" type="string" required=true hint="type:guid|'default'"/>
|
||||
<cfargument name="svcOperationId" type="string" required=true hint="type:integer"/>
|
||||
|
||||
<cftry>
|
||||
<cfif arguments.instanceUid NEQ 'default'>
|
||||
<cfset this.helper.validateField(arguments, "instanceUid", "guid")/>
|
||||
</cfif>
|
||||
<cfset this.helper.validateField(arguments, "svcOperationId", "integer")/>
|
||||
|
||||
<cfcatch type="invalidParamValue">
|
||||
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfset var local={}/>
|
||||
|
||||
<cfquery name="local.qSvcOperation" result="local.result">
|
||||
select
|
||||
<m:field_set titleMapOut="local.titleMap" lengthOut="local.fieldCount">
|
||||
@@ -36,11 +29,9 @@
|
||||
from svc_operation o
|
||||
where o.svc_operation_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.svcOperationId#" null=#!isValid('integer',arguments.svcOperationId)#/>
|
||||
</cfquery>
|
||||
|
||||
<cfif local.qSvcOperation.recordCount EQ 0>
|
||||
<cfreturn representationOf(this.helper.formatMessage("Not Found")).withStatus(404)/>
|
||||
</cfif>
|
||||
|
||||
<!--- получаем параметры из свежего стейта --->
|
||||
<cfset local.instanceDataParams = {}/>
|
||||
<cfset var currentState = {}/>
|
||||
@@ -62,13 +53,10 @@
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
</cfif>
|
||||
|
||||
|
||||
<cfquery name="local.qCfsParam" result="local.result">
|
||||
select
|
||||
<m:field_set titleMapOut="local.cfsParamMap" lengthOut="local.fieldCount">
|
||||
<m:field title="ID" cfSqlType="CF_SQL_INTEGER">p.svc_operation_cfs_param_id</m:field>
|
||||
<!--- <m:field cfSqlType="CF_SQL_INTEGER">p.svc_operation_id</m:field> --->
|
||||
<m:field>p.svc_operation_cfs_param</m:field>
|
||||
<m:field>p.label</m:field>
|
||||
<m:field>p.data_type</m:field>
|
||||
@@ -92,7 +80,6 @@
|
||||
<m:field>p.man</m:field>
|
||||
<m:field>p.sort</m:field>
|
||||
<m:field>p.nested_ref</m:field>
|
||||
<!--- <m:field>p.config::text as config</m:field> --->
|
||||
<m:field>p.config::text</m:field><!--- в таком виде конфиг доступен для кода, но не выводится в респонсе --->
|
||||
<m:field>null as nested_ref_data</m:field>
|
||||
<m:field>p.state_path</m:field>
|
||||
@@ -114,8 +101,6 @@
|
||||
AND p.is_actual
|
||||
order by p.sort, p.svc_operation_cfs_param_id
|
||||
</cfquery>
|
||||
|
||||
|
||||
<cfloop query="local.qCfsParam">
|
||||
<cfif len(local.qCfsParam.func)><!--- приоритет отдается функции перед списком значений--->
|
||||
<cfset var args = {
|
||||
@@ -124,7 +109,6 @@
|
||||
"contractId":#arguments.contractId#
|
||||
}/> <!--- если появятся новые аргументы у новых функций, будем добавлять их сюда --->
|
||||
<cfinvoke component="instance_operation_cfs_param" method="generateValueList" argumentCollection=#args# returnVariable="local.qCfsParam.value_list"/>
|
||||
|
||||
<cfif len(trim(local.qCfsParam.value_list)) AND listLen(local.qCfsParam.value_list) EQ 1>
|
||||
<cfset local.qCfsParam.default_value=local.qCfsParam.value_list/><!--- *** не очень красиво перетирать query, но делаем это довольно часто --->
|
||||
</cfif>
|
||||
@@ -147,12 +131,10 @@
|
||||
returnVariable="local.qCfsParam.value_list"
|
||||
/>
|
||||
</cfif>
|
||||
|
||||
<cfif (len(local.qCfsParam.func) OR len(local.qCfsParam.expression) OR len(local.qCfsParam.state_path) OR len(local.qCfsParam.nested_ref))
|
||||
AND len(local.qCfsParam.value_list) EQ 0>
|
||||
<cfset local.qCfsParam.value_list = []/>
|
||||
</cfif>
|
||||
|
||||
<cfif 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">
|
||||
@@ -184,43 +166,31 @@
|
||||
where sp.svc_operation_cfs_param_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#svc_operation_cfs_param_id#"/>
|
||||
order by sp.sort
|
||||
</cfquery>
|
||||
|
||||
|
||||
|
||||
<cfset var mapDescriptor=structNew("linked")/>
|
||||
<!--- *** выдавать на фронт expression нам ни к чему, это временное явление --->
|
||||
<cfloop query="local.qSubparam">
|
||||
|
||||
<cfif len(local.qSubparam.func)><!--- приоритет отдается функции перед списком значений--->
|
||||
<cfset var args = {
|
||||
"functionName":"#local.qSubparam.func#",
|
||||
"svcId":#local.qSvcOperation.svc_id#,
|
||||
"contractId":#arguments.contractId#
|
||||
}/>
|
||||
|
||||
<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>
|
||||
<cfset local.qSubparam.default_value=local.qSubparam.value_list/><!--- *** не очень красиво перетирать query, но делаем это довольно часто --->
|
||||
</cfif>
|
||||
</cfif>
|
||||
|
||||
<cfif (len(local.qSubparam.func) OR len(local.qSubparam.expression) )
|
||||
AND len(local.qSubparam.value_list) EQ 0>
|
||||
<cfset local.qSubparam.value_list = []/>
|
||||
</cfif>
|
||||
|
||||
<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)/>
|
||||
<cfif structKeyExists(local.instanceDataParams, paramName)>
|
||||
<cfset var oldValue = structFind(local.instanceDataParams, paramName)/>
|
||||
<cfset def = isStruct(oldValue) ? serializeJson(oldValue) : oldValue/> <!--- потому что передаем строку, а не объект --->
|
||||
</cfif>
|
||||
</cfif> --->
|
||||
|
||||
<cfset structInsert(mapDescriptor, local.qSubparam.svc_operation_cfs_subparam,
|
||||
{
|
||||
"svcOperationCfsSubparamId":"#local.qSubparam.svc_operation_cfs_subparam_id#",
|
||||
@@ -248,27 +218,17 @@
|
||||
}, true
|
||||
)
|
||||
/><!--- *** вообще-то передавать в дескриптор func и default_compute не нужно, это для не забыть --->
|
||||
|
||||
</cfloop>
|
||||
|
||||
<cfset local.qCfsParam.data_descriptor = mapDescriptor/>
|
||||
</cfif><!---/map --->
|
||||
|
||||
</cfloop>
|
||||
|
||||
<!--- <cfdump var=#local.qCfsParam# abort=true/> --->
|
||||
<!--- <cfset queryDeleteColumn(local.qCfsParam, "func")/> --->
|
||||
|
||||
<cfset var out=structNew("linked")/>
|
||||
<cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/>
|
||||
|
||||
<cfset "out.svcOperation" = this.helper.appendRecord(
|
||||
structNew("linked"), "", local.titleMap, local.qSvcOperation, this.helper.snake2camel
|
||||
)/>
|
||||
|
||||
<cfset "out.svcOperation.cfsParams"=[]/>
|
||||
<!--- подставляем значение из стейта, если оно там есть (некорректно, потому что в стейте RFS параметры) --->
|
||||
|
||||
<cfloop query=#local.qCfsParam#>
|
||||
<cfset local.qCfsParam.default_value = computeDefault(local.qCfsParam.default_compute, local.qCfsParam.default_value, qSvcOperation.svc_id, arguments.usrId)/><!--- *** не очень хорошо модифицировать запрос --->
|
||||
<cfif len(local.qCfsParam.default_value) EQ 0>
|
||||
@@ -280,16 +240,11 @@
|
||||
</cfif>
|
||||
</cfif>
|
||||
<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)/>
|
||||
</cfloop>
|
||||
|
||||
<cfset "out.runDurationMs"=getTickCount() - request.startTickCount/>
|
||||
<cfreturn representationOf(out) />
|
||||
|
||||
</cffunction>
|
||||
|
||||
<!--- *** выглядит ужасно, но красивый вариант не придумывается ряд месяцев --->
|
||||
<!--- *** Внимание! нужно учитывать скоуп уникальности --->
|
||||
<cffunction name="computeDefault">
|
||||
@@ -297,7 +252,6 @@
|
||||
<cfargument name="original"/>
|
||||
<cfargument name="service_id" type="numeric"/>
|
||||
<cfargument name="usr_id" type="numeric"/>
|
||||
|
||||
<cfswitch expression=#arguments.defaultCompute#>
|
||||
<cfcase value="display_name">
|
||||
<cfset var dnGenerator = CreateObject("component", "instance_ls")/>
|
||||
@@ -316,7 +270,5 @@
|
||||
<cfreturn #arguments.original#/>
|
||||
</cfdefaultcase>
|
||||
</cfswitch>
|
||||
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
<cfcomponent extends="taffy.core.resource" taffy:uri="/instanceOperations">
|
||||
|
||||
<cfsilent>
|
||||
<cfimport prefix="m" taglib="../lib"/>
|
||||
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/>
|
||||
</cfsilent>
|
||||
|
||||
<!---спецификация полей, пригодных для фильтрации (и сортировки)--->
|
||||
<cfset this.fieldsSpec = {
|
||||
"instance_operation_uid"={prefix="o", type="guid"},
|
||||
@@ -31,27 +29,18 @@
|
||||
"note"={prefix="o", type="string"},
|
||||
"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="Список операций">
|
||||
<cfargument name="pageSize" type="string" hint="type:integer" default="100"/>
|
||||
<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={}/>
|
||||
<cftry>
|
||||
|
||||
|
||||
<!---разбор и проверка параметров запроса--->
|
||||
<cftry>
|
||||
<cfset this.helper.validateField(arguments, "pageSize", "integer")/>
|
||||
<cfset this.helper.validateField(arguments, "page", "integer")/>
|
||||
|
||||
<!---мы мирно игнорируем поля, отсутствующие в спецификации, что позволяет не делать исключения для orderBy и т.п.--->
|
||||
<cfset var filter=this.helper.parseFilterParams(this.fieldsSpec)/>
|
||||
|
||||
<cfcatch type="invalidParamValue">
|
||||
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
|
||||
</cfcatch>
|
||||
@@ -59,8 +48,6 @@
|
||||
<cfreturn representationOf(cfcatch)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
|
||||
<cfquery name="local.qRead" result="local.result">
|
||||
select
|
||||
<m:field_set titleMapOut="local.titleMap" lengthOut="local.fieldCount">
|
||||
@@ -112,7 +99,6 @@
|
||||
offset #arguments.pageSize*(arguments.page-1)#
|
||||
</cfif>
|
||||
</cfquery>
|
||||
|
||||
<cfquery name="local.qCnt">
|
||||
select count(*) as cnt
|
||||
#local.fromClause#
|
||||
@@ -120,60 +106,43 @@
|
||||
s.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/>
|
||||
<m:filter_build filter=#filter#/>
|
||||
</cfquery>
|
||||
|
||||
<cfquery name="local.qTotal">
|
||||
select count(*) as cnt
|
||||
#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
|
||||
s.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/>
|
||||
</cfquery>
|
||||
|
||||
<cfset var out=structNew("linked")/>
|
||||
|
||||
<cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/>
|
||||
<cfset "out.total"=#local.qTotal.cnt#/>
|
||||
<cfset "out.resultSetSize"=#local.qCnt.cnt#/>
|
||||
<cfset "out.pageSize"=#arguments.pageSize*1#/>
|
||||
<cfset "out.page"=#arguments.page*1#/>
|
||||
<cfset "out.orderBy"=#arguments.orderBy#/>
|
||||
|
||||
<cfset var resultCollection=[]/>
|
||||
<cfloop query=#local.qRead#>
|
||||
<cfset var rec=structNew("linked")/>
|
||||
<cfset this.helper.appendRecord(rec, "", local.titleMap, local.qRead, this.helper.snake2camel)/>
|
||||
<cfset arrayAppend(resultCollection, rec)/>
|
||||
</cfloop>
|
||||
|
||||
<cfset "out.size"=#arrayLen(resultCollection)#/>
|
||||
<cfset "out.results"=#resultCollection#/>
|
||||
<cfset "out.runDurationMs"=getTickCount()-request.startTickCount/>
|
||||
<cfreturn representationOf(out)/>
|
||||
|
||||
<cfcatch type="any">
|
||||
<cfreturn representationOf(cfcatch)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
</cffunction>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<cffunction name="post" hint="Создание новой операции. Отдельно загружаются CFS параметры, генерируются RFS параметры. Запускается операция отдельным вызовом. До запуска CFS параметры могут корректироваться (а надо?). Запущенная операция вместе с параметрами навсегда становится Read Only (при желании можем реализовать ее клонирование). Можем реализовать корректировку параметров, но непонятно, зачем. Когда мы конфигурируем инстанс, на самом деле мы задаем CFS параметры операции create. Можно править параметры, а можно пересоздать операцию с новыми параметрами. Предусмотреть удаление (метод DELETE) незапущенной операции?">
|
||||
<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="note" type="string" required=false default="" hint="type:string decsiption: user notes"/>
|
||||
<!--- <cfargument name="resourceRealmId" type="string" default=-1 hint="type:integer decsiption: идентификатор ресурсной платформы"/> ---><!--- *** --->
|
||||
<!--- *** --->
|
||||
<!--- *** полноценная валидация операции предполагает проверку, что операция поддерживается для данного сервиса и текущего состояния инстанса. Можно представить себе зависимость этого от параметров, но хотелось бы избежать такого усложнения --->
|
||||
<!--- Можно отметить, что, например, допустимость операции delete зависит от контекста - сколько времени сервис остановлен --->
|
||||
<cftry>
|
||||
<cfset this.helper.validateField(arguments, "instanceUid", "guid")/>
|
||||
|
||||
<cfquery name="local.qCheckOperation" result="local.result">
|
||||
select count(*) as cnt
|
||||
from svc_operation so
|
||||
@@ -185,7 +154,6 @@
|
||||
<cfif local.qCheckOperation.cnt EQ 0>
|
||||
<cfthrow type="invalidParamValue" message="Operation unsupported for this service/instance" detail="#arguments.operation#"/>
|
||||
</cfif>
|
||||
|
||||
<cfquery name="local.qCheckAccess" result="local.result">
|
||||
select count(*) as cnt
|
||||
from instance e
|
||||
@@ -199,19 +167,12 @@
|
||||
</cfif>
|
||||
<!--- *** Добавить проверку разрешенных переходов, например, create нельзя сделать на развернутом экземпляре
|
||||
*** Вероятно, допустимые переходы нужно либо специфицировать в документации, либо явно опубликовать (инстанс может публиковать список допустимых операций) --->
|
||||
|
||||
<!--- <cfif listFind("create,redeploy",arguments.operation)>
|
||||
<cfset checkResourceRealmId(arguments.resourceRealmId, arguments.instanceUid)/>
|
||||
</cfif> --->
|
||||
|
||||
<cfcatch type="invalidParamValue">
|
||||
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfset local={}/>
|
||||
<cfset local.instanceOperationUid=#createGUID()#/>
|
||||
|
||||
<cftry>
|
||||
<cfquery name="local.qSave">
|
||||
insert into instance_operation
|
||||
@@ -228,30 +189,24 @@
|
||||
,<cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.usrId#" />
|
||||
);
|
||||
</cfquery>
|
||||
|
||||
<cfcatch type="any">
|
||||
<cfreturn representationOf(this.helper.formatException(cfcatch, "Internal Error")).withStatus(500)/><!--- это не нужно показывать в продуктиве --->
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfreturn noData()
|
||||
.withHeaders({location: "./#local.instanceOperationUid#"})
|
||||
.withStatus(201, "Created")
|
||||
/>
|
||||
</cffunction>
|
||||
|
||||
<!--- *** NOT USED --->
|
||||
<cffunction name="checkResourceRealmId" returntype="void" hint="deprecated">
|
||||
<!--- В данном случае мы проверяем соответствие платформы сервису, а не операции, поэтому вопрос, нужен ли для данной операции параметр resourceRealm, надо решать вне этой функции --->
|
||||
<cfargument name="resourceRealmId" type="numeric" required=true/>
|
||||
<cfargument name="instanceUid" type="guid" required=true/>
|
||||
|
||||
<cfset var local={}/>
|
||||
|
||||
<cfif NOT resourceRealmId GT 0>
|
||||
<cfthrow type="InvalidParamValue" message="Resource realm undefined" detail="Не выбрана ресурсная платформа"/><!--- *** для многих операций она и не нужна --->
|
||||
</cfif>
|
||||
|
||||
<cfquery name="local.qContract">
|
||||
select c.contract_id
|
||||
from instance e
|
||||
@@ -260,7 +215,6 @@
|
||||
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)#/>
|
||||
</cfquery>
|
||||
|
||||
<cfquery name="local.qCheckResourceRealmType">
|
||||
select r.resource_realm_type_id
|
||||
from resource_realm r
|
||||
@@ -273,7 +227,6 @@
|
||||
<cfif local.qCheckResourceRealmType.recordCount EQ 0>
|
||||
<cfthrow type="InvalidParamValue" message="Resource realm does not match service" detail="Ресурсная платформа не соответствует сервису"/>
|
||||
</cfif>
|
||||
|
||||
<cfquery name="local.qCheckResourceRealmAccess">
|
||||
select r.resource_realm_id
|
||||
from resource_realm r
|
||||
@@ -283,7 +236,6 @@
|
||||
OR a.contract_id=0)
|
||||
AND a.is_enabled
|
||||
</cfquery>
|
||||
|
||||
<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# нет доступа к выбранной ресурсной платформе"/>
|
||||
</cfif>
|
||||
@@ -297,5 +249,4 @@
|
||||
--->
|
||||
<cfreturn/>
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
@@ -1,24 +1,15 @@
|
||||
<cfcomponent extends="taffy.core.resource" taffy:uri="/instanceOperations/{instanceOperationUid}/validate-cfs">
|
||||
|
||||
<cfsilent>
|
||||
<cfimport prefix="m" taglib="../lib"/>
|
||||
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/><!---*** странно, почему мы его видим?---><!---вынести в апп?--->
|
||||
</cfsilent>
|
||||
|
||||
|
||||
<cffunction name="get" hint="Проверка корректности CFS">
|
||||
<cfargument name="instanceOperationUid" type="string" required=true hint="type:guid"/>
|
||||
|
||||
<!--- <cfset var local={}/> --->
|
||||
|
||||
<!--- *** мы не проверяем доступ к инстансу и существование инстанса 2DO --->
|
||||
|
||||
<cfset var validationMessage = createObject("component","instance_operation").validateCfsParams(arguments.instanceOperationUid)/>
|
||||
<cfif len(validationMessage)>
|
||||
<cfreturn representationOf(this.helper.formatMessage("Inconsistent CFS parameters", #validationMessage#)).withStatus(422)/>
|
||||
</cfif>
|
||||
|
||||
<cfreturn noData().withStatus(204, "OK") />
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
<cfcomponent extends="taffy.core.resource" taffy:uri="/services/{svcId}">
|
||||
|
||||
<cfsilent>
|
||||
<cfimport prefix="m" taglib="../lib"/>
|
||||
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/>
|
||||
</cfsilent>
|
||||
|
||||
|
||||
<cffunction name="get" hint="Сервис"><!--- *** TODO проверка принадлежности тенанту --->
|
||||
<cfargument name="svcId" type="string" required=true hint="type:integer"/>
|
||||
<cftry>
|
||||
@@ -14,10 +11,6 @@
|
||||
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<!--- <cfdump var=#arguments#/> <cfabort/> --->
|
||||
|
||||
|
||||
<cfquery name="local.qSvc" result="local.result">
|
||||
select
|
||||
<m:field_set titleMapOut="local.titleMap" lengthOut="local.fieldCount">
|
||||
@@ -37,7 +30,6 @@
|
||||
from svc s
|
||||
where svc_id=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.svcId#" null=#!isValid('integer',arguments.svcId)#/>
|
||||
</cfquery>
|
||||
|
||||
<cfquery name="local.qSvcOperation" result="local.result">
|
||||
select
|
||||
<m:field_set titleMapOut="local.operationsMap" lengthOut="local.fieldCount">
|
||||
@@ -50,29 +42,19 @@
|
||||
from svc_operation j
|
||||
where j.svc_id=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.svcId#" null=#!isValid('integer',arguments.svcId)#/>
|
||||
</cfquery>
|
||||
|
||||
<cfif local.qSvc.recordCount EQ 0>
|
||||
<cfreturn representationOf(this.helper.formatMessage("Not Found")).withStatus(404)/>
|
||||
</cfif>
|
||||
|
||||
<cfset var out=structNew("linked")/>
|
||||
<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(
|
||||
structNew("linked"), "", local.titleMap, local.qSvc, this.helper.snake2camel
|
||||
)/>
|
||||
|
||||
<cfset "out.svc.operations"=[]/>
|
||||
<cfloop query=#local.qSvcOperation#>
|
||||
<cfset arrayAppend(out.svc.operations, this.helper.appendRecord(structNew("linked"), "", local.operationsMap, local.qSvcOperation, this.helper.snake2camel))/>
|
||||
</cfloop>
|
||||
|
||||
<cfset "out.runDurationMs"=getTickCount() - request.startTickCount/>
|
||||
<cfreturn representationOf(out) />
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
@@ -1,12 +1,9 @@
|
||||
<cfcomponent extends="taffy.core.resource" taffy:uri="/servicesGrouped">
|
||||
|
||||
<!--- Внимание! Дублирование семантики с svc_ls (как правило, вносить изменения параллельно --->
|
||||
|
||||
<cfsilent>
|
||||
<cfimport prefix="m" taglib="../lib"/>
|
||||
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/><!---*** странно, почему мы его видим?---><!---вынести в апп?--->
|
||||
</cfsilent>
|
||||
|
||||
<!---спецификация полей, пригодных для фильтрации (?и сортировки)--->
|
||||
<cfset this.fieldsSpec={
|
||||
dt_created={prefix="s", type="date"},
|
||||
@@ -28,41 +25,26 @@
|
||||
resource_realm_cnt={type="integer"}
|
||||
}
|
||||
/>
|
||||
|
||||
<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={}/>
|
||||
|
||||
<!---parse and validate request parameters--->
|
||||
<cftry>
|
||||
<!--- <cfset this.helper.validateField(arguments, "pageSize", "integer")/>
|
||||
<cfset this.helper.validateField(arguments, "page", "integer")/> --->
|
||||
<!---мы мирно игнорируем поля, отсутствующие в спецификации, что позволяет не делать исключения для orderBy и т.п.--->
|
||||
<cfset var filter=this.helper.parseFilterParams(this.fieldsSpec)/>
|
||||
<!--- <cfset var order=this.helper.parseOrderBy(this.fieldsSpec, arguments.orderBy)/> --->
|
||||
|
||||
<cfcatch type="invalidParamValue"><!--- <cfreturn representationOf("Проверка связи 3")> --->
|
||||
<cfcatch type="invalidParamValue">
|
||||
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
|
||||
</cfcatch>
|
||||
<cfcatch type="any">
|
||||
<cfreturn representationOf(cfcatch)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<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">
|
||||
select
|
||||
<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="Сервис">s.svc</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="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>
|
||||
@@ -98,72 +80,41 @@
|
||||
)
|
||||
where 1=1 <m:filter_build filter=#filter#/>
|
||||
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# --->
|
||||
</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.total"=#local.qTotal.cnt#/> --->
|
||||
<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 svcMap = structCopy(local.titleMap)/><!--- ради аккуратности, дальше local.titleMap все равно не используем --->
|
||||
<cfset var groupMap = withdrawStructKeys(svcMap, "svc_group_id,svc_group")/>
|
||||
|
||||
<cfloop query=#local.qRead# group="svc_group_id"<!--- startRow=#startrow# endRow=#(startrow+maxrows-1)# --->>
|
||||
<cfset var grp = structNew("linked")/>
|
||||
<cfset this.helper.appendRecord(grp, "", groupMap, local.qRead, this.helper.snake2camel)/>
|
||||
|
||||
<cfset "grp.services"=[]/>
|
||||
<cfset var svcRec = structNew("linked")/>
|
||||
<cfloop>
|
||||
<cfset this.helper.appendRecord(svcRec, "", svcMap, local.qRead, this.helper.snake2camel)/>
|
||||
<cfset arrayAppend(grp.services, structCopy(svcRec))/>
|
||||
<!--- <cfdump var=#svcRec#/> --->
|
||||
</cfloop>
|
||||
|
||||
<cfset arrayAppend(resultCollection, structCopy(grp))/>почему-то здесь работает без structCopy
|
||||
</cfloop>
|
||||
|
||||
<cfset "out.size"=#arrayLen(resultCollection)#/>
|
||||
<cfset "out.results"=#resultCollection#/>
|
||||
<cfset "out.runDurationMs"=getTickCount()-request.startTickCount/> <!--- <cfabort/> --->
|
||||
<!---<cfset "out.sql"=#local.result.sql#/>--->
|
||||
<cfset "out.runDurationMs"=getTickCount()-request.startTickCount/>
|
||||
<cfreturn representationOf(out)/>
|
||||
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="withdrawStructKeys" access="private" returntype="struct">
|
||||
<!--- переносим ключи из входной структуры в возвращаемую (во входной удаляем) --->
|
||||
<cfargument name="structFrom" type="struct"/>
|
||||
<cfargument name="keyList" type="string"/>
|
||||
|
||||
<cfset var structOut = {}/>
|
||||
|
||||
<cfloop list=#arguments.keyList# item="key">
|
||||
<cfif structKeyExists(arguments.structFrom, key)>
|
||||
<cfset structInsert(structOut, key, structFind(structFrom, key))/>
|
||||
<cfset structDelete(arguments.structFrom, key)/>
|
||||
</cfif>
|
||||
</cfloop>
|
||||
|
||||
<cfreturn structOut/>
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
+1
-39
@@ -1,10 +1,8 @@
|
||||
<cfcomponent extends="taffy.core.resource" taffy:uri="/services">
|
||||
|
||||
<cfsilent>
|
||||
<cfimport prefix="m" taglib="../lib"/>
|
||||
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/><!---*** странно, почему мы его видим?---><!---вынести в апп?--->
|
||||
</cfsilent>
|
||||
|
||||
<!---спецификация полей, пригодных для фильтрации (?и сортировки)--->
|
||||
<!---здесь для простоты без префикса, потому что мы используем вложенный селект, чтобы сделать композитное поле--->
|
||||
<cfset this.fieldsSpec={
|
||||
@@ -27,7 +25,6 @@
|
||||
"resource_realm_cnt"={prefix="sv", type="integer"}
|
||||
}
|
||||
/>
|
||||
|
||||
<!--- *** пока сортировка, пагинация и состав полей компонуются так, что приходится добавлять поле сортировки в резалтсет --->
|
||||
<cffunction name="get" hint="Список сервисов">
|
||||
<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="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=""/>
|
||||
|
||||
<cfset local={}/>
|
||||
<!--- Фильтрация не униицирована (разница с instance_ls) --->
|
||||
|
||||
<!---parse and validate request parameters--->
|
||||
<cftry>
|
||||
<cfset this.helper.validateField(arguments, "pageSize", "integer")/>
|
||||
<cfset this.helper.validateField(arguments, "page", "integer")/>
|
||||
|
||||
<!---мы мирно игнорируем поля, отсутствующие в спецификации, что позволяет не делать исключения для orderBy и т.п.--->
|
||||
|
||||
<cfset var filter=this.helper.parseFilterParams(this.fieldsSpec)/>
|
||||
<cfset var order=this.helper.parseOrderBy(this.fieldsSpec, arguments.orderBy)/>
|
||||
|
||||
<cfset local.fieldsToOutput=""/>
|
||||
|
||||
<cfloop collection=#this.fieldsSpec# item="fld">
|
||||
<!--- <cfoutput>#this.helper.snake2camel(trim(fld))#</cfoutput> --->
|
||||
<!--- *** в данном случае мы некорректно ограничиваем состав выводимых полей
|
||||
полями, перечисленными в fieldSpec --->
|
||||
<cfif listFindNoCase(arguments.fields, this.helper.snake2camel(trim(fld)))
|
||||
@@ -60,13 +50,10 @@
|
||||
<cfset local.fieldsToOutput=listAppend(local.fieldsToOutput,trim(fld))/>
|
||||
</cfif>
|
||||
</cfloop>
|
||||
|
||||
<cfset local.fieldsToQueryFor = local.fieldsToOutput/>
|
||||
<cfset local.fieldsShortList=""/>
|
||||
|
||||
<!--- теперь добавим в перечень полей, которые нужно оставить, поля для фильтрации и сортировки --->
|
||||
<cfloop array=#filter# index="fltr">
|
||||
<!--- <cfset var fltr = structFind(filter,item)/> --->
|
||||
<cfif listLen(fltr.field,".") EQ 2>
|
||||
<cfset var fld = listGetAt(fltr.field,2,".")/>
|
||||
<cfelseif listLen(fltr.field,".") EQ 1>
|
||||
@@ -81,8 +68,6 @@
|
||||
<cfset local.fieldsShortList=listAppend(local.fieldsShortList,fld)/>
|
||||
</cfif>
|
||||
</cfloop>
|
||||
|
||||
|
||||
<!--- *** Не нужно ли сохранять префикс? (на случай одноименных полей) --->
|
||||
<cfloop collection=#order# item="item">
|
||||
<cfset var ord = structFind(order,item)/>
|
||||
@@ -101,21 +86,16 @@
|
||||
<cfset local.fieldsShortList=listAppend(local.fieldsShortList,fld)/>
|
||||
</cfif>
|
||||
</cfloop>
|
||||
|
||||
<cfcatch type="invalidParamValue"><!--- <cfreturn representationOf("Проверка связи 3")> --->
|
||||
<cfcatch type="invalidParamValue">
|
||||
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
|
||||
</cfcatch>
|
||||
|
||||
|
||||
<cfcatch type="any">
|
||||
<cfreturn representationOf(cfcatch)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfset var out=structNew("linked")/>
|
||||
<cfset var maxrows=arguments.pageSize*arguments.page/>
|
||||
<cfset var startrow=arguments.pageSize*(arguments.page-1)+1/>
|
||||
|
||||
<m:field_set
|
||||
titleMapOut="local.titleMap"
|
||||
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>(coalesce(s.svc,'') ||' '|| coalesce(s.svc_short,'') ||' '|| coalesce(s.synonyms,'')) as svc_extended_name</m:field>
|
||||
</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">
|
||||
select <cfif listLen(local.definedRecordFields)>#local.definedRecordFields#<cfelse>*</cfif> from
|
||||
@@ -184,8 +156,6 @@
|
||||
where 1=1 <m:filter_build filter=#filter#/>
|
||||
order by <m:order_build sortCollection=#this.helper.parseNumericOrder(local.titleMap, arguments.orderBy)# fieldCount=1/>
|
||||
</cfquery>
|
||||
|
||||
|
||||
<cftry>
|
||||
<cfquery name="local.qTotal">
|
||||
select count(*) as cnt
|
||||
@@ -196,29 +166,21 @@
|
||||
<cfreturn representationOf(cfcatch)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<!--- <cfreturn representationOf("Проверка связи 7")/> --->
|
||||
|
||||
<cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/>
|
||||
<cfset "out.total"=#local.qTotal.cnt#/>
|
||||
<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=[]/>
|
||||
<cfloop query=#local.qRead# startRow=#startrow# endRow=#(startrow+maxrows-1)#>
|
||||
<cfset var rec={}/>
|
||||
<cfset this.helper.appendRecord(rec, "", local.titleMap, local.qRead, this.helper.snake2camel)/>
|
||||
<cfset arrayAppend(resultCollection, rec)/>
|
||||
</cfloop>
|
||||
|
||||
<cfset "out.size"=#arrayLen(resultCollection)#/>
|
||||
<cfset "out.results"=#resultCollection#/>
|
||||
<cfset "out.runDurationMs"=getTickCount()-request.startTickCount/>
|
||||
<!---<cfset "out.sql"=#local.result.sql#/>--->
|
||||
<cfreturn representationOf(out)/>
|
||||
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
@@ -1,11 +1,8 @@
|
||||
<cfcomponent extends="taffy.core.resource" taffy:uri="/serviceOperation/{svcOperationId}">
|
||||
|
||||
<cfsilent>
|
||||
<cfimport prefix="m" taglib="../lib"/>
|
||||
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/>
|
||||
</cfsilent>
|
||||
|
||||
|
||||
<cffunction name="get" hint="Операция сервиса"><!--- *** TODO проверка принадлежности тенанту --->
|
||||
<cfargument name="svcOperationId" type="string" required=true hint="type:integer"/>
|
||||
<cftry>
|
||||
@@ -14,7 +11,6 @@
|
||||
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfquery name="local.qSvcOperation" result="local.result">
|
||||
select
|
||||
<m:field_set titleMapOut="local.titleMap" lengthOut="local.fieldCount">
|
||||
@@ -27,12 +23,10 @@
|
||||
from svc_operation o
|
||||
where o.svc_operation_id=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.svcOperationId#" null=#!isValid('integer',arguments.svcOperationId)#/>
|
||||
</cfquery>
|
||||
|
||||
<cfquery name="local.qCfsParam" result="local.result">
|
||||
select
|
||||
<m:field_set titleMapOut="local.cfsParamMap" lengthOut="local.fieldCount">
|
||||
<m:field title="ID" cfSqlType="CF_SQL_INTEGER">p.svc_operation_cfs_param_id</m:field>
|
||||
<!--- <m:field cfSqlType="CF_SQL_INTEGER">p.svc_operation_id</m:field> --->
|
||||
<m:field>p.svc_operation_cfs_param</m:field>
|
||||
<m:field>p.label</m:field>
|
||||
<m:field>p.data_type</m:field>
|
||||
@@ -73,18 +67,14 @@
|
||||
AND p.is_actual
|
||||
order by p.sort, p.svc_operation_cfs_param_id
|
||||
</cfquery>
|
||||
|
||||
<cfif local.qSvcOperation.recordCount EQ 0>
|
||||
<cfreturn representationOf(this.helper.formatMessage("Not Found")).withStatus(404)/>
|
||||
</cfif>
|
||||
|
||||
<cfset var out=structNew("linked")/>
|
||||
<cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/>
|
||||
|
||||
<cfset "out.svcOperation" = this.helper.appendRecord(
|
||||
structNew("linked"), "", local.titleMap, local.qSvcOperation, this.helper.snake2camel
|
||||
)/>
|
||||
|
||||
<cfset "out.svcOperation.cfsParams"=[]/>
|
||||
<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))
|
||||
@@ -93,16 +83,13 @@
|
||||
</cfif>
|
||||
<cfset arrayAppend(out.svcOperation.cfsParams, this.helper.appendRecord(structNew("linked"), "", local.cfsParamMap, local.qCfsParam, this.helper.snake2camel))/>
|
||||
</cfloop>
|
||||
|
||||
<cfset "out.runDurationMs"=getTickCount() - request.startTickCount/>
|
||||
<cfreturn representationOf(out) />
|
||||
</cffunction>
|
||||
|
||||
<!--- *** выглядит ужасно, но красивый вариант не придумывается ряд месяцев --->
|
||||
<cffunction name="computeDefault">
|
||||
<cfargument name="defaultCompute"/>
|
||||
<cfargument name="original"/>
|
||||
|
||||
<cfswitch expression=#arguments.defaultCompute#>
|
||||
<cfcase value="display_name">
|
||||
</cfcase>
|
||||
@@ -110,7 +97,5 @@
|
||||
<cfreturn #arguments.original#/>
|
||||
</cfdefaultcase>
|
||||
</cfswitch>
|
||||
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
@@ -1,44 +1,21 @@
|
||||
<cfcomponent extends="taffy.core.resource" taffy:uri="/user">
|
||||
|
||||
<cfsilent>
|
||||
<cfimport prefix="m" taglib="../lib"/>
|
||||
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/><!---*** странно, почему мы его видим?---><!---вынести в апп?--->
|
||||
</cfsilent>
|
||||
|
||||
<!--- *** Внимание! Особая обработка в Application.cfc по имени user.cfc --->
|
||||
|
||||
|
||||
<cffunction name="get" hint="Контрольная информация по текущему пользователю для проверки контекста. Предполагается использовать только для интеграционной отладки. Исключения перехватываются, всегда возвращается код 200, структура ответа при этом не предназначена для разбора">
|
||||
<cftry>
|
||||
|
||||
<cfset var local={}/><!--- *** а точно нужно var? --->
|
||||
<cfset var out=structNew("linked")/>
|
||||
|
||||
<cfset "out.usrId"=#ARGUMENTS.usrId#/>
|
||||
<!--- <cfset "out.iamServiceUrl"=request.locateIamService()/> --->
|
||||
|
||||
<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">
|
||||
select
|
||||
<m:field_set titleMapOut="local.specTitleMap" lengthOut="local.fieldCount">
|
||||
<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.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>
|
||||
from specification s
|
||||
join contract c on (s.contract_id=c.contract_id)
|
||||
@@ -47,44 +24,26 @@
|
||||
order by specification_id desc
|
||||
limit 1;
|
||||
</cfquery>
|
||||
|
||||
|
||||
<cfquery name="local.qRead" result="local.result">
|
||||
select
|
||||
<m:field_set titleMapOut="local.titleMap" lengthOut="local.fieldCount">
|
||||
<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><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>
|
||||
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 "out.queryDurationMs"=getTickCount() - request.startTickCount- out.serviceLocationDurationMs/>
|
||||
|
||||
<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.arguments" = #arguments#/>
|
||||
<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.sql"=#local.result.sql#/>--->
|
||||
<cfreturn representationOf(out)/>
|
||||
|
||||
<cfcatch type="any">
|
||||
<cfreturn representationOf(cfcatch)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
</cffunction>
|
||||
|
||||
<!--- <cffunction name="get" hint="проверка">
|
||||
<cfreturn representationOf("Проверка связи")/>
|
||||
</cffunction> --->
|
||||
|
||||
</cfcomponent>
|
||||
@@ -1,41 +1,21 @@
|
||||
<cfcomponent extends="taffy.core.resource" taffy:uri="/instances/{instanceUid}/vault/{secretName}" hint="getting secrets from the vault">
|
||||
|
||||
<cfsilent>
|
||||
<cfimport prefix="m" taglib="../lib"/>
|
||||
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/>
|
||||
</cfsilent>
|
||||
|
||||
<cffunction name="get" hint="Получить секрет">
|
||||
<cfargument name="instanceUid" type="string" required=true hint="type:UUID"/>
|
||||
<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 --->
|
||||
|
||||
<cftry>
|
||||
<cfset this.helper.validateField(arguments, "instanceUid", "guid")/>
|
||||
<cfcatch type="invalidParamValue">
|
||||
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfset var local={}/>
|
||||
<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 - стало быть, доступен пользователю --->
|
||||
|
||||
<!--- тут необходимо проконтролировать, что мы смотрим не чужие данные --->
|
||||
<!--- в других местах мы молча возврашаем пустой резалтсет на запрос чужих данных --->
|
||||
<!--- варианты: 403, 404, пустой набор данных --->
|
||||
@@ -59,16 +39,12 @@
|
||||
order by st.version desc
|
||||
limit 1
|
||||
</cfquery>
|
||||
|
||||
<cfif local.qCurrentState.recordCount EQ 0>
|
||||
<cfreturn representationOf("Cannot find instance current state or no permission to view").withStatus(404)/>
|
||||
</cfif>
|
||||
|
||||
<cfif len(local.qCurrentState.instance_data) EQ 0>
|
||||
<cfreturn representationOf("Instance current state is empty").withStatus(404)/>
|
||||
</cfif>
|
||||
|
||||
<!--- <cfdump var=#local.qCurrentState#/><cfabort/> --->
|
||||
<cfset var vaultUrl=""/>
|
||||
<cftry>
|
||||
<cfset var instanceData=#deserializeJson(local.qCurrentState.instance_data)#/>
|
||||
@@ -82,7 +58,6 @@
|
||||
<cfelse>
|
||||
<cfreturn representationOf("Instance data do not contain vault url").withStatus(422)/>
|
||||
</cfif>
|
||||
|
||||
<cfhttp method="post"
|
||||
url="#request.vault_login_url#"
|
||||
timeout="3"
|
||||
@@ -92,14 +67,11 @@
|
||||
<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#"}'/>
|
||||
</cfhttp>
|
||||
|
||||
<cfif local.res.status_code NEQ 200>
|
||||
<cfreturn representationOf(local.res).withStatus(422)/>
|
||||
</cfif>
|
||||
|
||||
<cfset resData=#deserializeJson(local.res.filecontent)#/>
|
||||
<cfset client_token=#resData.auth.client_token#/>
|
||||
|
||||
<cftry>
|
||||
<cfhttp method="get"
|
||||
url="#vaultUrl#"
|
||||
@@ -112,7 +84,6 @@
|
||||
<cfif local.cred.status_code NEQ 200>
|
||||
<cfreturn representationOf(local.cred).withStatus(422)/>
|
||||
</cfif>
|
||||
<!--- <cfdump var=#cred#/><cfabort/> --->
|
||||
<!--- *** костыль для перехода от формата v001 к v002 --->
|
||||
<cfif structKeyExists(instanceData,"vault")
|
||||
AND structKeyExists(instanceData.vault,"fields")
|
||||
@@ -125,18 +96,14 @@
|
||||
<cfelse>
|
||||
<cfreturn representationOf("Secret not found or no permission to view").withStatus(404)/>
|
||||
</cfif>
|
||||
|
||||
|
||||
<cfcatch type="ANY">
|
||||
<cfreturn representationOf(cfcatch).withStatus(500)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfcatch type="ANY">
|
||||
<cfreturn representationOf(cfcatch).withStatus(500)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<!--- логируем успешную попытку доступа. (если логировать сначала - неизвестен результат. *** Можно в catch логировать неуспешный --->
|
||||
<cfset logVaultAccess(
|
||||
"#request.iam_service_url#/events",
|
||||
@@ -150,7 +117,6 @@
|
||||
arguments.usrId,
|
||||
arguments.contragentId,
|
||||
arguments.isImpersonated)/>
|
||||
|
||||
<cfset var out = structNew("linked")/>
|
||||
<cfset "out.name" = #arguments.secretName#/>
|
||||
<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/>
|
||||
<cfreturn representationOf(out) />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="logVaultAccess" returntype="void">
|
||||
<cfargument name="loggerUrl" type="string" required=true hint=""/>
|
||||
<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="contragentId" type="string" required=true hint="type:string WZ"/>
|
||||
<cfargument name="isImpersonated" type="string" required=true hint="type:boolean"/>
|
||||
|
||||
<cftry>
|
||||
<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 = {
|
||||
"event_type": "credentials_access",
|
||||
"ip_address": "#CGI.REMOTE_ADDR#",
|
||||
@@ -208,7 +158,6 @@
|
||||
"isImpersonated": "#arguments.isImpersonated#"
|
||||
}
|
||||
}/>
|
||||
|
||||
<!---
|
||||
https://cfguide.io/logging-observability
|
||||
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 --->
|
||||
<cfcatch type="ANY"></cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfhttp method="post"
|
||||
url="#arguments.loggerUrl#"
|
||||
timeout="3"
|
||||
@@ -229,18 +177,9 @@
|
||||
<cfhttpparam type="HEADER" name="Content-Type" value="application/json"/>
|
||||
<cfhttpparam type="BODY" value="#serializeJson(msg)#"/>
|
||||
</cfhttp>
|
||||
|
||||
<!---
|
||||
arguments:<cfdump var=#arguments#/>
|
||||
msg:<cfdump var=#msg#/>
|
||||
local.res:<cfdump var=#local.res#/>
|
||||
<cfabort/>
|
||||
--->
|
||||
<cfcatch type="any">
|
||||
<cfrethrow/><!--- на этапе отладки лучше тут падать --->
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
Reference in New Issue
Block a user