def main(server=None, input=None): """ The main function of the custom script. The entire script was copied and pasted into the body of the try statement in order to add some error handling. It's all legacy code, so edit with caution. :param server: the TacticServerStub object :param input: a dict with data like like search_key, search_type, sobject, and update_data :return: None """ if not input: input = {} try: # CUSTOM_SCRIPT00103 # Matthew Tyler Misenhimer # Sends an email when a External Rejection is updated def fix_note_chars(note): if isinstance(note, bool): note2 = 'False' if note: note2 = 'True' note = note2 else: import sys from json import dumps as jsondumps if note not in [None,'']: if sys.stdout.encoding: note = note.decode(sys.stdout.encoding) note = jsondumps(note) note = note.replace('||t',' ') note = note.replace('\\\\t',' ') note = note.replace('\\\t',' ') note = note.replace('\\t',' ') note = note.replace('\t',' ') note = note.replace('\\"','"') note = note.replace('\"','"') note = note.replace('||n','<br/>') note = note.replace('\\\\n','<br/>') note = note.replace('\\\n','<br/>') note = note.replace('\\n','<br/>') note = note.replace('\n','<br/>') return note import os, time from pyasm.common import Environment import common_tools.utils as ctu internal_template_file = '/opt/spt/custom/formatted_emailer/internal_general_fillin_template.html' trigger_sobject = input.get('trigger_sobject') event = trigger_sobject.get('event') is_insert = False if 'insert' in event: is_insert = True if not is_insert: er_dict = input.get('sobject') login = er_dict.get('login') order_code = er_dict.get('order_code') title_code = er_dict.get('title_code') reported_issue = er_dict.get('reported_issue') if reported_issue not in [None,'']: reported_issue = reported_issue.replace('\n','<br/>').replace(' ',' ') reported_issue = fix_note_chars(reported_issue) rcnq = "@SOBJECT(sthpw/note['search_id','%s']['process','Root Cause']['search_type','twog/external_rejection?project=twog'])" % (er_dict.get('id')) root_cause_notes = server.eval(rcnq) root_cause = '' for rc in root_cause_notes: root_cause = '%s\n%s -- %s\n<b>Note: %s</b>\n' % (root_cause, rc.get('login'), rc.get('timestamp').split('.')[0], rc.get('note')) if root_cause not in [None,'']: root_cause = root_cause.replace('\n','<br/>').replace(' ',' ') root_cause = fix_note_chars(root_cause) corrective_action_notes = server.eval("@SOBJECT(sthpw/note['search_id','%s']['process','Corrective Action']['search_type','twog/external_rejection?project=twog'])" % (er_dict.get('id'))) corrective_action = '' for ca in corrective_action_notes: corrective_action = '%s\n%s -- %s\n<b>Note:%s</b>\n' % (corrective_action, ca.get('login'), ca.get('timestamp').split('.')[0], ca.get('note')) if corrective_action not in [None,'']: corrective_action = corrective_action.replace('\n','<br/>').replace(' ',' ') corrective_action = fix_note_chars(corrective_action) title = er_dict.get('title') episode = er_dict.get('episode') po_number = er_dict.get('po_number') assigned = er_dict.get('assigned') status = er_dict.get('status') root_cause_type = er_dict.get('root_cause_type') corrective_action_assigned = er_dict.get('corrective_action_assigned') email_list = er_dict.get('email_list') addressed_to = email_list sources = er_dict.get('sources') replacement_order_code = er_dict.get('replacement_order_code') replacement_title_code = er_dict.get('replacement_title_code') reasons = ['video_cropping_reason','video_digihits_reason','video_dropped_frames_reason','video_dropout_reason','video_duplicate_frames_reason','video_interlacing_progressive_reason','video_motion_lag_reason','video_missing_elements_reason','video_corrupt_file_reason','video_bad_aspect_ratio_reason','video_bad_resolution_reason','video_bad_pixel_aspect_ratio_reason','video_bad_specifications_reason','video_bad_head_tail_reason','video_other_reason','audio_bad_mapping_reason','audio_missing_audio_channel_reason','audio_crackle_reason','audio_distortion_reason','audio_dropouts_reason','audio_sync_reason','audio_missing_elements_reason','audio_corrupt_missing_file_reason','audio_bad_specifications_reason','audio_other_reason','metadata_missing_info_reason','metadata_bad_info_reason','metadata_bad_formatting_reason','metadata_other_reason','subtitle_interlacing_reason','subtitle_bad_subtitles_reason','subtitle_sync_issue_reason','subtitle_overlapping_reason','subtitle_other_reason','cc_sync_issue_reason','cc_bad_cc_reason','cc_overlapping_reason','cc_other_reason'] order_obj = server.eval("@SOBJECT(twog/order['code','%s'])" % order_code) order_name = '' client_name = '' scheduler = '' if order_obj: order_obj = order_obj[0] order_name = order_obj.get('name') client_name = order_obj.get('client_name') scheduler = order_obj.get('login') order_builder_url = ctu.get_order_builder_url(order_code, server) href = '<a href="{0}">{1}</a>' order_hyperlink = href.format(order_builder_url, order_name) title_obj = server.eval("@SOBJECT(twog/title['code','%s'])" % title_code) title_due_date = '' title_expected_delivery = '' title_full_name = title if episode not in [None,'']: title_full_name = '%s: %s' % (title, episode) if title_obj: title_obj = title_obj[0] title_due_date = title_obj.get('due_date') title_expected_delivery = title_obj.get('expected_delivery_date') if client_name in [None,'']: client_name = title_obj.get('client_name') if scheduler in [None,'']: scheduler = order_obj.get('login') update_data = None main_message = '' head_message = '' head_detail = '' is_an_update = False if 'update_data' in input.keys(): update_data = input.get('update_data') prev_data = input.get('prev_data') if prev_data not in [None,{},'']: ukeys = update_data.keys() if len(ukeys) > 0: is_an_update = True head_message = 'Update for External Rejection on %s (%s) [%s PO#: %s]:' % (title_full_name, title_code, order_code, po_number) if 'status' in ukeys and update_data['status'] == 'Closed': head_message += '<br/><br/>THIS EXTERNAL REJECTION IS NOW CLOSED' else: return main_message = '<table style="font-size: 14px;"><tr><td colspan="2"><br/><hr></td><td> </td></tr>' main_message += '<tr><td valign="top"><b><u>Reported Issue:</u></b></td><td valign="top">{0}</td></tr>'.format(reported_issue) main_message += '<tr><td valign="top"><b><u>Root Cause:</u></b></td><td valign="top">{0}</td></tr>'.format(root_cause) main_message += '<tr><td valign="top"><b><u>Corrective Action:</u></b></td><td valign="top">{0}</td></tr>'.format(corrective_action) main_message += '</table>' if is_an_update: subject_int = 'NEW - URGENT External Rejection Closed for %s (%s) - Status: %s Scheduler: %s PO#: %s' % (title_full_name, title_code, status, scheduler, po_number) else: return head_detail = '<tr><td align="left" style="font-size: 16px;">Replacement Order Code: <strong>%s</strong></td></tr><tr><td align="left" style="font-size: 16px;">Replacement Title Code: <strong>%s</strong></td></tr>' % (replacement_order_code, replacement_title_code) from formatted_emailer import EmailDirections ed = EmailDirections(order_code=order_code) int_data = ed.get_internal_data() int_template = open(internal_template_file, 'r') filled = '' for line in int_template: line = line.replace('[ORDER_CODE]', order_code) line = line.replace('[ORDER_NAME]', order_hyperlink) line = line.replace('[PO_NUMBER]', po_number) line = line.replace('[MAIN_MESSAGE]', main_message) line = line.replace('[TOP_MESSAGE]', head_message) line = line.replace('[EXTRA_HEAD_DETAIL]', head_detail) line = line.replace('[CLIENT_NAME]', client_name) line = line.replace('[TITLE_CODE]', title_code) line = line.replace('[TITLE_FULL_NAME]', title_full_name) line = line.replace('[TITLE_DUE_DATE]', title_due_date) line = line.replace('[TITLE_EXPECTED_DELIVERY]', title_expected_delivery) filled = '%s%s' % (filled, line) int_template.close() filled_in_email = '/var/www/html/formatted_emails/int_note_inserted_%s.html' % er_dict.get('code') filler = open(filled_in_email, 'w') filler.write(filled) filler.close() if addressed_to not in [None,'']: adt = addressed_to.split(',') for adta in adt: if '@2gdigital' in adta and adta not in int_data['int_ccs']: if int_data['int_ccs'] == '': int_data['int_ccs'] = adta else: int_data['int_ccs'] = '%s;%s' % (int_data['int_ccs'], adta) if int_data['int_ccs'] in [None,'']: int_data['int_ccs'] = '[email protected];[email protected]' else: int_data['int_ccs'] = '%s;[email protected];[email protected]' % int_data['int_ccs'] int_data['int_ccs'] = '%s;[email protected]' % (int_data['int_ccs']) login_email = server.eval("@GET(sthpw/login['login','%s'].email)" % login) if login_email: int_data['from_email'] = login_email[0] #NEW WAY TO SET THE FROM FOR THE EMAIL login_obj = Environment.get_login() sender_email = login_obj.get_value('email') sender_name = '%s %s' % (login_obj.get_value('first_name'), login_obj.get_value('last_name')) subject_int = subject_int.replace(' ','..') #the_command = "php /opt/spt/custom/formatted_emailer/trusty_emailer.php '''%s''' '''%s''' '''%s''' '''%s''' '''%s''' '''%s'''" % (filled_in_email, int_data['to_email'], int_data['from_email'], int_data['from_name'], subject_int, int_data['int_ccs'].replace(';','#Xs*')) the_command = "php /opt/spt/custom/formatted_emailer/trusty_emailer.php '''%s''' '''%s''' '''%s''' '''%s''' '''%s''' '''%s'''" % (filled_in_email, int_data['to_email'], sender_email, sender_name, subject_int, int_data['int_ccs'].replace(';','#Xs*')) if int_data['to_email'] not in [None,''] and int_data['int_ccs'] not in [None,'',';']: os.system(the_command) except AttributeError as e: traceback.print_exc() print str(e) + '\nMost likely the server object does not exist.' raise e except KeyError as e: traceback.print_exc() print str(e) + '\nMost likely the input dictionary does not exist.' raise e except Exception as e: traceback.print_exc() print str(e) raise e
def get_internal_data(my): login_email = '' sched_team = '' int_list = [] # Figure out who the email should say it is from from_email = '' if my.client: sched_team = my.client.get('scheduling_team_email') if sched_team: from_email = sched_team if my.scheduler_email not in [None,''] and from_email == '': from_email = my.scheduler_email if my.logged_in_login.get('location') == 'internal': if my.logged_in_login.get('email') not in [None,'']: login_email = my.logged_in_login.get('email') if from_email == '': if login_email not in [None,'']: from_email = login_email if from_email == '': from_email = '*****@*****.**' #Figure out who we want to send the email to to_email = '' if sched_team not in [None,'']: to_email = sched_team if to_email == '' and my.scheduler_email not in [None,'']: to_email = my.scheduler_email elif my.scheduler_email not in [None,'']: int_list.append(my.scheduler_email) if my.logged_in_login.get('location') == 'internal': if login_email not in [None,'']: if to_email == '': to_email = login_email else: if login_email not in int_list: int_list.append(login_email) if to_email == '': to_email = '*****@*****.**' #If the client has people that they want alerted all the time for their notifications, get those email addresses too - as long as it's not the client themself that's writing the note (or whatever) internal_email_list1 = my.logged_in_login.get('internal_notification_list') internal_email_list2 = '' if my.client_login_obj: if my.client_login_obj.get('internal_notification_list') not in [None,''] and my.client_login_obj.get('login') != my.logged_in_login.get('login'): internal_email_list2 = my.client_login_obj.get('internal_notification_list') internal_email_list3 = '' if my.client: if my.client.get('internal_notification_list'): internal_email_list3 = my.client.get('internal_notification_list') list1_arr = internal_email_list1.split(',') list2_arr = internal_email_list2.split(',') list3_arr = internal_email_list3.split(',') all_lists = list1_arr + list2_arr + list3_arr for email in all_lists: if email not in int_list: int_list.append(email) order_builder_url = ctu.get_order_builder_url(my.order_code, my.server) href = '<a href="{0}">{1}</a>' order_hyperlink = href.format(order_builder_url, my.order_name) client_hyperlink = ctu.get_edit_wdg_hyperlink('twog/client', my.client_code, sobject_name=my.client_name, server=my.server) clean_data = {} for key, val in my.data.iteritems(): if key != 'ext_ccs': clean_data[key] = val send_data = clean_data send_data['order_hyperlink'] = order_hyperlink send_data['client_hyperlink'] = client_hyperlink send_data['from_email'] = from_email send_data['to_email'] = to_email #print "int list = %s" % int_list final_int_list = [] for thing in int_list: if thing not in [None,'',[]]: final_int_list.append(thing) cc_list = ';'.join(final_int_list) if cc_list not in [None,'']: if cc_list[0] == ';': cc_list = cc_list[1:] send_data['int_ccs'] = cc_list send_data['ccs'] = send_data.get('int_ccs') return send_data
def main(server=None, input=None): """ The main function of the custom script. The entire script was copied and pasted into the body of the try statement in order to add some error handling. It's all legacy code, so edit with caution. :param server: the TacticServerStub object :param input: a dict with data like like search_key, search_type, sobject, and update_data :return: None """ if not input: input = {} try: # CUSTOM_SCRIPT00078 from pyasm.common import Environment from pyasm.biz import Note from pyasm.search import Search import common_tools.utils as ctu login = Environment.get_login() user_name = login.get_login() delim = '#Xs*' all_ccs = '[email protected]%[email protected]' % delim #This is for production_error operator_description update sobject = input.get('sobject') operator_description = sobject.get('operator_description') title_code = sobject.get('title_code') wo_code = sobject.get('work_order_code') title_id_pre = title_code.split('TITLE')[1] found_non_zero = False title_id = '' note = '' for ch in title_id_pre: if ch != '0': found_non_zero = True if ch == '0' and found_non_zero or (ch != '0'): title_id = '%s%s' % (title_id, ch) wo_code = sobject.get('work_order_code') expr = "@SOBJECT(sthpw/note['search_id','%s']['search_type','~','twog/title']['process','QC Rejected']['@ORDER_BY','timestamp desc'])" % (title_id) last_note = server.eval(expr) if last_note: last_note = last_note[0] # Now just need to update it with the operator description, wo code and title note = last_note.get('note') note = '%s\n%s' % (note, operator_description) server.update(last_note.get('__search_key__'), {'note': note}, triggers=False) wo_obj2 = Search.get_by_search_key(server.build_search_key('twog/work_order',wo_code)) #This is the type of object required for Note creation note2 = Note.create(wo_obj2, note, context='QC Rejected', process='QC Rejected') wo = server.eval("@SOBJECT(twog/work_order['code','%s'])" % wo_code)[0] proj = server.eval("@SOBJECT(twog/proj['code','%s'])" % wo.get('proj_code'))[0] title = server.eval("@SOBJECT(twog/title['code','%s'])" % proj.get('title_code'))[0] order = server.eval("@SOBJECT(twog/order['code','%s'])" % title.get('order_code'))[0] scheduler_name = order.get('login') scheduler = server.eval("@SOBJECT(sthpw/login['login','%s']['location','internal'])" % scheduler_name) if scheduler: scheduler = scheduler[0] all_ccs = '%s%s%s' % (all_ccs, delim, scheduler.get('email')) group = '' process = '' client_name = '' po_number = order.get('po_number') order_name = order.get('name') title_name = title.get('title') episode = title.get('episode') if wo: group = wo.get('work_group') process = wo.get('process') client_name = wo.get('client_name') error_type = sobject.get('error_type') rejection_cause = sobject.get('rejection_cause') time_spent = sobject.get('time_spent') client_description = sobject.get('client_description') client_description = client_description.replace('\t',' ') client_description = client_description.replace('\n','<br/>') client_description = client_description.replace(' ', ' ') operator_description = operator_description.replace('\t',' ') operator_description = operator_description.replace('\n','<br/>') operator_description = operator_description.replace(' ', ' ') action_taken = sobject.get('action_taken') order_builder_url = ctu.get_order_builder_url(order.get('code'), server) href = '<a href="{0}">{1}</a>' order_hyperlink = href.format(order_builder_url, order_name) title_row = '' proj_row = '' if title: full_title = title.get('title') if title.get('episode') not in [None,'']: full_title = '%s: %s' % (full_title, title.get('episode')) title_row = "<tr><td align='left' style='color: #06C; font-size: 16px;'>Title: <strong>%s</strong> | Title Code: <strong>%s</strong></td></tr>" % (full_title, title.get('code')) if proj: proj_row = "<tr><td align='left' style='color: #06C; font-size: 16px;'>Project: <strong>%s</strong> | Project Code: <strong>%s</strong></td></tr>" % (proj.get('process'), proj.get('code')) template_path = '/opt/spt/custom/formatted_emailer/error_msg.html' filled_in_path = '/var/www/html/formatted_emails/error_msg_%s.html' % wo_code template = open(template_path, 'r') filled = '' for line in template: line = line.replace('[WORK_ORDER_CODE]', wo_code) line = line.replace('[TITLE_CODE]', title.get('code')) line = line.replace('[PROJ_CODE]', proj.get('code')) line = line.replace('[TITLE_ROW]', title_row) line = line.replace('[PROJ_ROW]', proj_row) line = line.replace('[ORDER_CODE]', order.get('code')) line = line.replace('[LOGIN]', user_name) line = line.replace('[GROUP]', group) line = line.replace('[PROCESS]', process) line = line.replace('[CLIENT_NAME]', client_name) line = line.replace('[PO_NUMBER]', po_number) line = line.replace('[ORDER_NAME]', order_hyperlink) line = line.replace('[TITLE]', title_name) line = line.replace('[EPISODE]', episode) line = line.replace('[ERROR_TYPE]', error_type) line = line.replace('[REJECTION_CAUSE]', rejection_cause) line = line.replace('[TIME_SPENT]', time_spent) line = line.replace('[CLIENT_DESCRIPTION]', client_description) line = line.replace('[OPERATOR_DESCRIPTION]', operator_description) line = line.replace('[ACTION_TAKEN]', action_taken) filled = '%s%s' % (filled, line) template.close() filler = open(filled_in_path, 'w') filler.write(filled) filler.close() server.insert('twog/bundled_message', {'filled_in_path': filled_in_path, 'message': 'New Error', 'from_email': '*****@*****.**', 'to_email': '*****@*****.**', 'from_name': 'Tech Alert', 'subject': 'Error: %s, %s, %s: %s' % (wo_code, po_number, title_name, episode), 'all_ccs': all_ccs, 'object_code': wo_code}) except AttributeError as e: traceback.print_exc() print str(e) + '\nMost likely the server object does not exist.' raise e except KeyError as e: traceback.print_exc() print str(e) + '\nMost likely the input dictionary does not exist.' raise e except Exception as e: traceback.print_exc() print str(e) raise e
def get_display(my): import common_tools.utils as ctu from common_tools.copy_url_button import CopyUrlButton my.sk = str(my.kwargs.get('sk')) my.sid = str(my.kwargs.get('search_id')) allowed_search_titles = '' if 'user' in my.kwargs.keys(): my.user = my.kwargs.get('user') else: my.user = Environment.get_user_name() if 'groups_str' in my.kwargs.keys(): my.groups_str = my.kwargs.get('groups_str') if my.groups_str in [None,'']: user_group_names = Environment.get_group_names() for mg in user_group_names: if my.groups_str == '': my.groups_str = mg else: my.groups_str = '%s,%s' % (my.groups_str, mg) user_is_scheduler = False if 'scheduling' in my.groups_str or 'onboarding' in my.groups_str: user_is_scheduler = True if 'display_mode' in my.kwargs.keys(): my.disp_mode = my.kwargs.get('display_mode') if my.disp_mode == 'Small': my.small = True my.code = my.sk.split('code=')[1] if 'allowed_titles' in my.kwargs.keys(): my.allowed_titles_str = str(my.kwargs.get('allowed_titles')) split_allow = my.allowed_titles_str.split('|') for sa in split_allow: if allowed_search_titles == '': allowed_search_titles = "('%s'" % sa else: allowed_search_titles = "%s,'%s'" % (allowed_search_titles, sa) if allowed_search_titles != '': allowed_search_titles = '%s)' % allowed_search_titles if my.allowed_titles_str == '': my.allowed_titles_str = 'NOTHING|NOTHING' main_search = Search("twog/order") main_search.add_filter('code', my.code) main_obj = main_search.get_sobject() if 'is_master' in my.kwargs.keys(): my.is_master_str = my.kwargs.get('is_master') if my.is_master_str == 'true': my.is_master = True else: if main_obj.get_value('classification') in ['master', 'Master']: my.is_master = True my.is_master_str = 'true' sched_full_name = '' if main_obj.get_value('login') not in [None,'']: sched_s = Search('sthpw/login') sched_s.add_filter('location', 'internal') sched_s.add_filter('login', main_obj.get_value('login')) sched = sched_s.get_sobject() if sched: sched_full_name = '%s %s' % (sched.get_value('first_name'), sched.get_value('last_name')) sales_full_name = '' if main_obj.get_value('sales_rep') not in [None,'']: sales_s = Search('sthpw/login') sales_s.add_filter('location', 'internal') sales_s.add_filter('login', main_obj.get_value('sales_rep')) sales = sales_s.get_sobject() if sales: sales_full_name = '%s %s' % (sales.get_value('first_name'), sales.get_value('last_name')) title_search = Search("twog/title") title_search.add_filter('order_code', main_obj.get_value('code')) if allowed_search_titles != '': title_search.add_where("\"code\" in %s" % allowed_search_titles) titles = title_search.get_sobjects() table = Table() table.add_attr('I_AM', 'ORDER TABLE') if user_is_scheduler: table.add_attr('SOY', 'ORDER-O TABLE-O') table.add_attr('cellpadding', '0') table.add_attr('cellspacing', '0') table.add_style('border-collapse', 'separate') table.add_style('border-spacing', '25px 0px') table.add_style('color: #00033a;') table.add_style('background-color: #d9edf7;') table.add_style('width: 100%;') table.add_style('border-bottom-right-radius', '10px') table.add_style('border-bottom-left-radius', '10px') table.add_style('border-top-right-radius', '10px') table.add_style('border-top-left-radius', '10px') order_name_row = table.add_row() full_o_name = main_obj.get('name') if main_obj.get('details') not in [None,'']: full_o_name = '%s - %s' % (full_o_name, main_obj.get('details')) order_name_cell = table.add_cell('<b><u>Order: %s</u><b>' % full_o_name) order_name_cell.add_attr('nowrap','nowrap') order_name_cell.add_style('cursor: pointer;') order_name_cell.add_behavior(get_panel_change_behavior('twog/order', my.code, my.sk, my.sk, my.title, '', 'builder/refresh_from_save', '', my.sk, main_obj.get_value('name'), user_is_scheduler)) order_due_cell = table.add_cell("Due: %s" % fix_date(main_obj.get_value('due_date')).split(' ')[0]) order_due_cell.add_attr('nowrap', 'nowrap') long_cell1 = table.add_cell('Scheduler: %s' % sched_full_name) long_cell1.add_style('width: 100%') order_sales_row = table.add_row() order_po_cell = table.add_cell("Code: %s PO Number: %s" % (my.code, main_obj.get_value('po_number'))) order_po_cell.add_attr('nowrap', 'nowrap') order_sales_cell = table.add_cell('Sales Rep: %s' % sales_full_name) order_sales_cell.add_attr('nowrap', 'nowrap') bottom_buttons = Table() bottom_buttons.add_row() order_builder_url = ctu.get_order_builder_url(my.code) copy_url_button = CopyUrlButton(title='Copy URL to Clipboard', url=order_builder_url) copy_url_cell = bottom_buttons.add_cell(copy_url_button) copy_url_cell.add_attr('align', 'right') instructions_button = FullInstructionsLauncherWdg(title='View Instructions', search_key=my.sk) instructions_cell = bottom_buttons.add_cell(instructions_button) instructions_cell.add_attr('align', 'right') if user_is_scheduler: tcloner = ButtonSmallNewWdg(title="Title Cloner", icon=CustomIconWdg.icons.get('STAR')) tcloner.add_behavior(get_launch_title_cloner_behavior(my.sk, main_obj.get_value('name'), my.user)) dcl = bottom_buttons.add_cell(tcloner) dcl.add_attr('align', 'right') tchanger = ButtonSmallNewWdg(title="Title Changer", icon=CustomIconWdg.icons.get('CALENDAR')) tchanger.add_behavior(get_launch_title_changer_behavior(my.sk, main_obj.get_value('name'), my.user)) dcal = bottom_buttons.add_cell(tchanger) dcal.add_attr('align', 'right') tdeletor = ButtonSmallNewWdg(title="Title Deletor", icon=CustomIconWdg.icons.get('TABLE_ROW_DELETE')) tdeletor.add_behavior(get_launch_title_deletor_behavior(my.sk, main_obj.get_value('name'), my.user)) dfilt = bottom_buttons.add_cell(tdeletor) dfilt.add_attr('align', 'right') tfilter = ButtonSmallNewWdg(title="Filter Titles", icon=CustomIconWdg.icons.get('CONTENTS')) tfilter.add_behavior(get_launch_title_filter_behavior(my.sk, main_obj.get_value('name'), my.user)) filt = bottom_buttons.add_cell(tfilter) filt.add_attr('align', 'right') upload = ButtonSmallNewWdg(title="Upload", icon=CustomIconWdg.icons.get('PUBLISH')) upload.add_behavior(get_upload_behavior(my.sk)) up = bottom_buttons.add_cell(upload) up.add_attr('align', 'right') note_adder = ButtonSmallNewWdg(title="Add Note", icon=CustomIconWdg.icons.get('NOTE_ADD')) note_adder.add_behavior(get_launch_note_behavior(my.sk, main_obj.get_value('name'))) nadd = bottom_buttons.add_cell(note_adder) nadd.add_attr('align', 'right') nadd.add_style('cursor: pointer;') if user_is_scheduler or 'onboarding' in my.groups_str: title_adder = ButtonSmallNewWdg(title="Add Titles", icon=CustomIconWdg.icons.get('INSERT_MULTI')) title_adder.add_behavior(get_title_add_behavior(my.sk, my.sid, main_obj.get_value('client_code'), main_obj.get_value('name'))) tadd = bottom_buttons.add_cell(title_adder) tadd.add_attr('align', 'right') tadd.add_style('cursor: pointer;') long_cell2 = table.add_cell(bottom_buttons) long_cell2.add_attr('align', 'right') long_cell2.add_attr('valign', 'bottom') long_cell2.add_style('width: 100%') bottom = Table() bottom.add_attr('width', '100%') bottom.add_attr('cellpadding', '0') bottom.add_attr('cellspacing', '0') for title in titles: title_sk = title.get_search_key() title_row = bottom.add_row() title_row.add_attr('width', '100%') title_row.add_attr('class', 'row_%s' % title_sk) title_obj = TitleRow(sk=title_sk, parent_sk=my.sk, parent_sid=my.sid, groups_str=my.groups_str, user=my.user, display_mode=my.disp_mode, is_master=my.is_master_str, main_obj=title) content_cell = bottom.add_cell(title_obj) content_cell.add_attr('width', '100%') content_cell.add_attr('sk', title_sk) content_cell.add_attr('order_sk', my.sk) content_cell.add_attr('parent_sk', my.sk) content_cell.add_attr('parent_sid', my.sid) content_cell.add_attr('call_me', title.get_value('title')) content_cell.add_attr('episode', title.get_value('episode')) content_cell.add_attr('my_class', 'TitleRow') content_cell.add_attr('client_code', title.get_value('client_code')) content_cell.add_attr('class', 'cell_%s' % title_sk) tab2ret = Table() tab2ret.add_attr('width', '100%') tab2ret.add_row() tab2ret.add_cell(table) tab2ret.add_row() bot = tab2ret.add_cell(bottom) bot.add_style('padding-left: 40px;') return tab2ret