import sys
import json
import re
def extract_resource_and_operation(name):
"""Извлекает resource и operation из имени нода"""
name_lower = name.lower().strip()
# Определение resource по ключевым словам
resources = {
'fieldvalue': ['field value'],
'field': ['field'],
'file': ['file'],
'listentry': ['list entry'],
'list': ['list'],
'note': ['note'],
'opportunity': ['opportunity'],
'organization': ['organization'],
'person': ['person'],
'contact': ['contact'] # fallback
}
resource = 'contact' # default
for res, keywords in resources.items():
for keyword in keywords:
if keyword in name_lower:
resource = res
break
if resource != 'contact':
break
# Определение operation
if 'deleted' in name_lower or 'delete' in name_lower:
operation = 'delete'
elif 'updated' in name_lower or 'update' in name_lower:
operation = 'update'
elif 'created' in name_lower or 'create' in name_lower:
operation = 'create'
elif 'get many' in name_lower or 'get all' in name_lower:
operation = 'getAll'
elif 'get' in name_lower:
operation = 'get'
else:
operation = None
# Для trigger нодов (начинающихся с "On")
if name_lower.startswith('on '):
# Для trigger нодов operation часто не нужен, кроме delete/update
if 'deleted' in name_lower:
operation = 'delete'
elif 'updated' in name_lower:
operation = 'update'
else:
operation = None
return resource, operation
def generate_parameters(name, resource, operation, node_type):
"""Генерирует параметры для нода"""
parameters = {}
# Определяем является ли нод триггером
is_trigger = 'trigger' in node_type.lower()
if is_trigger:
# Affinity Trigger ноды
if resource == 'fieldvalue':
if operation == 'delete':
parameters['operation'] = 'delete'
elif operation == 'update':
parameters['operation'] = 'update'
parameters['updateFields'] = {}
# created не требует параметров
elif resource == 'field':
if operation == 'delete':
parameters['operation'] = 'delete'
elif operation == 'update':
parameters['operation'] = 'update'
parameters['updateFields'] = {}
# created не требует параметров
elif resource == 'file':
if operation == 'delete':
parameters['operation'] = 'delete'
elif operation == 'update':
parameters['operation'] = 'update'
parameters['updateFields'] = {}
# created не требует параметров
elif resource == 'listentry':
parameters['resource'] = 'list'
# Для list entry created/deleted/updated не требуют доп параметров кроме resource
elif resource == 'list':
parameters['resource'] = 'list'
# Для list created/deleted/updated не требуют доп параметров кроме resource
elif resource == 'note':
if operation == 'delete':
parameters['operation'] = 'delete'
elif operation == 'update':
parameters['operation'] = 'update'
parameters['updateFields'] = {}
# created не требует параметров
elif resource == 'opportunity':
if operation == 'delete':
parameters['operation'] = 'delete'
elif operation == 'update':
parameters['operation'] = 'update'
parameters['updateFields'] = {}
# created не требует параметров
elif resource == 'organization':
if operation == 'delete':
parameters['operation'] = 'delete'
elif operation == 'update':
parameters['operation'] = 'update'
parameters['updateFields'] = {}
# created не требует параметров
elif resource == 'person':
if operation == 'delete':
parameters['operation'] = 'delete'
elif operation == 'update':
parameters['operation'] = 'update'
parameters['updateFields'] = {}
# created не требует параметров
else:
# Обычные Affinity ноды (не триггеры)
if resource == 'list':
parameters['resource'] = 'list'
if operation == 'getAll':
parameters['operation'] = 'getAll'
elif operation == 'delete':
# Delete a list entry
pass # resource: list достаточно
elif operation == 'get':
# Get a list entry
pass # resource: list достаточно
# Create и Get не требуют operation
elif resource == 'organization':
if operation is None:
# Create an organization
pass # без параметров
elif operation == 'delete':
parameters['operation'] = 'delete'
elif operation == 'get':
parameters['operation'] = 'get'
elif operation == 'getAll':
parameters['operation'] = 'getAll'
parameters['additionalFields'] = {}
elif operation == 'update':
parameters['operation'] = 'update'
parameters['updateFields'] = {}
elif resource == 'person':
if operation is None:
# Create a person
pass # без параметров
elif operation == 'delete':
parameters['operation'] = 'delete'
elif operation == 'get':
parameters['operation'] = 'get'
elif operation == 'getAll':
parameters['operation'] = 'getAll'
parameters['additionalFields'] = {}
elif operation == 'update':
parameters['operation'] = 'update'
parameters['updateFields'] = {}
elif resource == 'listentry':
parameters['resource'] = 'list'
# Create/Delete/Get list entry - resource: list достаточно
return parameters
def calculate_position(index):
"""Рассчитывает позицию с отступом -64 по X и -128 по Y для первой строки"""
row = index // 15
col = index % 15
# Начинаем с (-64, -128) и добавляем отступы
x_position = -64 + col * 192
y_position = -128 + row * 192
return [x_position, y_position]
def process_workflow(input_file, output_file):
# Чтение входного файла
try:
with open(input_file, 'r', encoding='utf-8') as f:
data = json.load(f)
except FileNotFoundError:
print(f"❌ Файл {input_file} не найден")
return
except Exception as e:
print(f"❌ Ошибка чтения файла {input_file}: {e}")
return
# Обработка каждого нода
for index, node in enumerate(data.get('nodes', [])):
# Извлечение resource и operation из имени
resource, operation = extract_resource_and_operation(node['name'])
# Генерация параметров
parameters = generate_parameters(node['name'], resource, operation, node['type'])
node['parameters'] = parameters
# Расчет позиции
node['position'] = calculate_position(index)
# Добавление дополнительных полей
data['pinData'] = {}
data['meta'] = {
"templateCredsSetupCompleted": True,
"instanceId": "b20ef463441a8a2250f82688aace439e1bfed5cdc4224606159f0fb852849ec9"
}
# Сохранение результата
try:
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
print(f"✅ Успешно обработано {len(data.get('nodes', []))} узлов. Результат записан в {output_file}")
except Exception as e:
print(f"❌ Ошибка записи файла {output_file}: {e}")
def main():
if len(sys.argv) != 3:
print("Использование: python process_workflow.py <input_file.json> <output_file.json>")
sys.exit(1)
input_filename = sys.argv[1]
output_filename = sys.argv[2]
process_workflow(input_filename, output_filename)
if __name__ == "__main__":
main()