def add_attr_access(self, search_type, attr, level): # find the group group_xpath = "rules/group[@key='%s']" % (search_type) group = self.xml.get_node(group_xpath) if group == None: # add the group (default to view) group_level = "view" group = self.add_sobject_access(search_type,group_level) # get the attr rule rule_xpath = "rules/group[@key='%s']/rule[@key='%s']" % (search_type,attr) rule = self.xml.get_node(rule_xpath ) if rule != None: # if nothing has changed, continue access = Xml.get_attribute(rule,"access") if level == access: raise CommandExitException() else: rule = self.xml.create_element("rule") rule.setAttributeNS(None,"key",attr) #group.appendChild(rule) Xml.append_child(group, rule) #self.root.appendChild(group) Xml.append_child(self.root, group) # set the access level rule.setAttributeNS(None,"type","attr") rule.setAttributeNS(None,"access",level)
def execute(my): my.init() # create the filters my.filters = [] """ for element_name in my.config.get_element_names(): filter = my.config.get_display_widget(element_name) my.filters.append(filter) # make sure there is at least one filter defined assert my.filters """ config = "<config>\n" config += "<filter>\n" # get all of the serialized versions of the filters """ for filter in my.filters: config += filter.serialize() + "\n" """ filter_data = FilterData.get() json = filter_data.serialize() value_type = "json" config += "<values type='%s'>%s</values>\n" % (value_type, json) config += "</filter>\n" config += "</config>\n" # format the xml xml = Xml() xml.read_string(config) if not my.view: saved_view = "saved_search:%s" % my.search_type else: saved_view = my.view # if my.view.startswith("saved_search:"): # saved_view = my.view # else: # saved_view = "saved_search:%s" % my.view # use widget config instead search = Search("config/widget_config") search.add_filter("view", saved_view) search.add_filter("search_type", my.search_type) if my.personal: search.add_user_filter() config = search.get_sobject() if not config: config = SearchType.create("config/widget_config") config.set_value("view", saved_view) config.set_value("search_type", my.search_type) if my.personal: config.set_user() config.set_value("config", xml.to_string()) config.commit()
def get_child_types(self, search_type, relationship="hierarchy", hierarchy=True): if search_type.find("?") != -1: search_type, tmp = search_type.split("?", 1) child_types = [] # first get the child types defined in the admin schema if hierarchy and self.sthpw_schema: sthpw_child_types = self.sthpw_schema.get_child_types(search_type, relationship) child_types.extend(sthpw_child_types) # get the child types in the project type schema if hierarchy and self.parent_schema: parent_child_types = self.parent_schema.get_child_types(search_type, relationship) child_types.extend(parent_child_types) # add new style connects = self.xml.get_nodes("schema/connect[@to='%s'] | schema/connect[@to='*']" % search_type) for connect in connects: relationship = Xml.get_attribute(connect, "relationship") # skip old style if not relationship: continue child_type = Xml.get_attribute(connect, "from") # skip identical type if child_type == search_type: continue child_types.append(child_type) return child_types
def get_input_snapshots(my, sobject, process_name, input_name, version='latest'): '''gets the snapshots of the input''' assert version in ['latest', 'current'] process_node = my.xml.get_node( "pipeline/process[@name='%s']/input[@name='%s']" % (process_name, input_name)) search_type = Xml.get_attribute(process_node, "search_type") context = Xml.get_attribute(process_node, "context") filter = Xml.get_attribute(process_node, "filter") # get the sobjects sobjects = sobject.get_all_children(search_type) # get the snapshots search = Search("sthpw/snapshot") search.add_filter('context', context) #if version == 'latest': # search.add_filter("is_latest", 1) #elif version == 'current': # search.add_filter("is_current", 1) # build filters for search_type, search_id combinations filters = [] for sobject in sobjects: filter = "(\"search_type\" = '%s' and \"search_id\" = %s)" % (sobject.get_search_type(), sobject.get_id() ) filters.append(filter) search.add_where( "( %s )" % " or ".join(filters) ) snapshots = search.get_sobjects() return snapshots
def get_related_search_types(self, search_type, direction=None): related_types = [] if not direction or direction == "parent": xpath = "schema/connect[@from='%s']" %(search_type) connects = self.xml.get_nodes(xpath) for connect in connects: related_type = Xml.get_attribute(connect,"to") related_types.append(related_type) if not direction or direction == "children": xpath = "schema/connect[@to='%s']" %(search_type) connects = self.xml.get_nodes(xpath) for connect in connects: related_type = Xml.get_attribute(connect,"from") related_types.append(related_type) if self.parent_schema: search_types = self.parent_schema.get_related_search_types(search_type, direction=direction) related_types.extend(search_types) if self.sthpw_schema: search_types = self.sthpw_schema.get_related_search_types(search_type, direction=direction) related_types.extend(search_types) return related_types
def delete_files(my, nodes): # clean out all of the files for node in nodes: name = my.xml.get_node_name(node) if name == "include": path = my.xml.get_attribute(node, "path") if not path: print("WARNING: No path found for search type in manifest") continue path = "%s/%s" % (my.plugin_dir, path) if path.endswith(".py"): from tactic.command import PythonCmd cmd = PythonCmd(file_path=path) manifest = cmd.execute() if manifest: xml = Xml() xml.read_string(manifest) include_nodes = xml.get_nodes("manifest/*") my.delete_files(include_nodes) elif name == "python": # don't delete python node file pass else: path = my.get_path_from_node(node) if path and os.path.exists(path): print "Deleting: ", path os.unlink(path)
def handle_include(my, node): path = my.xml.get_attribute(node, "path") if not path: raise TacticException("No path found for include in manifest") path = "%s/%s" % (my.plugin_dir, path) if path.endswith(".py"): from tactic.command import PythonCmd cmd = PythonCmd(file_path=path) manifest = cmd.execute() if not manifest: print "No manifest discovered in [%s]" %path return xml = Xml() xml.read_string(manifest) nodes = xml.get_nodes("manifest/*") sobjects = [] for i, node in enumerate(nodes): name = my.xml.get_node_name(node) if name == 'sobject': dumped_sobjects = my.handle_sobject(node) if not dumped_sobjects: dumped_sobjects = [] sobjects.extend(dumped_sobjects) elif name == 'search_type': my.handle_search_type(node) elif name == 'include': my.handle_include(node)
def _test_accept(my): # try json url = "http://localhost/tactic/unittest/rest" headers = { "Accept": "application/json" } ret_val = my.send_request(url, headers) my.assertEquals( [3,2,1], ret_val) # try xml url = "http://localhost/tactic/unittest/rest" headers = { "Accept": "application/xml" } ret_val = my.send_request(url, headers) xml = Xml(ret_val) values = xml.get_values("arr/int") my.assertEquals( ['1','2','3'], values) # try json url = "http://localhost/tactic/unittest/rest/CODE0123" headers = { "Accept": "application/json" } ret_val = my.send_request(url, headers) my.assertEquals( "OK", ret_val)
def execute(my): database = "sthpw" sql = DbContainer.get(database) value_array = sql.do_query("select code, cc from (select code, count(code) as cc from file group by code order by cc desc) as X where cc > 1;") #value_array = sql.do_query("select code, cc from (select code, count(code) as cc from file group by code order by cc desc) as X;") print "found [%s] pairs" % len(value_array) for count, value_list in enumerate(value_array): if count >= BATCH: break # get the file object file_code = value_list[0] search = Search("sthpw/file") search.add_filter("code", file_code) files = search.get_sobjects() #if len(files) == 1: # continue for file in files: project_code = file.get_value("project_code") if not project_code: print "WARNING: file [%s] has no project_code" % file_code continue project = Project.get_by_code(project_code) initials = project.get_initials() id = file.get_id() new_file_code = "%s%s" % (id, initials) if file_code == new_file_code: continue print "-"*20 print "switching: ", file_code, "to", new_file_code snapshot_code = file.get_value("snapshot_code") snapshot = Snapshot.get_by_code(snapshot_code) assert snapshot snapshot_xml = snapshot.get_xml_value("snapshot") print snapshot_xml.to_string() node = snapshot_xml.get_node("snapshot/file[@file_code='%s']" % file_code) Xml.set_attribute(node, "file_code", new_file_code) print snapshot_xml.to_string() assert node # set the file_code file.set_value("code", new_file_code) file.commit() # set the snapshot snapshot.set_value("snapshot", snapshot_xml.to_string() ) snapshot.commit()
def get_config(my): # TEST config_xml = ''' <config> <custom_filter> <element name='asset_library'> <display class='SelectWdg'> <query>prod/asset_library|code|code</query> <empty>true</empty> </display> </element> <element name='pipeline_code'> <display class='SelectWdg'> <query>sthpw/pipeline|code|code</query> <empty>true</empty> </display> </element> </custom_filter> </config> ''' my.view = my.kwargs.get("search_view") if not my.view: my.view = 'custom_filter' #view = "custom_filter" project_code = Project.extract_project_code(my.search_type) search = Search("config/widget_config", project_code=project_code ) search.add_filter("view", my.view) search.add_filter("search_type", my.base_search_type) config_sobj = search.get_sobject() if config_sobj: config_xml = config_sobj.get_value("config") else: config_xml = ''' <config> <custom_filter> </custom_filter> </config> ''' # use the one defined in the default config file file_configs = WidgetConfigView.get_configs_from_file(my.base_search_type, my.view) if file_configs: config = file_configs[0] xml_node = config.get_view_node() if xml_node is not None: xml = Xml(config.get_xml().to_string()) config_xml = '<config>%s</config>' %xml.to_string(node=xml_node) from pyasm.widget import WidgetConfig config = WidgetConfig.get(view=my.view, xml=config_xml) return config
def get_plugin_data(my, reldir): manifest_path = "%s/%s/manifest.xml" % (my.base_dir, reldir) xml = Xml() xml.read_file(manifest_path) node = xml.get_node("manifest/data") data = xml.get_node_values_of_children(node) return data
def handle_config(my): web = WebContainer.get_web() search_type = my.kwargs.get("search_type") view = my.view config_search_type = "config/widget_config" search = Search(config_search_type) search.add_filter("search_type", search_type) search.add_filter("view", view) search.add_filter("login", my.login) config = search.get_sobject() if not config: config = SearchType.create(config_search_type) config.set_value("search_type", search_type ) config.set_value("view", view ) if my.login: config.set_value("login", my.login ) xml = config.get_xml_value("config", "config") root = xml.get_root_node() # reinitialize config._init() # build a new config view_node = xml.create_element(view) root.appendChild(view_node) config_mode = web.get_form_value("config_mode") if config_mode == "advanced": config_string = web.get_form_value("config_xml") else: config_title = web.get_form_value("config_title") config_icon = web.get_form_value("config_icon") config_icon2 = web.get_form_value("config_icon2") if config_icon2: config_icon = config_icon2 # TAKEN FROM API: should be centralized or something from tactic.ui.panel import SideBarBookmarkMenuWdg config_view = SideBarBookmarkMenuWdg.get_config(search_type, view) node = config_view.get_element_node(my.element_name) if node: config_xml = config_view.get_xml() node = config_view.get_element_node(my.element_name) Xml.set_attribute(node, "title", config_title) Xml.set_attribute(node, "icon", config_icon) config_string = config_xml.to_string(node) else: config_string = ''' <element name="%s" title="%s" icon="%s"/> ''' %(my.element_name, config_title, config_icon) config.append_xml_element(my.element_name, config_string) config.commit_config()
def _read_ref_file(my): '''read the reference file containing extra node information''' dir = my.get_upload_dir() xml = Xml() key = my.sobject.get_code() # make this filename good for the file system filename = File.get_filesystem_name(key) xml.read_file( "%s/%s-ref.xml" % (dir,filename) ) return xml
def _test_guest_allow(self): '''test Config tag allow_guest in security tag. Note: Since it is hard to emulate AppServer class, this is based on logic which handles in _get_display of BaseAppServer. 1. If allow_guest is false, then it is necessary that Sudo is instantiated. 2. If allow_guest is true, then it is necessary that guest login rules are added and login_as_guest is executed. ''' security = Security() Environment.set_security(security) #1. allow_guest is false fail = False try: sudo = Sudo() except Exception as e: fail = True self.assertEquals( False, fail ) sudo.exit() key = [{'code': "*"}] project_access = security.check_access("project", key, "allow") self.assertEquals(project_access, False) #2. allow_guest is true Site.set_site("default") try: security.login_as_guest() ticket_key = security.get_ticket_key() access_manager = security.get_access_manager() xml = Xml() xml.read_string(''' <rules> <rule column="login" value="{$LOGIN}" search_type="sthpw/login" access="deny" op="!=" group="search_filter"/> <rule group="project" code="default" access="allow"/> </rules> ''') access_manager.add_xml_rules(xml) finally: Site.pop_site() default_key = [{'code': "default"}] project_access = security.check_access("project", default_key, "allow") self.assertEquals(project_access, True) unittest_key = [{'code', "sample3d"}] project_access = security.check_access("project", unittest_key, "allow") self.assertEquals(project_access, False)
def get_parent_type(my, search_type, relationship=None): # NOTE: relationship arg is deprecated!! if search_type.find("?") != -1: search_type, tmp = search_type.split("?", 1) # make a provision for admin search_types passed in if my.get_code() != "admin" and search_type.startswith("sthpw/"): parent_type = Schema.get_admin_schema().get_parent_type(search_type, relationship) if parent_type: return parent_type parent_type = "" # look at new style connections first connects = my.xml.get_nodes("schema/connect[@from='%s']" % search_type ) for connect in connects: relationship_new = Xml.get_attribute(connect, "relationship") if relationship_new: type = Xml.get_attribute(connect, "type") if type == 'hierarchy': parent_type = Xml.get_attribute(connect, "to") break # NOTE: there could be multiple parents here. Hierarchy type # should be the one to resolve this. # if there is no "hierarchy" type, use the first one if not parent_type: for connect in connects: from_type = Xml.get_attribute(connect, "from") if from_type == search_type: parent_type = Xml.get_attribute(connect, "to") break """ # DEPRECATED: resort to old style if not parent_type: connects = my.xml.get_nodes("schema/connect[@to='%s']" % search_type ) # FIXME: you need to assign parent_type here for connect in connects: type = Xml.get_attribute(connect, "type") if type != relationship: continue parent_type = Xml.get_attribute(connect, "from") # FIXME: should we call break? """ if not parent_type and my.parent_schema: parent_type = my.parent_schema.get_parent_type(search_type, relationship) return parent_type
def get_config(self): self.view = self.kwargs.get("search_view") config = self.kwargs.get("search_config") if not self.view: self.view = 'custom_filter' #view = "custom_filter" project_code = Project.extract_project_code(self.search_type) search = Search("config/widget_config", project_code=project_code ) search.add_filter("view", self.view) search.add_filter("search_type", self.base_search_type) config_sobjs = search.get_sobjects() from pyasm.search import WidgetDbConfig config_sobj = WidgetDbConfig.merge_configs(config_sobjs) if config_sobj: #config_xml = config_sobj.get("config") config_xml = config_sobj.get_xml().to_string() config_xml = config_xml.replace("<", "<") config_xml = config_xml.replace(">", ">") config_xml = Common.run_mako(config_xml) elif config: config_xml = ''' <config> <custom_filter>%s </custom_filter> </config> ''' % config else: config_xml = ''' <config> <custom_filter> </custom_filter> </config> ''' # use the one defined in the default config file file_configs = WidgetConfigView.get_configs_from_file(self.base_search_type, self.view) if file_configs: config = file_configs[0] xml_node = config.get_view_node() if xml_node is not None: xml = Xml(config.get_xml().to_string()) config_xml = '<config>%s</config>' %xml.to_string(node=xml_node) from pyasm.widget import WidgetConfig config = WidgetConfig.get(view=self.view, xml=config_xml) return config
def get_task_pipeline(my, default=True): ''' assuming the child pipeline is task related ''' task_pipeline_code = Xml.get_attribute( my.node, "task_pipeline" ) node_type = Xml.get_attribute(my.node, "type") if node_type == "approval": return "approval" if not task_pipeline_code and default: return "task" else: return task_pipeline_code
def execute(self): project_type = "prod" # copy all of the widget configs from the prod definition and put # them into the database xml = Xml(string=test_xml) search_type = "SideBarWdg" view = "cow" config = WidgetDbConfig.create(search_type, view, data=xml.to_string()) '''
def get_action_nodes(my, scope="dependent"): action_nodes = [] nodes = Xml.get_children(my.node) for node in nodes: node_name = Xml.get_node_name(node) if node_name == "action": node_scope = Xml.get_attribute(node, "scope") if scope and node_scope != scope: continue action_nodes.append(node) return action_nodes
def _test_sobject_access_manager(my): '''test a more realistic example''' # create a test person person = Person.create("Donald", "Duck", "DisneyLand", "A duck!!!") my.person = person for project_code in ['unittest','unittest','sample3d']: task = SearchType.create('sthpw/task') task.set_sobject_value(person) task.set_value('assigned', 'unittest_guy') task.set_value('project_code', project_code) task.set_value('description', 'do something good') task.set_value('process', 'unittest') task.set_value('context', 'unittest') task.commit() # an extra task for list-based search_filter test task = SearchType.create('sthpw/task') task.set_sobject_value(person) task.set_value('assigned', 'unittest_gal') task.set_value('project_code', 'unittest') task.set_value('description', 'do something good') task.set_value('process', 'unittest2') task.set_value('context', 'unittest2') task.commit() # add these rules to the current user rules = """ <rules> <rule group="sobject_column" default="edit"/> <rule group="sobject_column" search_type="unittest/person" column="name_first" access="edit"/> <rule group="sobject_column" search_type="unittest/person" column="name_last" access="deny"/> <rule group="sobject_column" search_type="unittest/person" column="nationality" access="deny"/> </rules> """ xml = Xml() xml.read_string(rules) access_manager = Environment.get_security().get_access_manager() access_manager.add_xml_rules(xml) # disable admin for this test access_manager.set_admin(False) # should succeed person.set_value("name_first", "Donny") # should fail try: person.set_value("name_last", "Ducky") except SecurityException, e: pass
def handle_columns_mode(my): doc = my.xml.create_doc("config") root = my.xml.get_root_node() columns = my.get_columns() if len(columns) == 1 and columns[0] == "id": columns = my.get_columns(required_only=False) # create the table # search is a special view for SearchWdg and it should not be created if my.view not in ['search','publish']: if my.view.find('@') != -1: table = my.xml.create_element('view', attrs={'name': my.view}) else: table = my.xml.create_element(my.view) my.xml.append_child(root, table) for column in columns: if column in ["_id", "id", "oid", "s_status"]: continue element = my.xml.create_element("element") Xml.set_attribute(element, "name", column) my.xml.append_child(table, element) # add history, input and output for the load view (designed for app loading) if my.view == 'load': element = my.xml.create_element("element") Xml.set_attribute(element, "name", "checkin") my.xml.append_child(table, element) for column in ['input', 'output']: element = my.xml.create_element("element") Xml.set_attribute(element, "name", column) Xml.set_attribute(element, "edit", "false") display_element = my.xml.create_element("display") Xml.set_attribute(display_element, "class", "tactic.ui.cgapp.LoaderElementWdg") my.xml.append_child(element, display_element) stype, key = SearchType.break_up_key(my.search_type) op1 = my.xml.create_text_element("search_type", stype) op2 = my.xml.create_text_element("mode", column) my.xml.append_child(display_element, op1) my.xml.append_child(display_element, op2) my.xml.append_child(table, element) value = my.xml.to_string() my.xml = Xml() my.xml.read_string(value)
def get_by_code(cls, code, allow_default=False): '''it is fatal not to have a pipeline, so put a default''' if not code: return None # first look at project specific pipeline pipeline = Search.get_by_code("config/pipeline", code) if not pipeline: pipeline = super(Pipeline,cls).get_by_code(code) if not pipeline and code == 'task': # Create a default task pipeline pipeline = SearchType.create("sthpw/pipeline") pipeline.set_value("code", "task") from pyasm.biz import Task xml = Task.get_default_task_xml() pipeline.set_value("pipeline", xml) pipeline.set_pipeline(xml) pipeline.set_value("search_type", "sthpw/task") #pipeline.commit() if not pipeline and allow_default: search = Search(cls) search.add_filter('code', 'default') pipeline = search.get_sobject() if not pipeline: pipeline = cls.create('default', \ 'default pipeline', '') xml = pipeline.get_xml_value("pipeline") # create a default process for the table root = xml.get_root_node() element = xml.create_element("process") Xml.set_attribute(element,"name", "default_process") Xml.append_child(root, element) pipeline.set_value('pipeline', xml.get_xml()) pipeline.commit() # set the pipeline pipeline.set_pipeline(pipeline.get_value('pipeline')) Environment.add_warning("pipeline autogenerated", \ "[default] pipeline has just been created.") # Sometimes, a pipeline is instantiated without calling set_pipeline() # to be looked into if pipeline and not pipeline.get_processes(): pipeline.set_pipeline(pipeline.get_value('pipeline')) return pipeline
def get_file_info(xml, file_objects, sobject, snapshot, show_versionless=False, is_list=False, protocol='http'): info = {} #TODO: {'file_type': [file_type]: [path], 'base_type': [base_type]: [file|directory|sequence]} if is_list: info = [] else: repo_info = {} info['_repo'] = repo_info nodes = xml.get_nodes("snapshot/file") for node in nodes: type = Xml.get_attribute(node, "type") file_code = Xml.get_attribute(node, "file_code") file_object = file_objects.get(file_code) if not file_object: if isinstance(info, dict): info[type] = ThumbWdg.get_no_image() else: info.append((type, ThumbWdg.get_no_image())) Environment.add_warning("No file object", "No file object found for file code '%s'" % file_code) continue file_name = file_object.get_full_file_name() web_dir = sobject.get_web_dir(snapshot, file_object=file_object) # handle a range if it exists file_range = file_object.get_value("file_range") if file_range: from pyasm.biz import FileGroup, FileRange file_range = FileRange.get(file_range) file_names = FileGroup.expand_paths(file_name, file_range) # just check the first frame if file_names: file_name = file_names[0] path = "%s/%s" % (web_dir, file_name) if protocol != "file": path = urllib.pathname2url(path) if isinstance(info, dict): info[type] = path lib_dir = sobject.get_lib_dir(snapshot, file_object=file_object) repo_info[type] = "%s/%s" % (lib_dir, file_name) else: info.append((type, path)) return info
class Package(Command): def __init__(self, search_key, context, package): self.search_key = search_key self.context = context self.package = package self.package_xml = Xml() self.package_xml.read_string(package) super(Package, self).__init__() def execute(self): from tactic_client_lib import TacticServerStub server = TacticServerStub.get(protocol='local') # create a new snapshot snapshot = server.create_snapshot(self.search_key, self.context) # get all of the file_types file_nodes = self.package_xml.get_nodes("package/file_type") count = 0 for file_node in file_nodes: name = self.package_xml.get_attribute(file_node, "name") values = self.package_xml.get_node_values_of_children(file_node) expression = values.get("expression") dir_naming = values.get("dir_naming") file_naming = values.get("file_naming") files = Search.eval(expression) for file in files: file_type = "%s%s" % (name, count) try: # FIXME: the assumed action is to checkin server.add_file(snapshot, file, file_type=file_type, mode='copy', dir_naming=dir_naming, file_naming=file_naming) # What if we just wished to copy? Can we run the files # through a naming convention filter? count += 1 except Exception as e: print "WARNING: ", str(e)
def execute(self): self.init() # create the filters self.filters = [] config = "<config>\n" config += "<filter>\n" # get all of the serialized versions of the filters filter_data = FilterData.get() json = filter_data.serialize() value_type = "json" config += "<values type='%s'>%s</values>\n" % (value_type, json) config += "</filter>\n" config += "</config>\n" # format the xml xml = Xml() xml.read_string(config) if not self.view: saved_view = "saved_search:%s" % self.search_type else: saved_view = self.view # if self.view.startswith("saved_search:"): # saved_view = self.view # else: # saved_view = "saved_search:%s" % self.view # use widget config instead search = Search('config/widget_config') search.add_filter("view", saved_view) search.add_filter("search_type", self.search_type) if self.personal: search.add_user_filter() config = search.get_sobject() if not config: config = SearchType.create('config/widget_config') config.set_value("view", saved_view) config.set_value("search_type", self.search_type) if self.personal: config.set_user() config.set_value("category", "search_filter") config.set_value("config", xml.to_string()) config.commit()
def get_action_node(my, event_name, scope="dependent"): nodes = Xml.get_children(my.node) for node in nodes: node_name = Xml.get_node_name(node) if node_name == "action": node_event = Xml.get_attribute(node, "event") if node_event != event_name: continue node_scope = Xml.get_attribute(node, "scope") if scope and node_scope != scope: continue return node
def get_action_options(my, event_name, scope="dependent"): options = {} action_node = my.get_action_node(event_name, scope=scope) if action_node is None: return options nodes = Xml.get_children(action_node) for node in nodes: name = Xml.get_node_name(node) if name == "#text": continue value = Xml.get_node_value(node) options[name] = value return options
def get_by_ticket(ticket): search = Search(TransactionState) search.add_filter("ticket", ticket) state = search.get_sobject() # create the state data for this ticket if not state: state = SObjectFactory.create(TransactionState.SEARCH_TYPE) state.set_value("ticket", ticket) data = Xml() data.create_doc("state") state.set_value("data", data.to_string() ) state.commit() return state
def get_type(my): node_type = Xml.get_attribute( my.node, "type" ) if node_type == "auto": node_type = "action" if not node_type: node_type = "manual" return node_type
def import_schema(plugin_code): from pyasm.search import Transaction transaction = Transaction.get(create=True) install_dir = Environment.get_install_dir() base_dir = Environment.get_plugin_dir() template_dir = "%s/%s" % (base_dir, plugin_code) manifest_path = "%s/manifest.xml" % (template_dir) print "Reading manifest: ", manifest_path xml = Xml() xml.read_file(manifest_path) # create a new project installer = PluginInstaller(base_dir=base_dir, manifest=xml.to_string() ) installer.execute()
def get_by_code(cls, code, allow_default=False): '''it is fatal not to have a pipeline, so put a default''' if not code: return None # first look at project specific pipeline pipeline = Search.get_by_code("config/pipeline", code) if not pipeline: pipeline = super(Pipeline, cls).get_by_code(code) if not pipeline and code == 'task': # Create a default task pipeline pipeline = SearchType.create("sthpw/pipeline") pipeline.set_value("code", "task") from pyasm.biz import Task xml = Task.get_default_task_xml() pipeline.set_value("pipeline", xml) pipeline.set_pipeline(xml) pipeline.set_value("search_type", "sthpw/task") #pipeline.commit() if not pipeline and code == 'approval': # Create a default task pipeline pipeline = SearchType.create("sthpw/pipeline") pipeline.set_value("code", "approval") from pyasm.biz import Task xml = Task.get_default_approval_xml() pipeline.set_value("pipeline", xml) pipeline.set_pipeline(xml) pipeline.set_value("search_type", "sthpw/task") #pipeline.commit() if not pipeline and code == 'dependency': # Create a default task pipeline pipeline = SearchType.create("sthpw/pipeline") pipeline.set_value("code", "dependency") from pyasm.biz import Task xml = Task.get_default_dependency_xml() pipeline.set_value("pipeline", xml) pipeline.set_pipeline(xml) pipeline.set_value("search_type", "sthpw/task") #pipeline.commit() if not pipeline and allow_default: search = Search(cls) search.add_filter('code', 'default') pipeline = search.get_sobject() if not pipeline: pipeline = cls.create('default', \ 'default pipeline', '') xml = pipeline.get_xml_value("pipeline") # create a default process for the table root = xml.get_root_node() element = xml.create_element("process") Xml.set_attribute(element, "name", "default_process") Xml.append_child(root, element) pipeline.set_value('pipeline', xml.get_xml()) pipeline.commit() # set the pipeline pipeline.set_pipeline(pipeline.get_value('pipeline')) Environment.add_warning("pipeline autogenerated", \ "[default] pipeline has just been created.") # Sometimes, a pipeline is instantiated without calling set_pipeline() # to be looked into if pipeline and not pipeline.get_processes(): pipeline.set_pipeline(pipeline.get_value('pipeline')) return pipeline
def get_from_pipeline(my): return Xml.get_attribute(my.node, "from_pipeline")
def get_to_expression(my): return Xml.get_attribute(my.node, "to_expression")
def handle_basic_mode(my): doc = my.xml.create_doc("config") root = my.xml.get_root_node() db_columns = my.get_columns() if "code" in db_columns: columns = ["preview", "code"] elif "name" in db_columns: columns = ["preview", "name"] elif "id" in db_columns: columns = ["preview", "id"] table = my.xml.create_element("table") Xml.append_child(root, table) for column in ["preview", "code"]: element = my.xml.create_element("element") Xml.set_attribute(element, "name", column) Xml.append_child(table, element) # create the edit edit = my.xml.create_element("edit") Xml.append_child(root, edit) for column in ["preview", "code"]: element = my.xml.create_element("element") Xml.set_attribute(element, "name", column) Xml.append_child(edit, element) # create the manual publish view publish = my.xml.create_element("publish") Xml.append_child(root, publish) element = my.xml.create_element("element") Xml.set_attribute(element, "name", "image") Xml.append_child(publish, element) dis_element = my.xml.create_element("display") Xml.set_attribute(dis_element, "class", "ThumbInputWdg") act_element = my.xml.create_element("action") Xml.set_attribute(act_element, "class", "NullAction") Xml.append_child(element, dis_element) Xml.append_child(element, act_element) element = my.xml.create_element("element") Xml.set_attribute(element, "name", "publish_files") Xml.append_child(publish, element) dis_element = my.xml.create_element("display") Xml.set_attribute(dis_element, "class", "UploadWdg") # add options option = my.xml.create_text_element('names', 'publish_icon|publish_main') Xml.append_child(dis_element, option) option = my.xml.create_text_element('required', 'false|true') Xml.append_child(dis_element, option) act_element = my.xml.create_element("action") Xml.set_attribute(act_element, "class", "MultiUploadAction") # add options option = my.xml.create_text_element('names', 'publish_icon|publish_main') Xml.append_child(act_element, option) option = my.xml.create_text_element('types', 'icon_main|main') Xml.append_child(act_element, option) Xml.append_child(element, dis_element) Xml.append_child(element, act_element) value = my.xml.to_string() my.xml = Xml() my.xml.read_string(value)
def get_to(my): return Xml.get_attribute(my.node, "to")
def get_from(my): return Xml.get_attribute(my.node, "from")
def get_label(my): return Xml.get_attribute(my.node, "label")
def add_xml_rules(my, xml, project_code=None): '''xml should be an XML object with the data in the form of <rules> <group type='sobject' default='<default>'> <rule key='<key>' access='<access>'/> </group> </rules> ''' from pyasm.search import SObject if isinstance(xml, SObject): sobject = xml xml = sobject.get_xml_value("access_rules") if not project_code: project_code = sobject.get_value("project_code") project_override = project_code if isinstance(xml, basestring): xmlx = Xml() xmlx.read_string(xml) xml = xmlx my.xml = xml # parse shorthand rules rule_nodes = xml.get_nodes("rules/rule") if not rule_nodes: return # store all of the project codes (this will only run once) if my.project_codes == None: search = Search('sthpw/project') projects = search.get_sobjects() my.project_codes = [x.get_code() for x in projects] my.project_codes.append('*') for rule_node in rule_nodes: # initiate the project_code here for each loop project_code = '*' group_type = Xml.get_attribute(rule_node, "group") if not group_type: # category is the preferred name over group now # TODO: phase out the use of group completely group_type = Xml.get_attribute(rule_node, "category") # get an existing rule set or create a new one if my.groups.has_key(group_type): rules = my.groups[group_type] else: rules = {} my.groups[group_type] = rules # set the default, if specified group_default = xml.get_attribute(rule_node, "default") if group_default: rules['__DEFAULT__'] = group_default continue # generate the rule key #rule_key = xml.get_attribute(rule_node, 'key') attrs = xml.get_attributes(rule_node) attrs2 = {} count = 0 for name, value in attrs.items(): if name in ['access', 'group', 'category', 'project']: continue # have to turn everything into strings attrs2[str(name)] = str(value) count += 1 if count == 1 and attrs2.has_key('key'): # backwards compatibility rule_key = attrs2['key'] else: #rule_key = str(attrs2) rule_key = str(Common.get_dict_list(attrs2)) if project_override: rule_project = project_override else: rule_project = xml.get_attribute(rule_node, 'project') if rule_project: project_code = rule_project # special treatment for search_filter to enable # project-specific search if group_type == 'search_filter': attrs2['project'] = rule_project # if there is a value, then combine it with the key rule_value = xml.get_attribute(rule_node, 'value') if rule_value: rule_key = "%s||%s" % (rule_key, rule_value) # add a project code qualifier rule_keys = [] if project_code == '*' and group_type != 'search_filter': for code in my.project_codes: key = "%s?project=%s" % (rule_key, code) rule_keys.append(key) else: key = "%s?project=%s" % (rule_key, project_code) #key = str(key) # may need to stringify unicode string rule_keys.append(key) rule_access = xml.get_attribute(rule_node, 'access') #if rule_access == "": # raise AccessException("Cannot have empty 'access':\n%s" \ # % xml.to_string(rule_node) ) # if no key is specified, it is considered a DEFAULT if not rule_keys and not rule_value: rule_keys = ['__DEFAULT__'] for rule_key in rule_keys: # check if rule_access exists first, which doesn't for search_filter, # but it has to go into the rules regardless # if the rule already exists, take the highest one if rule_access and rules.has_key(rule_key): curr_access, cur_attrs = rules[rule_key] try: access_enum = my._get_access_enum(rule_access) if my._get_access_enum(curr_access) > access_enum: continue except: if group_type == "builtin": continue else: raise rules[rule_key] = rule_access, attrs2 #for rule, values in rules.items(): # print "rule: ", rule, values[0] # FIXME: this one doesn't support the multi-attr structure # convert this to a python data structure group_nodes = xml.get_nodes("rules/group") for group_node in group_nodes: group_type = Xml.get_attribute(group_node, "type") # get an existing rule set or create a new one if my.groups.has_key(group_type): rules = my.groups[group_type] else: rules = {} my.groups[group_type] = rules # set the default, if specified group_default = xml.get_attribute(group_node, "default") if group_default != "": rules['__DEFAULT__'] = group_default # get all of the rule nodes rule_nodes = Xml.get_children(group_node) for rule_node in rule_nodes: project_code = '*' if Xml.get_node_name(rule_node) != 'rule': continue rule_key = xml.get_attribute(rule_node, 'key') rule_access = xml.get_attribute(rule_node, 'access') if project_override: rule_project = project_override else: rule_project = xml.get_attribute(rule_node, 'project') if rule_project: project_code = rule_project if rule_access == "": raise AccessException("Cannot have empty 'access':\n%s" \ % xml.to_string(rule_node) ) rule_keys = [] attrs2 = {'key': rule_key} # add a project code qualifier if project_code == '*' and group_type != 'search_filter': for code in my.project_codes: key = "%s?project=%s" % (rule_key, code) rule_keys.append(key) else: key = "%s?project=%s" % (rule_key, project_code) rule_keys.append(key) for rule_key in rule_keys: rules[rule_key] = rule_access, attrs2
def get_from_expression(my, name): return Xml.get_attribute(my.node, name)
def execute(self): log = self.log rules = self.rules # Give rules. Only notes will get through # we need heirarchical rules. This will ensure that only notes # for project/assets will pass # Here, the second one is much more difficult to do. rulesXXX = ''' <rule group='heirarchy' key='project/asset.sthpw/note' access='allow'/> <rule group='heirarchy' key="project/asset.sthpw/note['assigned','beth']" access='allow'/>" ''' access_manager = AccessManager() access_manager.add_xml_rules(rules) # filter out project namespace = log.get_value("namespace") key1 = { 'code': namespace } key2 = { 'code': '*' } keys = [key1, key2] if not access_manager.check_access("project", keys, "allow", default="deny"): self.filtered_xml = Xml() self.filtered_xml.read_string("<transaction/>") self.message = "Transaction prevented due to project restriction" return # filter the transaction against the security model xml = log.get_xml_value("transaction") self.filtered_xml = Xml() self.filtered_xml.create_doc("transaction") root2 = self.filtered_xml.get_root_node() nodes = xml.get_nodes("transaction/*") num_nodes = len(nodes) count = 0 for node in nodes: if Xml.get_node_name(node) == "sobject": search_type = xml.get_attribute(node, "search_type") parts = search_type.split("?") search_type = parts[0] # filter search types key1 = { 'code': search_type } key2 = { 'code': "*" } keys = [ key1, key2 ] if not access_manager.check_access("search_type", keys, "allow", default="deny"): continue # check hierachical rule parent_type = xml.get_attribute(node, "parent_type") key = "%s.%s" % (parent_type, search_type) self.filtered_xml.append_child(root2, node) count += 1 else: self.filtered_xml.append_child(root2, node) count += 1 if len(nodes) != 0 and len(self.filtered_xml.get_nodes("transaction/*")) == 0: self.message = "All actions filtered due to security restrictions (%s actions)" % num_nodes
def get_handler(my): return Xml.get_attribute(my.node, "handler")
def get_attribute(my, name): return Xml.get_attribute(my.node, name)
def get_name(my): return Xml.get_attribute(my.node, "name")
def get_to_pipeline(my): return Xml.get_attribute(my.node, "to_pipeline")
def get_title(my): return Xml.get_attribute(my.node, "title")
def serialize(self): '''provide the ability for a widget to serialize itself''' xml = Xml() xml.create_doc("config") # create the top element element = xml.create_element("element") xml.set_attribute(element, "name", self.name) # create the display handler display = xml.create_element("display") xml.set_attribute(display, "class", Common.get_full_class_name(self)) element.appendChild(display) # create the options for name, value in self.kwargs.items(): if value: option = xml.create_text_element(name, value) else: # avoid the \n in the textContent of the textNode option = xml.create_element(name) display.appendChild(option) return xml.to_string(element)
# clear these again when set externally my.processes = [] my.recursive_processes = [] # create the process and pipelines process_nodes = my.xml.get_nodes( "pipeline/process | pipeline/pipeline") for node in process_nodes: node_name = my.xml.get_node_name(node) process = Process(node) process.set_parent_pipeline_code(my.get_code()) my.processes.append(process) if node_name == "pipeline": name = Xml.get_attribute(node, "name") # prevent infinite loop if name == my.get_code(): continue child = Pipeline.get_by_code(name) if not child: continue my.pipeline_dict[name] = child process.set_child_pipeline(child) def get_pipeline_xml(my): return my.xml def to_string(my):
def execute(my): class_names = my.kwargs.get("class_names") attrs_list = my.kwargs.get("attrs_list") kwargs_list = my.kwargs.get("kwargs_list") xml = Xml() xml.create_doc("config") root = xml.get_root_node() view = xml.create_element("tab") xml.append_child(root, view) for class_name, attrs, kwargs in zip(class_names, attrs_list, kwargs_list): element = xml.create_element("element") xml.append_child(view, element) for key, value in attrs.items(): xml.set_attribute(element, key, value) display = xml.create_element("display") xml.append_child(element, display) xml.set_attribute(display, "class", class_name) for key, value in kwargs.items(): attr = xml.create_text_element(key, value, node=display) xml.append_child(display, attr) xml_string = xml.to_string() from pyasm.web import WidgetSettings WidgetSettings.set_value_by_key("tab", xml_string)
def get_default_filter_config(my): custom_filter_view = my.kwargs.get('custom_filter_view') if not custom_filter_view: custom_filter_view = '' config = [] config.append("<config>\n") config.append("<filter>\n") config.append(''' <element name='Keyword Search'> <display class='tactic.ui.filter.SObjectSearchFilterWdg'> <search_type>%s</search_type> <prefix>quick</prefix> </display> </element> ''' % my.search_type) config.append(''' <element name='Custom'> <display class='tactic.ui.filter.GeneralFilterWdg'> <prefix>custom</prefix> <search_type>%s</search_type> <mode>custom</mode> <custom_filter_view>%s</custom_filter_view> </display> </element> ''' % (my.search_type, custom_filter_view)) config.append(''' <element name='Filter'> <display class='tactic.ui.filter.GeneralFilterWdg'> <prefix>main_body</prefix> <search_type>%s</search_type> <mode>sobject</mode> </display> </element> ''' % my.search_type) """ config.append(''' <element name='Filter2'> <display class='tactic.ui.filter.GeneralFilterWdg'> <prefix>filter2</prefix> <search_type>%s</search_type> <mode>sobject</mode> </display> </element> ''' % my.search_type) """ config.append(''' <element name='Parent'> <display class='tactic.ui.filter.GeneralFilterWdg'> <prefix>parent</prefix> <search_type>%s</search_type> <mode>parent</mode> </display> </element> ''' % my.search_type) config.append(''' <element name='Children'> <display class='tactic.ui.filter.GeneralFilterWdg'> <prefix>children</prefix> <search_type>%s</search_type> <mode>child</mode> </display> </element> ''' % my.search_type) """ config.append(''' <element name='Related'> <display class='tactic.ui.filter.GeneralFilterWdg'> <prefix>related</prefix> <search_type>%s</search_type> <mode>child</mode> </display> </element> ''' % my.search_type) """ config.append("</filter>\n") config.append("</config>\n") config = ''.join(config) config_xml = Xml() config_xml.read_string(config) config = WidgetConfig.get(xml=config_xml, view='filter') return config
def get_color(my): color = Xml.get_attribute(my.node, "color") return color
def set_attribute(my, name, value): return Xml.set_attribute(my.node, name, value)
def get_display(self): # Custom URLs have the ability to send out different content types url = self.kwargs.get("url") web = WebContainer.get_web() #content_type = self.kwargs.get("content_type") #print("content_type: ", content_type) hash = self.kwargs.get("hash") ticket = web.get_form_value("ticket") method = web.get_request_method() headers = web.get_request_headers() accept = headers.get("Accept") expression = url.get_value("url") # extract values from custom url kwargs = Common.extract_dict(hash, expression) # Does the URL listen to specific Accept values? # or does it enforce a return content type ... and how does one # know what exactly is supported? Accept is kind of complicated. # Easier to put in as a paramenter ... but should accept both # get the widget designated for hash kwargs['Accept'] = accept kwargs['Method'] = method handler = self.kwargs.get("handler") if handler: hash_widget = Common.create_from_class_path(handler, [], kwargs) else: from tactic.ui.panel import HashPanelWdg hash_widget = HashPanelWdg.get_widget_from_hash(hash, kwargs=kwargs) # Really, the hash widget should determine what is returned, but # should take the Accept into account. It is not up to this # class to determine what is or isn't implemented, nor is it the # responsibility of this class to convert the data. So, it # returns whatever is given. try: custom_accept = hash_widget.get_content_type() accept = custom_accept except AttributeError as e: pass widget = Widget() # # Example implementation of custom script, run by hash_widget # if accept == "application/json": value = hash_widget.get_display() value = jsondumps(value) web.set_content_type(accept) elif accept == "application/xml": from pyasm.common import Xml value = hash_widget.get_display() if isinstance(value, basestring): xml = Xml(value) value = xml.to_string() elif isinstance(value, Xml): value = value.to_string() web.set_content_type(accept) elif accept == "plain/text": from pyasm.common import Xml value = hash_widget.get_display() value = str(value) web.set_content_type(accept) else: # return text/html value = DivWdg() if isinstance(hash_widget, basestring): value.add(hash_widget) else: value.add(hash_widget.get_display()) current_type = web.get_content_type() if not current_type: web.set_content_type("text/html") widget.add(value) return widget
def get_completion(my): return Xml.get_attribute(my.node, "completion")
def get_attributes(my): return Xml.get_attributes(my.node)
def init(my): link = my.kwargs.get('link') hash = my.kwargs.get('hash') my.widget = None if link: from tactic.ui.panel import SideBarBookmarkMenuWdg personal = False if '.' in link: personal = True config = SideBarBookmarkMenuWdg.get_config("SideBarWdg", link, personal=personal) options = config.get_display_options(link) # this is vital for view saving element_name = link attr_dict = config.get_element_attributes(link) title = attr_dict.get('title') hash = "/tab/%s" % link config = ''' <config> <application> <element name="left_nav"> <display class="tactic.ui.panel.SideBarPanelWdg"> </display> </element> <element name="main_body"> <display class="tactic.ui.panel.HashPanelWdg"> <hash>%s</hash> <element_name>%s</element_name> <title>%s</title> </display> <web/> </element> </application> </config> ''' % (hash, element_name, title) elif hash: from tactic.ui.panel import HashPanelWdg my.widget = HashPanelWdg.get_widget_from_hash(hash, force_no_index=True) config = None else: security = Environment.get_security() start_link = security.get_start_link() if start_link: my.kwargs['link'] = start_link return my.init() # search for a defined welcome view search = Search("config/widget_config") search.add_filter("category", "top_layout") search.add_filter("view", "welcome") config_sobj = search.get_sobject() if config_sobj: config = config_sobj.get_value("config") else: config = WidgetSettings.get_value_by_key("top_layout") if not config: config = my.get_default_config() my.config_xml = Xml() my.config_xml.read_string(config)
def get_from_expression(my): return Xml.get_attribute(my.node, "from_expression")
def get_widget_from_hash(cls, hash, return_none=False, force_no_index=False, kwargs={}): from pyasm.web import DivWdg if hash.startswith("//"): use_top = False hash = hash[1:] else: use_top = True import re p = re.compile("^/(\w+)") m = p.search(hash) if not m: if return_none: return None print "Cannot parse hash[%s]" % hash return DivWdg("Cannot parse hash [%s]" % hash) key = m.groups()[0] # guest user should never be able to see admin site if key != 'login': security = Environment.get_security() login = security.get_user_name() if login == "guest" and key == 'admin': #from pyasm.widget import Error403Wdg #return Error403Wdg().get_buffer_display() from pyasm.widget import WebLoginWdg # HACK: if the guest access is full, the the outer form # is not defined ... force it in here. This is because the # top used it TopWdg and not TitleTopWdg div = DivWdg() div.add("<form id='form' name='form' method='post' enctype='multipart/form-data'>\n") web_login_wdg = WebLoginWdg().get_buffer_display() div.add(web_login_wdg) div.add("</form>\n") return div sobject = cls._get_predefined_url(key, hash) # look up the url if not sobject: search = Search("config/url") search.add_filter("url", "/%s/%%"%key, "like") search.add_filter("url", "/%s"%key) search.add_where("or") sobject = search.get_sobject() if not sobject: if return_none: return None return DivWdg("No Widget found for hash [%s]" % hash) config = sobject.get_value("widget") config = config.replace('&','&') url = sobject.get_value("url") url = url.strip() # update the config value with expressions options = Common.extract_dict(hash, url) for name, value in options.items(): config = config.replace("{%s}" % name, value) xml = Xml() xml.read_string(config) use_index, use_admin, use_sidebar = cls._get_flags(xml, sobject, force_no_index, kwargs) if use_admin: # use admin from tactic.ui.app import PageNavContainerWdg top = PageNavContainerWdg( hash=hash, use_sidebar=use_sidebar ) return top.get_buffer_display() elif use_index: # check if there is an index search = Search("config/url") search.add_filter("url", "/index") index = search.get_sobject() # just use admin if no index page is found if not index: from tactic.ui.app import PageNavContainerWdg top = PageNavContainerWdg( hash=hash, use_sidebar=use_sidebar ) return top.get_buffer_display() config = index.get_value("widget") xml = Xml() xml.read_string(config) node = xml.get_node("element/display") options.update(xml.get_node_values_of_children(node)) class_name = xml.get_value("element/display/@class") if class_name: options['class_name'] = class_name # this passes the hash value to the index widget # which must handle it accordingly options['hash'] = hash top = cls.build_widget(options) return top.get_buffer_display() # process the options and then build the widget from the xml options = Common.extract_dict(hash, url) for name, value in kwargs.items(): options[name] = value node = xml.get_node("element/display") options.update(xml.get_node_values_of_children(node)) class_name = xml.get_value("element/display/@class") if class_name: options['class_name'] = class_name widget = cls.build_widget(options) name = hash.lstrip("/") name = name.replace("/", " ") widget.set_name(name) return widget
def get_group(my): return Xml.get_attribute(my.node, "group")
def handle_columns_mode(my): doc = my.xml.create_doc("config") root = my.xml.get_root_node() columns = my.get_columns() if len(columns) == 1 and columns[0] == "id": columns = my.get_columns(required_only=False) # create the table # search is a special view for SearchWdg and it should not be created if my.view not in ['search', 'publish']: if my.view.find('@') != -1: table = my.xml.create_element('view', attrs={'name': my.view}) else: table = my.xml.create_element(my.view) my.xml.append_child(root, table) for column in columns: if column in ["_id", "id", "oid", "s_status"]: continue element = my.xml.create_element("element") Xml.set_attribute(element, "name", column) my.xml.append_child(table, element) # add history, input and output for the load view (designed for app loading) if my.view == 'load': element = my.xml.create_element("element") Xml.set_attribute(element, "name", "checkin") my.xml.append_child(table, element) for column in ['input', 'output']: element = my.xml.create_element("element") Xml.set_attribute(element, "name", column) Xml.set_attribute(element, "edit", "false") display_element = my.xml.create_element("display") Xml.set_attribute(display_element, "class", "tactic.ui.cgapp.LoaderElementWdg") my.xml.append_child(element, display_element) stype, key = SearchType.break_up_key(my.search_type) op1 = my.xml.create_text_element("search_type", stype) op2 = my.xml.create_text_element("mode", column) my.xml.append_child(display_element, op1) my.xml.append_child(display_element, op2) my.xml.append_child(table, element) value = my.xml.to_string() my.xml = Xml() my.xml.read_string(value)
def get_action_handler(my, event_name, scope="dependent"): action_node = my.get_action_node(event_name, scope=scope) if action_node is None: return None action_handler = Xml.get_attribute(action_node, "class") return action_handler