mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-01 08:24:53 +01:00
- added show_message to BaseAction
- added priorities to register - test action show only to Pypeclub user - custom attributes can be created from json file (instructions inside)
This commit is contained in:
parent
46a1f54b82
commit
a4ec8b54f5
5 changed files with 627 additions and 254 deletions
|
|
@ -1,246 +0,0 @@
|
|||
# :coding: utf-8
|
||||
# :copyright: Copyright (c) 2017 ftrack
|
||||
import sys
|
||||
import argparse
|
||||
import logging
|
||||
import os
|
||||
import json
|
||||
import ftrack_api
|
||||
from ftrack_action_handler import BaseAction
|
||||
|
||||
from avalon import io, inventory, lib
|
||||
from avalon.vendor import toml
|
||||
|
||||
|
||||
class AvalonIdAttribute(BaseAction):
|
||||
'''Edit meta data action.'''
|
||||
|
||||
#: Action identifier.
|
||||
identifier = 'avalon.id.attribute'
|
||||
#: Action label.
|
||||
label = 'Create Avalon Attribute'
|
||||
#: Action description.
|
||||
description = 'Creates Avalon/Mongo ID for double check'
|
||||
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
'''
|
||||
Validation
|
||||
- action is only for Administrators
|
||||
'''
|
||||
success = False
|
||||
userId = event['source']['user']['id']
|
||||
user = session.query('User where id is ' + userId).one()
|
||||
for role in user['user_security_roles']:
|
||||
if role['security_role']['name'] == 'Administrator':
|
||||
success = True
|
||||
|
||||
return success
|
||||
|
||||
|
||||
def launch(self, session, entities, event):
|
||||
# JOB SETTINGS
|
||||
|
||||
userId = event['source']['user']['id']
|
||||
user = session.query('User where id is ' + userId).one()
|
||||
|
||||
job = session.create('Job', {
|
||||
'user': user,
|
||||
'status': 'running',
|
||||
'data': json.dumps({
|
||||
'description': 'Custom Attribute creation.'
|
||||
})
|
||||
})
|
||||
session.commit()
|
||||
try:
|
||||
# Checkbox for event sync
|
||||
cbxSyncName = 'avalon_auto_sync'
|
||||
cbxSyncLabel = 'Avalon auto-sync'
|
||||
cbxSyncExist = False
|
||||
|
||||
# Attribute Name and Label
|
||||
custAttrName = 'avalon_mongo_id'
|
||||
custAttrLabel = 'Avalon/Mongo Id'
|
||||
|
||||
attrs_update = set()
|
||||
# Types that don't need object_type_id
|
||||
base = {'show'}
|
||||
|
||||
# Don't create custom attribute on these entity types:
|
||||
exceptions = ['task', 'milestone']
|
||||
exceptions.extend(base)
|
||||
# Get all possible object types
|
||||
all_obj_types = session.query('ObjectType').all()
|
||||
count_types = len(all_obj_types)
|
||||
# Filter object types by exceptions
|
||||
for index in range(count_types):
|
||||
i = count_types - 1 - index
|
||||
name = all_obj_types[i]['name'].lower()
|
||||
|
||||
if " " in name:
|
||||
name = name.replace(" ","")
|
||||
|
||||
if name in exceptions:
|
||||
all_obj_types.pop(i)
|
||||
|
||||
# Get IDs of filtered object types
|
||||
all_obj_types_id = set()
|
||||
|
||||
for obj in all_obj_types:
|
||||
all_obj_types_id.add(obj['id'])
|
||||
|
||||
# Get all custom attributes
|
||||
current_cust_attr = session.query('CustomAttributeConfiguration').all()
|
||||
# Filter already existing AvalonMongoID attr.
|
||||
for attr in current_cust_attr:
|
||||
if attr['key'] == cbxSyncName:
|
||||
cbxSyncExist = True
|
||||
cbxAttribute = attr
|
||||
if attr['key'] == custAttrName:
|
||||
if attr['entity_type'] in base:
|
||||
base.remove(attr['entity_type'])
|
||||
attrs_update.add(attr)
|
||||
if attr['object_type_id'] in all_obj_types_id:
|
||||
all_obj_types_id.remove(attr['object_type_id'])
|
||||
attrs_update.add(attr)
|
||||
|
||||
# Set session back to begin("session.query" raises error on commit)
|
||||
session.rollback()
|
||||
# Set security roles for attribute
|
||||
role_api = session.query('SecurityRole where name is "API"').one()
|
||||
role_admin = session.query('SecurityRole where name is "Administrator"').one()
|
||||
roles = [role_api,role_admin]
|
||||
|
||||
# Set Text type of Attribute
|
||||
custom_attribute_type = session.query(
|
||||
'CustomAttributeType where name is "text"'
|
||||
).one()
|
||||
# Get/Set 'avalon' group
|
||||
groups = session.query('CustomAttributeGroup where name is "avalon"').all()
|
||||
if len(groups) > 1:
|
||||
msg = "There are more Custom attribute groups with name 'avalon'"
|
||||
self.log.warning(msg)
|
||||
return { 'success': False, 'message':msg }
|
||||
|
||||
elif len(groups) < 1:
|
||||
group = session.create('CustomAttributeGroup', {
|
||||
'name': 'avalon',
|
||||
})
|
||||
session.commit()
|
||||
else:
|
||||
group = groups[0]
|
||||
|
||||
# Checkbox for auto-sync event / Create or Update(roles + group)
|
||||
if cbxSyncExist is False:
|
||||
cbxType = session.query('CustomAttributeType where name is "boolean"').first()
|
||||
session.create('CustomAttributeConfiguration', {
|
||||
'entity_type': 'show',
|
||||
'type': cbxType,
|
||||
'label': cbxSyncLabel,
|
||||
'key': cbxSyncName,
|
||||
'default': False,
|
||||
'write_security_roles': roles,
|
||||
'read_security_roles': roles,
|
||||
'group':group,
|
||||
})
|
||||
else:
|
||||
cbxAttribute['write_security_roles'] = roles
|
||||
cbxAttribute['read_security_roles'] = roles
|
||||
cbxAttribute['group'] = group
|
||||
|
||||
for entity_type in base:
|
||||
# Create a custom attribute configuration.
|
||||
session.create('CustomAttributeConfiguration', {
|
||||
'entity_type': entity_type,
|
||||
'type': custom_attribute_type,
|
||||
'label': custAttrLabel,
|
||||
'key': custAttrName,
|
||||
'default': '',
|
||||
'write_security_roles': roles,
|
||||
'read_security_roles': roles,
|
||||
'group':group,
|
||||
'config': json.dumps({'markdown': False})
|
||||
})
|
||||
|
||||
for type in all_obj_types_id:
|
||||
# Create a custom attribute configuration.
|
||||
session.create('CustomAttributeConfiguration', {
|
||||
'entity_type': 'task',
|
||||
'object_type_id': type,
|
||||
'type': custom_attribute_type,
|
||||
'label': custAttrLabel,
|
||||
'key': custAttrName,
|
||||
'default': '',
|
||||
'write_security_roles': roles,
|
||||
'read_security_roles': roles,
|
||||
'group':group,
|
||||
'config': json.dumps({'markdown': False})
|
||||
})
|
||||
|
||||
for attr in attrs_update:
|
||||
attr['write_security_roles'] = roles
|
||||
attr['read_security_roles'] = roles
|
||||
attr['group'] = group
|
||||
|
||||
job['status'] = 'done'
|
||||
session.commit()
|
||||
|
||||
except Exception as e:
|
||||
session.rollback()
|
||||
job['status'] = 'failed'
|
||||
session.commit()
|
||||
self.log.error("Creating custom attributes failed ({})".format(e))
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def register(session, **kw):
|
||||
'''Register plugin. Called when used as an plugin.'''
|
||||
|
||||
# Validate that session is an instance of ftrack_api.Session. If not,
|
||||
# assume that register is being called from an old or incompatible API and
|
||||
# return without doing anything.
|
||||
if not isinstance(session, ftrack_api.session.Session):
|
||||
return
|
||||
|
||||
action_handler = AvalonIdAttribute(session)
|
||||
action_handler.register()
|
||||
|
||||
|
||||
def main(arguments=None):
|
||||
'''Set up logging and register action.'''
|
||||
if arguments is None:
|
||||
arguments = []
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
# Allow setting of logging level from arguments.
|
||||
loggingLevels = {}
|
||||
for level in (
|
||||
logging.NOTSET, logging.DEBUG, logging.INFO, logging.WARNING,
|
||||
logging.ERROR, logging.CRITICAL
|
||||
):
|
||||
loggingLevels[logging.getLevelName(level).lower()] = level
|
||||
|
||||
parser.add_argument(
|
||||
'-v', '--verbosity',
|
||||
help='Set the logging output verbosity.',
|
||||
choices=loggingLevels.keys(),
|
||||
default='info'
|
||||
)
|
||||
namespace = parser.parse_args(arguments)
|
||||
|
||||
# Set up basic logging
|
||||
logging.basicConfig(level=loggingLevels[namespace.verbosity])
|
||||
|
||||
session = ftrack_api.Session()
|
||||
register(session)
|
||||
|
||||
# Wait for events
|
||||
logging.info(
|
||||
'Registered actions and listening for events. Use Ctrl-C to abort.'
|
||||
)
|
||||
session.event_hub.wait()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
raise SystemExit(main(sys.argv[1:]))
|
||||
576
pype/ftrack/actions/action_create_cust_attrs.py
Normal file
576
pype/ftrack/actions/action_create_cust_attrs.py
Normal file
|
|
@ -0,0 +1,576 @@
|
|||
# :coding: utf-8
|
||||
# :copyright: Copyright (c) 2017 ftrack
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
import json
|
||||
import ftrack_api
|
||||
from ftrack_action_handler import BaseAction
|
||||
|
||||
"""
|
||||
This action creates/updates custom attributes.
|
||||
- first part take care about avalon_mongo_id attribute
|
||||
- second part is based on json file in templates:
|
||||
~/PYPE-TEMPLATES/presets/ftrack/ftrack_custom_attributes.json
|
||||
- you can add Custom attributes based on these conditions
|
||||
|
||||
*** Required ***************************************************************
|
||||
|
||||
label (string)
|
||||
- label that will show in ftrack
|
||||
|
||||
key (string)
|
||||
- must contain only chars [a-z0-9_]
|
||||
|
||||
type (string)
|
||||
- type of custom attribute
|
||||
- possibilities: text, boolean, date, enumerator, dynamic enumerator, number
|
||||
|
||||
*** Required with conditions ***********************************************
|
||||
|
||||
entity_type (string)
|
||||
- if 'is_hierarchical' is set to False
|
||||
- type of entity
|
||||
- possibilities: task, show, assetversion, user, list, asset
|
||||
|
||||
config (dictionary)
|
||||
- for each entity type different requirements and possibilities:
|
||||
- enumerator: multiSelect = True/False(default: False)
|
||||
data = {key_1:value_1,key_2:value_2,..,key_n:value_n}
|
||||
- 'data' is Required value with enumerator
|
||||
- 'key' must contain only chars [a-z0-9_]
|
||||
|
||||
- number: isdecimal = True/False(default: False)
|
||||
|
||||
- text: markdown = True/False(default: False)
|
||||
|
||||
object_type (string)
|
||||
- IF ENTITY_TYPE is set to 'task'
|
||||
- default possibilities: Folder, Shot, Sequence, Task, Library,
|
||||
Milestone, Episode, Asset Build,...
|
||||
|
||||
*** Optional ***************************************************************
|
||||
|
||||
write_security_roles/read_security_roles (array of strings)
|
||||
- default: ["ALL"]
|
||||
- strings should be role names (e.g.: ["API", "Administrator"])
|
||||
- if set to ["ALL"] - all roles will be availabled
|
||||
- if first is 'except' - roles will be set to all except roles in array
|
||||
- Warning: Be carefull with except - roles can be different by company
|
||||
- example:
|
||||
write_security_roles = ["except", "User"]
|
||||
read_security_roles = ["ALL"]
|
||||
- User is unable to write but can read
|
||||
|
||||
group (string)
|
||||
- default: None
|
||||
- name of group
|
||||
|
||||
default
|
||||
- default: None
|
||||
- sets default value for custom attribute:
|
||||
- text -> string
|
||||
- number -> integer
|
||||
- enumerator -> array with string of key/s
|
||||
- boolean -> bool true/false
|
||||
- date -> string in format: 'YYYY.MM.DD' or 'YYYY.MM.DD HH:mm:ss'
|
||||
- example: "2018.12.24" / "2018.1.1 6:0:0"
|
||||
- dynamic enumerator -> DON'T HAVE DEFAULT VALUE!!!
|
||||
|
||||
is_hierarchical (bool)
|
||||
- default: False
|
||||
- will set hierachical attribute
|
||||
- False by default
|
||||
|
||||
EXAMPLE:
|
||||
{
|
||||
"avalon_auto_sync": {
|
||||
"label": "Avalon auto-sync",
|
||||
"key": "avalon_auto_sync",
|
||||
"type": "boolean",
|
||||
"entity_type": "show",
|
||||
"group": "avalon",
|
||||
"default": false,
|
||||
"write_security_role": ["API","Administrator"],
|
||||
"read_security_role": ["API","Administrator"]
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
class CustAttrException(Exception):
|
||||
pass
|
||||
|
||||
class CustomAttributes(BaseAction):
|
||||
'''Edit meta data action.'''
|
||||
|
||||
#: Action identifier.
|
||||
identifier = 'create.update.attributes'
|
||||
#: Action label.
|
||||
label = 'Create/Update Avalon Attributes'
|
||||
#: Action description.
|
||||
description = 'Creates Avalon/Mongo ID for double check'
|
||||
|
||||
def __init__(self, session):
|
||||
super().__init__(session)
|
||||
|
||||
templates = os.environ['PYPE_STUDIO_TEMPLATES']
|
||||
path_items = [templates,'presets','ftrack', 'ftrack_custom_attributes.json']
|
||||
self.filepath = os.path.sep.join(path_items)
|
||||
# self.all_current_attributes = session.query('CustomAttributeConfiguration').all()
|
||||
self.types = {}
|
||||
self.object_type_ids = {}
|
||||
self.groups = {}
|
||||
self.security_roles = {}
|
||||
self.required_keys = ['key', 'label', 'type']
|
||||
self.type_posibilities = ['text', 'boolean', 'date', 'enumerator',
|
||||
'dynamic enumerator', 'number']
|
||||
|
||||
def discover(self, session, entities, event):
|
||||
'''
|
||||
Validation
|
||||
- action is only for Administrators
|
||||
'''
|
||||
success = False
|
||||
userId = event['source']['user']['id']
|
||||
user = session.query('User where id is ' + userId).one()
|
||||
for role in user['user_security_roles']:
|
||||
if role['security_role']['name'] == 'Administrator':
|
||||
success = True
|
||||
|
||||
return success
|
||||
|
||||
|
||||
def launch(self, session, entities, event):
|
||||
# JOB SETTINGS
|
||||
|
||||
userId = event['source']['user']['id']
|
||||
user = session.query('User where id is ' + userId).one()
|
||||
|
||||
job = session.create('Job', {
|
||||
'user': user,
|
||||
'status': 'running',
|
||||
'data': json.dumps({
|
||||
'description': 'Custom Attribute creation.'
|
||||
})
|
||||
})
|
||||
session.commit()
|
||||
try:
|
||||
self.avalon_mongo_id_attributes(session)
|
||||
self.custom_attributes_from_file(session, event)
|
||||
|
||||
job['status'] = 'done'
|
||||
session.commit()
|
||||
|
||||
except Exception as e:
|
||||
session.rollback()
|
||||
job['status'] = 'failed'
|
||||
session.commit()
|
||||
self.log.error("Creating custom attributes failed ({})".format(e))
|
||||
|
||||
return True
|
||||
|
||||
def avalon_mongo_id_attributes(self, session):
|
||||
# Attribute Name and Label
|
||||
cust_attr_name = 'avalon_mongo_id'
|
||||
cust_attr_label = 'Avalon/Mongo Id'
|
||||
|
||||
# Types that don't need object_type_id
|
||||
base = {'show'}
|
||||
|
||||
# Don't create custom attribute on these entity types:
|
||||
exceptions = ['task', 'milestone']
|
||||
exceptions.extend(base)
|
||||
|
||||
# Get all possible object types
|
||||
all_obj_types = session.query('ObjectType').all()
|
||||
|
||||
# Filter object types by exceptions
|
||||
filtered_types_id = set()
|
||||
|
||||
for obj_type in all_obj_types:
|
||||
name = obj_type['name']
|
||||
if " " in name:
|
||||
name = name.replace(" ","")
|
||||
|
||||
if obj_type['name'] not in self.object_type_ids:
|
||||
self.object_type_ids[name] = obj_type['id']
|
||||
|
||||
if name.lower() not in exceptions:
|
||||
filtered_types_id.add(obj_type['id'])
|
||||
|
||||
# Set security roles for attribute
|
||||
role_list = ["API","Administrator"]
|
||||
roles = self.get_security_role(role_list)
|
||||
# Set Text type of Attribute
|
||||
custom_attribute_type = self.get_type('text')
|
||||
# Set group to 'avalon'
|
||||
group = self.get_group('avalon')
|
||||
|
||||
data = {}
|
||||
data['key'] = cust_attr_name
|
||||
data['label'] = cust_attr_label
|
||||
data['type'] = custom_attribute_type
|
||||
data['default'] = ''
|
||||
data['write_security_roles'] = roles
|
||||
data['read_security_roles'] = roles
|
||||
data['group'] = group
|
||||
data['config'] = json.dumps({'markdown': False})
|
||||
|
||||
for entity_type in base:
|
||||
data['entity_type'] = entity_type
|
||||
self.process_attribute(data)
|
||||
|
||||
data['entity_type'] = 'task'
|
||||
for object_type_id in filtered_types_id:
|
||||
data['object_type_id'] = str(object_type_id)
|
||||
self.process_attribute(data)
|
||||
|
||||
def custom_attributes_from_file(self, session, event):
|
||||
try:
|
||||
with open(self.filepath) as data_file:
|
||||
json_dict = json.load(data_file)
|
||||
except Exception as e:
|
||||
msg = 'Loading "Custom attribute file" Failed. Please check log for more information'
|
||||
self.log.warning("{} - {}".format(msg,str(e)))
|
||||
self.show_message(event, msg)
|
||||
return
|
||||
|
||||
for cust_attr_name in json_dict:
|
||||
try:
|
||||
data = {}
|
||||
cust_attr = json_dict[cust_attr_name]
|
||||
# Get key, label, type
|
||||
data.update(self.get_required(cust_attr))
|
||||
# Get hierachical/ entity_type/ object_id
|
||||
data.update(self.get_entity_type(cust_attr))
|
||||
# Get group, default, security roles
|
||||
data.update(self.get_optional(cust_attr))
|
||||
# Process data
|
||||
self.process_attribute(data)
|
||||
|
||||
except CustAttrException as cae:
|
||||
msg = 'Custom attribute error "{}" - {}'.format(cust_attr_name, str(cae))
|
||||
self.log.warning(msg)
|
||||
self.show_message(event, msg)
|
||||
|
||||
return True
|
||||
|
||||
def process_attribute(self, data):
|
||||
existing_atr = self.session.query('CustomAttributeConfiguration').all()
|
||||
matching = []
|
||||
for attr in existing_atr:
|
||||
if (attr['key'] != data['key'] or
|
||||
attr['type']['name'] != data['type']['name']):
|
||||
continue
|
||||
|
||||
if 'is_hierarchical' in data:
|
||||
if data['is_hierarchical'] == attr['is_hierarchical']:
|
||||
matching.append(attr)
|
||||
elif 'object_type_id' in data:
|
||||
if (attr['entity_type'] == data['entity_type'] and
|
||||
attr['object_type_id'] == data['object_type_id']):
|
||||
matching.append(attr)
|
||||
else:
|
||||
if attr['entity_type'] == data['entity_type']:
|
||||
matching.append(attr)
|
||||
|
||||
if len(matching) == 0:
|
||||
self.session.create('CustomAttributeConfiguration', data)
|
||||
self.session.commit()
|
||||
|
||||
elif len(matching) == 1:
|
||||
attr_update = matching[0]
|
||||
for key in data:
|
||||
if key not in ['is_hierarchical','entity_type', 'object_type_id']:
|
||||
attr_update[key] = data[key]
|
||||
self.session.commit()
|
||||
|
||||
else:
|
||||
raise CustAttrException("Is duplicated")
|
||||
|
||||
|
||||
def get_required(self, attr):
|
||||
output = {}
|
||||
for key in self.required_keys:
|
||||
if key not in attr:
|
||||
raise CustAttrException("Key {} is required - please set".format(key))
|
||||
|
||||
if attr['type'].lower() not in self.type_posibilities:
|
||||
raise CustAttrException("Type {} is not valid".format(attr['type']))
|
||||
|
||||
type_name = attr['type'].lower()
|
||||
|
||||
output['key'] = attr['key']
|
||||
output['label'] = attr['label']
|
||||
output['type'] = self.get_type(type_name)
|
||||
|
||||
config = None
|
||||
if type_name == 'number':
|
||||
config = self.get_number_config(attr)
|
||||
elif type_name == 'text':
|
||||
config = self.get_text_config(attr)
|
||||
elif type_name == 'enumerator':
|
||||
config = self.get_enumerator_config(attr)
|
||||
|
||||
if config is not None:
|
||||
output['config'] = config
|
||||
|
||||
return output
|
||||
|
||||
def get_number_config(self, attr):
|
||||
if 'config' in attr and 'isdecimal' in attr['config']:
|
||||
isdecimal = attr['config']['isdecimal']
|
||||
else:
|
||||
isdecimal = False
|
||||
|
||||
config = json.dumps({'isdecimal':isdecimal})
|
||||
|
||||
return config
|
||||
|
||||
def get_text_config(self, attr):
|
||||
if 'config' in attr and 'markdown' in attr['config']:
|
||||
markdown = attr['config']['markdown']
|
||||
else:
|
||||
markdown = False
|
||||
config = json.dumps({'markdown':markdown})
|
||||
|
||||
return config
|
||||
|
||||
def get_enumerator_config(self,attr):
|
||||
if 'config' not in attr:
|
||||
raise CustAttrException("Missing config with data")
|
||||
if 'data' not in attr['config']:
|
||||
raise CustAttrException("Missing data in config")
|
||||
|
||||
data = []
|
||||
for item in attr['config']['data']:
|
||||
item_data = {}
|
||||
for key in item:
|
||||
# TODO key check by regex
|
||||
item_data['menu'] = item[key]
|
||||
item_data['value'] = key
|
||||
data.append(item_data)
|
||||
|
||||
if 'multiSelect' in attr['config']:
|
||||
multiSelect = attr['config']['multiSelect']
|
||||
else:
|
||||
multiSelect = False
|
||||
|
||||
config = json.dumps({
|
||||
'multiSelect':multiSelect,
|
||||
'data': json.dumps(data)
|
||||
})
|
||||
|
||||
return config
|
||||
|
||||
def get_group(self, attr):
|
||||
if isinstance(attr, str):
|
||||
group_name = attr
|
||||
else:
|
||||
group_name = attr['group'].lower()
|
||||
if group_name in self.groups:
|
||||
return self.groups[group_name]
|
||||
|
||||
query = 'CustomAttributeGroup where name is "{}"'.format(group_name)
|
||||
groups = self.session.query(query).all()
|
||||
|
||||
if len(groups) == 1:
|
||||
group = groups[0]
|
||||
self.groups[group_name] = group
|
||||
|
||||
return group
|
||||
|
||||
elif len(groups) < 1:
|
||||
group = self.session.create('CustomAttributeGroup', {
|
||||
'name': group_name,
|
||||
})
|
||||
self.session.commit()
|
||||
|
||||
return group
|
||||
|
||||
else:
|
||||
raise CustAttrException("Found more than one group '{}'".format(group_name))
|
||||
|
||||
def get_role_ALL(self):
|
||||
role_name = 'ALL'
|
||||
if role_name in self.security_roles:
|
||||
all_roles = self.security_roles[role_name]
|
||||
else:
|
||||
all_roles = self.session.query('SecurityRole').all()
|
||||
self.security_roles[role_name] = all_roles
|
||||
for role in all_roles:
|
||||
if role['name'] not in self.security_roles:
|
||||
self.security_roles[role['name']] = role
|
||||
return all_roles
|
||||
|
||||
def get_security_role(self, security_roles):
|
||||
roles = []
|
||||
if len(security_roles) == 0 or security_roles[0] == 'ALL':
|
||||
roles = self.get_role_ALL()
|
||||
elif security_roles[0] == 'except':
|
||||
excepts = security_roles[1:]
|
||||
all = self.get_role_ALL()
|
||||
for role in all:
|
||||
if role['name'] not in excepts:
|
||||
roles.append(role)
|
||||
if role['name'] not in self.security_roles:
|
||||
self.security_roles[role['name']] = role
|
||||
else:
|
||||
for role_name in security_roles:
|
||||
if role_name in self.security_roles:
|
||||
roles.append(self.security_roles[role_name])
|
||||
continue
|
||||
|
||||
try:
|
||||
query = 'SecurityRole where name is "{}"'.format(role_name)
|
||||
role = self.session.query(query).one()
|
||||
self.security_roles[role_name] = role
|
||||
roles.append(role)
|
||||
except Exception as e:
|
||||
raise CustAttrException("Securit role '{}' does not exist".format(role_name))
|
||||
|
||||
return roles
|
||||
|
||||
def get_default(self, attr):
|
||||
type = attr['type']
|
||||
default = attr['default']
|
||||
err_msg = 'Default value is not'
|
||||
if type == 'number':
|
||||
if not isinstance(default, (float, int)):
|
||||
raise CustAttrException('{} integer'.format(err_msg))
|
||||
elif type == 'text':
|
||||
if not isinstance(default, str):
|
||||
raise CustAttrException('{} string'.format(err_msg))
|
||||
elif type == 'boolean':
|
||||
if not isinstance(default, bool):
|
||||
raise CustAttrException('{} boolean'.format(err_msg))
|
||||
elif type == 'enumerator':
|
||||
if not isinstance(default, array):
|
||||
raise CustAttrException('{} array with strings'.format(err_msg))
|
||||
# TODO check if multiSelect is available and if default is one of data menu
|
||||
if not isinstance(default[0], str):
|
||||
raise CustAttrException('{} array of strings'.format(err_msg))
|
||||
elif type == 'date':
|
||||
date_items = default.split(" ")
|
||||
try:
|
||||
if len(date_items) == 1:
|
||||
default = arrow.get(default, 'YY.M.D')
|
||||
elif len(date_items) == 2:
|
||||
default = arrow.get(default, 'YY.M.D H:m:s')
|
||||
else:
|
||||
raise Exception
|
||||
except Exception as e:
|
||||
raise CustAttrException('Date is not in proper format')
|
||||
elif type == 'dynamic enumerator':
|
||||
raise CustAttrException('Dynamic enumerator can\'t have default')
|
||||
|
||||
return default
|
||||
|
||||
def get_optional(self, attr):
|
||||
output = {}
|
||||
if 'group' in attr:
|
||||
output['group'] = self.get_group(attr)
|
||||
if 'default' in attr:
|
||||
output['default'] = self.get_default(attr)
|
||||
|
||||
roles_read = []
|
||||
roles_write = []
|
||||
if 'read_security_roles' in output:
|
||||
roles_read = attr['read_security_roles']
|
||||
if 'read_security_roles' in output:
|
||||
roles_write = attr['write_security_roles']
|
||||
output['read_security_roles'] = self.get_security_role(roles_read)
|
||||
output['write_security_roles'] = self.get_security_role(roles_write)
|
||||
|
||||
return output
|
||||
|
||||
def get_type(self, type_name):
|
||||
if type_name in self.types:
|
||||
return self.types[type_name]
|
||||
|
||||
query = 'CustomAttributeType where name is "{}"'.format(type_name)
|
||||
type = self.session.query(query).one()
|
||||
self.types[type_name] = type
|
||||
|
||||
return type
|
||||
|
||||
def get_entity_type(self, attr):
|
||||
if 'is_hierarchical' in attr:
|
||||
if attr['is_hierarchical'] is True:
|
||||
return {'is_hierarchical':True}
|
||||
|
||||
if 'entity_type' not in attr:
|
||||
raise CustAttrException('Missing entity_type')
|
||||
|
||||
if attr['entity_type'].lower() != 'task':
|
||||
return {'entity_type':attr['entity_type']}
|
||||
|
||||
if 'object_type' not in attr:
|
||||
raise CustAttrException('Missing object_type')
|
||||
|
||||
object_type_name = attr['object_type']
|
||||
if object_type_name not in self.object_type_ids:
|
||||
try:
|
||||
query = 'ObjectType where name is "{}"'.format(object_type_name)
|
||||
object_type_id = self.session.query(query).one()['id']
|
||||
except Exception as e:
|
||||
raise CustAttrException('Object type with name "{}" don\'t exist'.format(object_type_name))
|
||||
self.object_type_ids[object_type_name] = object_type_id
|
||||
else:
|
||||
object_type_id = self.object_type_ids[object_type_name]
|
||||
|
||||
return {
|
||||
'entity_type': attr['entity_type'],
|
||||
'object_type_id': object_type_id
|
||||
}
|
||||
|
||||
def register(session, **kw):
|
||||
'''Register plugin. Called when used as an plugin.'''
|
||||
|
||||
# Validate that session is an instance of ftrack_api.Session. If not,
|
||||
# assume that register is being called from an old or incompatible API and
|
||||
# return without doing anything.
|
||||
if not isinstance(session, ftrack_api.session.Session):
|
||||
return
|
||||
|
||||
action_handler = CustomAttributes(session)
|
||||
action_handler.register()
|
||||
|
||||
|
||||
def main(arguments=None):
|
||||
'''Set up logging and register action.'''
|
||||
if arguments is None:
|
||||
arguments = []
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
# Allow setting of logging level from arguments.
|
||||
loggingLevels = {}
|
||||
for level in (
|
||||
logging.NOTSET, logging.DEBUG, logging.INFO, logging.WARNING,
|
||||
logging.ERROR, logging.CRITICAL
|
||||
):
|
||||
loggingLevels[logging.getLevelName(level).lower()] = level
|
||||
|
||||
parser.add_argument(
|
||||
'-v', '--verbosity',
|
||||
help='Set the logging output verbosity.',
|
||||
choices=loggingLevels.keys(),
|
||||
default='info'
|
||||
)
|
||||
namespace = parser.parse_args(arguments)
|
||||
|
||||
# Set up basic logging
|
||||
logging.basicConfig(level=loggingLevels[namespace.verbosity])
|
||||
|
||||
session = ftrack_api.Session()
|
||||
register(session)
|
||||
|
||||
# Wait for events
|
||||
logging.info(
|
||||
'Registered actions and listening for events. Use Ctrl-C to abort.'
|
||||
)
|
||||
session.event_hub.wait()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
raise SystemExit(main(sys.argv[1:]))
|
||||
|
|
@ -309,7 +309,7 @@ def register(session, **kw):
|
|||
return
|
||||
|
||||
action_handler = SyncToAvalon(session)
|
||||
action_handler.register()
|
||||
action_handler.register(200)
|
||||
|
||||
|
||||
def main(arguments=None):
|
||||
|
|
|
|||
|
|
@ -27,8 +27,17 @@ class TestAction(BaseAction):
|
|||
|
||||
def discover(self, session, entities, event):
|
||||
''' Validation '''
|
||||
discover = False
|
||||
roleList = ['Pypeclub']
|
||||
userId = event['source']['user']['id']
|
||||
user = session.query('User where id is ' + userId).one()
|
||||
|
||||
return True
|
||||
for role in user['user_security_roles']:
|
||||
if role['security_role']['name'] in roleList:
|
||||
discover = True
|
||||
break
|
||||
|
||||
return discover
|
||||
|
||||
|
||||
def launch(self, session, entities, event):
|
||||
|
|
@ -70,7 +79,7 @@ def register(session, **kw):
|
|||
return
|
||||
|
||||
action_handler = TestAction(session)
|
||||
action_handler.register()
|
||||
action_handler.register(10000)
|
||||
|
||||
|
||||
def main(arguments=None):
|
||||
|
|
|
|||
|
|
@ -54,12 +54,12 @@ class AppAction(object):
|
|||
'''Return current session.'''
|
||||
return self._session
|
||||
|
||||
def register(self):
|
||||
def register(self, priority = 100):
|
||||
'''Registers the action, subscribing the discover and launch topics.'''
|
||||
self.session.event_hub.subscribe(
|
||||
'topic=ftrack.action.discover and source.user.username={0}'.format(
|
||||
self.session.api_user
|
||||
), self._discover
|
||||
), self._discover,priority=priority
|
||||
)
|
||||
|
||||
self.session.event_hub.subscribe(
|
||||
|
|
@ -467,12 +467,15 @@ class BaseAction(object):
|
|||
def reset_session(self):
|
||||
self.session.reset()
|
||||
|
||||
def register(self):
|
||||
'''Registers the action, subscribing the the discover and launch topics.'''
|
||||
def register(self, priority = 100):
|
||||
'''
|
||||
Registers the action, subscribing the the discover and launch topics.
|
||||
- highest priority event will show last
|
||||
'''
|
||||
self.session.event_hub.subscribe(
|
||||
'topic=ftrack.action.discover and source.user.username={0}'.format(
|
||||
self.session.api_user
|
||||
), self._discover
|
||||
), self._discover, priority=priority
|
||||
)
|
||||
|
||||
self.session.event_hub.subscribe(
|
||||
|
|
@ -632,6 +635,37 @@ class BaseAction(object):
|
|||
'''
|
||||
return None
|
||||
|
||||
def show_message(self, event, input_message, result = False):
|
||||
"""
|
||||
Shows message to user who triggered event
|
||||
- event - just source of user id
|
||||
- input_message - message that is shown to user
|
||||
- result - changes color of message (based on ftrack settings)
|
||||
- True = Violet
|
||||
- False = Red
|
||||
"""
|
||||
if not isinstance(result, bool):
|
||||
result = False
|
||||
|
||||
try:
|
||||
message = str(input_message)
|
||||
except:
|
||||
return
|
||||
|
||||
user_id = event['source']['user']['id']
|
||||
self.session.event_hub.publish(
|
||||
ftrack_api.event.base.Event(
|
||||
topic='ftrack.action.trigger-user-interface',
|
||||
data=dict(
|
||||
type='message',
|
||||
success=result,
|
||||
message=message
|
||||
),
|
||||
target='applicationId=ftrack.client.web and user.id="{0}"'.format(user_id)
|
||||
),
|
||||
on_error='ignore'
|
||||
)
|
||||
|
||||
def _handle_result(self, session, result, entities, event):
|
||||
'''Validate the returned result from the action callback'''
|
||||
if isinstance(result, bool):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue