def get_display(self): last_week = 52 if self.kwargs.get('show_future') == 'false': today = Date() last_week = int(today.get_week()) weeks = [i for i in xrange(1, last_week + 1)] weeks.reverse() self.set_option('values', weeks) return super(WeekSelectWdg, self).get_display()
def get_display(my): last_week = 52 if my.kwargs.get('show_future') == 'false': today = Date() last_week = int(today.get_week()) weeks = [i for i in xrange(1, last_week + 1)] weeks.reverse() my.set_option('values', weeks) return super(WeekSelectWdg, my).get_display()
def get_display(my): filter_data = FilterData.get_from_cgi() values = filter_data.get_values("custom", "year") year = 0 for value in values: if value: try: year = int(value) except: pass if not year: date = Date() year = int(date.get_year()) sobject = my.get_current_sobject() id = sobject.get_id() column = my.get_option("column") month = int( my.get_option('month') ) end_year = year end_month = month + 1 if end_month > 12: end_month = 1 end_year += 1 search_type = 'MMS/personal_time_log' if year: search = Search(search_type) search.add_filter('login_id', id) search.add_filter('work_performed_date', '%s-%0.2d-01' % (year,month), '>') search.add_filter('work_performed_date', '%s-%0.2d-01' % (end_year,end_month), '<') sobjects = search.get_sobjects() else: sobjects = [] if sobjects: parser = ExpressionParser() sum = parser.eval("@SUM(%s.%s)" % (search_type,column),sobjects=sobjects) else: sum = 0 div = DivWdg() div.add(sum) return div
def get_display(self): filter_data = FilterData.get_from_cgi() values = filter_data.get_values("custom", "year") year = 0 for value in values: if value: try: year = int(value) except: pass if not year: date = Date() year = int(date.get_year()) sobject = self.get_current_sobject() id = sobject.get_id() column = self.get_option("column") month = int(self.get_option('month')) end_year = year end_month = month + 1 if end_month > 12: end_month = 1 end_year += 1 search_type = 'MMS/personal_time_log' if year: search = Search(search_type) search.add_filter('login_id', id) search.add_filter('work_performed_date', '%s-%0.2d-01' % (year, month), '>') search.add_filter('work_performed_date', '%s-%0.2d-01' % (end_year, end_month), '<') sobjects = search.get_sobjects() else: sobjects = [] if sobjects: parser = ExpressionParser() sum = parser.eval("@SUM(%s.%s)" % (search_type, column), sobjects=sobjects) else: sum = 0 div = DivWdg() div.add(sum) return div
def get_display(self): today = Date() cur_year = int(today.get_year()) limit = self.get_option('limit') if limit: limit = int(limit) else: limit = 10 years = [i for i in xrange(cur_year - limit + 1, cur_year + 1)] years.reverse() self.set_option('values', years) return super(YearSelectWdg, self).get_display()
def get_display(my): today = Date() cur_year = int(today.get_year()) limit = my.get_option('limit') if limit: limit = int(limit) else: limit = 10 years = [i for i in xrange(cur_year-limit + 1, cur_year + 1)] years.reverse() my.set_option('values', years) return super(YearSelectWdg, my).get_display()
def get_display(my): value = my.get_value() name = my.get_name() type = my.get_option("type") if not type: type = my.get_type() # FIXME: this needs to be handled outside of this class to centralize # the type of an element!!! if type in ["timestamp"]: # make a guess here if name.endswith('time'): type = 'time' elif name.endswith('date'): type = 'date' if type == "text": wiki = WikiUtil() display = wiki.convert(value) elif type in ["time"]: if value: display = Date(value).get_display_time() else: display = '' elif type in ["datetime"]: if value: display = Date(value).get_display_datetime() else: display = '' elif type in ["timestamp", 'date']: if value == '{now}': display = Date() elif value: display = Date(value).get_display_date() else: display = '' elif type == "timecode": display = "00:00:00:00" elif type == "currency": display = "$%s" % value elif type == "color": display = DivWdg() color = DivWdg(" ") color.add_style("height: 15px") color.add_style("width: 15px") color.add_style("float: left") color.add_style("margin: 0 5px 0 5px") color.add_style("background: %s" % value) display.add(color) display.add(value) display.add_style("width: 100%") display.add_style("height: 100%") elif type == "boolean": display = DivWdg() display.add_style("text-align: center") display.add_style("width: 100%") display.add_style("height: 100%") if value == True: from pyasm.widget import IconWdg icon = IconWdg("True", IconWdg.CHECK) display.add(icon) elif value == False: from pyasm.widget import IconWdg icon = IconWdg("False", IconWdg.INVALID) display.add(icon) else: display.add(" ") else: if not isinstance(value, basestring): display = DivWdg() display.add_style("float: right") display.add_style("padding-right: 3px") display.add(str(value)) else: display = value return display
def add_initial_tasks(sobject, pipeline_code=None, processes=[], contexts=[], skip_duplicate=True, mode='standard',start_offset=0): '''add initial tasks based on the pipeline of the sobject''' from pipeline import Pipeline def _get_context(existing_task_dict, process_name, context=None): existed = False if not existing_task_dict: if context: context = context else: context = process_name else: compare_key = "%s:%s" %(process_name, context) max_num = 0 for item in existing_task_dict.keys(): item_stripped = re.sub('/\d+$', '', item) #if item.startswith(compare_key): if item_stripped == compare_key: existing_context = item.replace('%s:'%process_name,'') suffix = existing_context.split('/')[-1] try: num = int(suffix) except: num = 0 if num > max_num: max_num = num existed = True if existed: context = "%s/%0.3d" % (context, max_num+1) return context # get pipeline if not pipeline_code: pipeline_code = sobject.get_value("pipeline_code") if pipeline_code in ['', '__default__']: pipeline = SearchType.create("sthpw/pipeline") pipeline.set_value("code", "__default__") pipeline.set_value("pipeline", ''' <pipeline> <process name='publish'/> </pipeline> ''') # FIXME: HACK to initialize virtual pipeline pipeline.set_pipeline(pipeline.get_value("pipeline")) else: pipeline = Pipeline.get_by_code(pipeline_code) if not pipeline: print "WARNING: pipeline '%s' does not exist" % pipeline_code return [] #TODO: add recursive property here if processes: process_names = processes else: process_names = pipeline.get_process_names(recurse=True) # remember which ones already exist existing_tasks = Task.get_by_sobject(sobject, order=False) existing_task_dict = {} for x in existing_tasks: key1 = '%s:%s' %(x.get_value('process'),x.get_value("context")) existing_task_dict[key1] = True # for backward compatibility, if the process has been created, we will skip later below # we may remove this in the future #key2 = '%s' %(x.get_value('process')) #existing_task_dict[key2] = True # create all of the tasks description = "" tasks = [] start_date = Date() start_date.add_days(start_offset) bid_duration_unit = ProdSetting.get_value_by_key("bid_duration_unit") if not bid_duration_unit: bid_duration_unit = 'hour' # that's the date range in 5 days (not hours) default_duration = 5 default_bid_duration = 8 if bid_duration_unit == 'minute': default_bid_duration = 60 last_task = None # this is the explicit mode for creating task for a specific process:context combo if mode=='context': for context_combo in contexts: process_name, context = context_combo.split(':') # depend_id is None since these are arbitrary tasks depend_id = None # first check if it already exists when skip_duplicate is True key1 = '%s:%s' %(process_name, context) task_existed = False for item in existing_task_dict: if item.startswith(key1): task_existed = True break if skip_duplicate and task_existed: continue process_obj = pipeline.get_process(process_name) if not process_obj: continue context=_get_context(existing_task_dict,process_name, context) pipe_code = process_obj.get_task_pipeline() attrs = process_obj.get_attributes() duration = attrs.get("duration") if duration: duration = int(duration) else: duration = default_duration bid_duration = attrs.get("bid_duration") if not bid_duration: bid_duration = default_bid_duration else: bid_duration = int(bid_duration) end_date = start_date.copy() # for a task to be x days long, we need duration x-1. end_date.add_days(duration-1) start_date_str = start_date.get_db_date() end_date_str = end_date.get_db_date() # Create the task last_task = Task.create(sobject, process_name, description, depend_id=depend_id, pipeline_code=pipe_code, start_date=start_date_str, end_date=end_date_str, context=context, bid_duration=bid_duration) # this avoids duplicated tasks for process connecting to multiple processes new_key = '%s:%s' %(last_task.get_value('process'), last_task.get_value("context") ) existing_task_dict[new_key] = True # for backward compatibility, if the process has been created, we will skip later below tasks.append(last_task) start_date = end_date.copy() # start the day after start_date.add_days(1) return tasks for process_name in process_names: if last_task: depend_id = last_task.get_id() else: depend_id = None process_obj = pipeline.get_process(process_name) if not process_obj: continue attrs = process_obj.get_attributes() duration = attrs.get("duration") if duration: duration = int(duration) else: duration = default_duration bid_duration = attrs.get("bid_duration") if not bid_duration: bid_duration = default_bid_duration else: bid_duration = int(bid_duration) end_date = start_date.copy() if duration >= 1: # for a task to be x days long, we need duration x-1. end_date.add_days(duration-1) # output contexts could be duplicated from 2 different outout processes if mode == 'simple process': output_contexts = [process_name] else: output_contexts = pipeline.get_output_contexts(process_obj.get_name(), show_process=False) pipe_code = process_obj.get_task_pipeline() start_date_str = start_date.get_db_date() end_date_str = end_date.get_db_date() for context in output_contexts: # first check if it already exists when skip_duplicate is True key1 = '%s:%s' %(process_name, context) task_existed = False for item in existing_task_dict: if item.startswith(key1): task_existed = True break if skip_duplicate and task_existed: continue if contexts and context not in contexts: continue context = _get_context(existing_task_dict, process_name, context) last_task = Task.create(sobject, process_name, description, depend_id=depend_id, pipeline_code=pipe_code, start_date=start_date_str, end_date=end_date_str, context=context, bid_duration=bid_duration) # this avoids duplicated tasks for process connecting to multiple processes new_key = '%s:%s' %(last_task.get_value('process'), last_task.get_value("context") ) existing_task_dict[new_key] = True # for backward compatibility, if the process has been created, we will skip later below tasks.append(last_task) start_date = end_date.copy() # start the day after start_date.add_days(1) return tasks
def get_message(my): search_type_obj = my.parent.get_search_type_obj() title = search_type_obj.get_title() subject = my.get_subject() notification_message = my.notification.get_value("message") message = "%s %s Note Entry" % (title, my.parent.get_name()) if notification_message: message = "%s (%s)" %(message, notification_message) submit_desc = '' from pyasm.prod.biz import Submission if isinstance(my.parent, Submission): update_info = [''] # add more info about the file and bin snapshot = Snapshot.get_latest_by_sobject(my.parent, "publish") xpath = "snapshot/file[@type='main']" xml = snapshot.get_xml_value('snapshot') file = None if xml.get_node(xpath) is not None: file = my._get_file_obj(snapshot) else: snapshots = snapshot.get_all_ref_snapshots() snapshot_file_objects = [] if snapshots: snapshot = snapshots[0] file = my._get_file_obj(snapshot, type=None) if file: file_name = file.get_file_name() web_path = file.get_web_path() from pyasm.web import WebContainer host = WebContainer.get_web().get_base_url() update_info.append('Browse: %s %s%s' %( file_name, host.to_string(), web_path)) bins = my.parent.get_bins() bin_labels = [ bin.get_label() for bin in bins] update_info.append('Bin: %s' %', '.join(bin_labels)) update_info.append('Artist: %s' %my.parent.get_value('artist')) update_info.append('Description: %s' %my.parent.get_value('description')) # get notes search = Note.get_search_by_sobjects([my.parent]) if search: search.add_order_by("context") search.add_order_by("timestamp desc") notes = search.get_sobjects() last_context = None note_list = [] for i, note in enumerate(notes): context = note.get_value('context') # explicit compare to None if last_context == None or context != last_context: note_list.append( "[ %s ] " % context ) last_context = context #child_notes = my.notes_dict.get(note.get_id()) # draw note item date = Date(db=note.get_value('timestamp')) note_list.append('(%s) %s'%(date.get_display_time(), note.get_value("note"))) update_info.append('Notes: \n %s' % '\n'.join(note_list)) submit_desc = '\n'.join(update_info) update_desc = my.sobject.get_update_description() command_desc = my.command.get_description() message = '%s\n\nReport from transaction:\n%s\n\n%s\n%s' \ % (message, update_desc, command_desc, submit_desc) return message
def run(my): import time time.sleep(6) #print "Starting Timed Trigger" # checks are done every 60 seconds chunk = 60 # FIXME: not sure why we have to do a batch here from pyasm.security import Batch Batch(login_code="admin") # get the all of the timed triggers #search = Search("sthpw/timed_trigger") #search.add_filter("type", "timed") search = Search("sthpw/trigger") search.add_filter("event", "timed") timed_trigger_sobjs = search.get_sobjects() timed_triggers = [] for trigger_sobj in timed_trigger_sobjs: trigger_class = trigger_sobj.get_value("class_name") try: timed_trigger = Common.create_from_class_path(trigger_class) except ImportError: raise Exception("WARNING: [%s] does not exist" % trigger_class) timed_triggers.append(timed_trigger) while 1: time.sleep(chunk) #print "Running timer" date = Date() #print "utc: ", date.get_display_time() # go through each trigger for timed_trigger in timed_triggers: print timed_trigger if not timed_trigger.is_ready(): print "... not ready" continue if timed_trigger.is_in_separate_thread(): class xxx(threading.Thread): def run(my): try: Batch() timed_trigger._do_execute() finally: DbContainer.close_thread_sql() xxx().start() else: timed_trigger._do_execute() DbContainer.close_thread_sql() if my.end: print "Stopping timed thread" break
def update_dependent_tasks(my, top=True): '''for purposes of dependent tasks''' if top: Task.tasks_updated = [] Task.tasks_updated.append(my.get_id()) # get the dependent tasks tasks = my.get_dependent_tasks() bid_start_date = my.get_value("bid_start_date") bid_end_date = my.get_value("bid_end_date") bid_duration_unit = ProdSetting.get_value_by_key("bid_duration_unit") if not bid_duration_unit: bid_duration_unit = 'hour' # if there is no end date specified, return if not bid_end_date: bid_duration = my.get_value("bid_duration") if bid_duration and bid_start_date: date = Date(db=bid_start_date) bid_duration = float(bid_duration) if bid_duration_unit == 'minute': date.add_minutes(bid_duration) else: date.add_hours(bid_duration) bid_end_date = date.get_db_time() else: return for task in tasks: # prevent circular dependency if for some reason they occur. if task.get_id() in Task.tasks_updated: Environment.add_warning("Circular dependency", "Circular dependency with task '%s'" % task.get_id() ) continue Task.tasks_updated.append(my.get_id()) # if the dependency is fixed, update the d #mode = task.get_value("mode") mode = "depend" # put the start date as the end date if mode == "depend": # add one day to the end date to get the start date date = Date(db=bid_end_date) date.add_days(1) bid_start_date = date.get_db_time() task.set_value("bid_start_date", bid_start_date ) # check if there is a duration in hours to this date bid_duration = task.get_value("bid_duration") if bid_duration: bid_duration = int(bid_duration) date = Date(db=bid_start_date) if bid_duration_unit == 'minute': date.add_minutes(bid_duration) else: date.add_hours(bid_duration) bid_end_date = date.get_db_time() task.set_value("bid_end_date", bid_end_date) task.commit() task.update_dependent_tasks(False)
def get_display(self): web = WebContainer.get_web() widget = Widget() if not self.search_type: self.search_type = self.options.get("search_type") assert self.search_type sobject_filter = self.sobject_filter web_state = WebState.get() web_state.add_state("ref_search_type", self.search_type) div = FilterboxWdg() widget.add(div) # add the sobject filter if self.sobject_filter: div.add(self.sobject_filter) # add a milestone filter milestone_filter = FilterSelectWdg("milestone_filter", label="Milestone: ") milestones = Search("sthpw/milestone").get_sobjects() milestone_filter.set_sobjects_for_options(milestones, "code", "code") milestone_filter.add_empty_option(label='-- Any Milestones --') milestone_filter.set_submit_onchange(False) milestone = milestone_filter.get_value() div.add_advanced_filter(milestone_filter) # add a process filter process_filter = ProcessFilterSelectWdg(name=self.process_filter_name, label='Process: ') process_filter.set_search_type(self.search_type) process_filter.set_submit_onchange(False) div.add_advanced_filter(process_filter) user_filter = None user = Environment.get_user_name() # it has a special colunn 'assigned' if not UserFilterWdg.has_restriction(): user_filter = UserFilterWdg() user_filter.set_search_column('assigned') user = user_filter.get_value() div.add_advanced_filter(user_filter) # add a task properties search search_columns = ['status', 'description'] task_search_filter = SearchFilterWdg(name='task_prop_search', \ columns=search_columns, label='Task Search: ') div.add_advanced_filter(task_search_filter) # add a retired filter retired_filter = RetiredFilterWdg() div.add_advanced_filter(retired_filter) # set a limit to only see set amount of sobjects at a time search_limit = SearchLimitWdg() search_limit.set_limit(50) search_limit.set_style(SearchLimitWdg.LESS_DETAIL) div.add_bottom(search_limit) div.add_advanced_filter(HtmlElement.br(2)) start_date_wdg = CalendarInputWdg("start_date_filter", label="From: ", css='med') start_date_wdg.set_persist_on_submit() div.add_advanced_filter(start_date_wdg) start_date = start_date_wdg.get_value() # these dates are actually used for search filtering processed_start_date = None processed_end_date = None if start_date: date = Date(db_date=start_date) # this guarantees a valid date( today ) is invalid input is detected processed_start_date = date.get_db_date() if start_date != processed_start_date: start_date_wdg.set_value(self.INVALID) # add hints hint = HintWdg("The 'From' and 'To' dates apply to bid dates.") #span.add(hint) end_date_wdg = CalendarInputWdg("end_date_filter", label="To: ", css='med') end_date_wdg.set_persist_on_submit() div.add_advanced_filter(end_date_wdg) div.add_advanced_filter(hint) end_date = end_date_wdg.get_value() if end_date: date = Date(db_date=end_date) processed_end_date = date.get_db_date() if end_date != processed_end_date: end_date_wdg.set_value(self.INVALID) # show sub task checkbox sub_task_cb = FilterCheckboxWdg('show_sub_tasks', label='show sub tasks', css='med') div.add_advanced_filter(sub_task_cb) div.add_advanced_filter(HtmlElement.br(2)) task_filter = TaskStatusFilterWdg() div.add_advanced_filter(task_filter) shot_filter = None if self.search_type == 'prod/shot': shot_filter = SObjectStatusFilterWdg() div.add_advanced_filter(shot_filter) # add refresh icon ''' refresh = IconRefreshWdg(long=False) calendar_div.add(refresh) calendar_div.add(SpanWdg(' ', css='small')) ''' # get all of the assets search = Search(self.search_type) if sobject_filter: sobject_filter.alter_search(search) if shot_filter: shot_statuses = shot_filter.get_statuses() shot_statuses_selected = shot_filter.get_values() if shot_statuses != shot_statuses_selected: search.add_filters("status", shot_filter.get_values()) assets = search.get_sobjects() if not assets: # drawing the empty table prevents the loss of some prefs data table = TableWdg("sthpw/task", self.task_view) #widget.add(HtmlElement.h3("No assets found")) widget.add(table) return widget # this assumes looking at one project only project_search_type = assets[0].get_search_type() ids = SObject.get_values(assets, 'id') # get all of the tasks search = Search("sthpw/task") if processed_start_date and start_date_wdg.get_value( True) != self.INVALID: search.add_where("(bid_start_date >= '%s' or actual_start_date >='%s')" \ % (processed_start_date, processed_start_date)) if processed_end_date and end_date_wdg.get_value(True) != self.INVALID: search.add_where("(bid_end_date <= '%s' or actual_end_date <='%s')" \ % (processed_end_date, processed_end_date)) # filter out sub pipeline tasks if not sub_task_cb.is_checked(): search.add_regex_filter('process', '/', op='NEQ') search.add_filter("search_type", project_search_type) search.add_filters("search_id", ids) # order by the search ids of the asset as the were defined in the # previous search search.add_enum_order_by("search_id", ids) if user != "": search.add_filter("assigned", user) if milestone != "": search.add_filter("milestone_code", milestone) process_filter.alter_search(search) task_search_filter.alter_search(search) if not self.show_all_task_approvals: #task_filter = TaskStatusFilterWdg(task_pipeline="task") #widget.add(task_filter) task_statuses = task_filter.get_processes() task_statuses_selected = task_filter.get_values() # one way to show tasks with obsolete statuses when the user # check all the task status checkboxes if task_statuses != task_statuses_selected: search.add_filters("status", task_filter.get_values()) # filter for retired ... # NOTE: this must be above the search limit filter # because it uses a get count which commits the retired flag if retired_filter.get_value() == 'true': search.set_show_retired(True) # alter_search() will run set_search() implicitly search_limit.alter_search(search) # define the table table = TableWdg("sthpw/task", self.task_view) # get all of the tasks tasks = search.get_sobjects() sorted_tasks = self.process_tasks(tasks, search) widget.add(HtmlElement.br()) table.set_sobjects(sorted_tasks) # make some adjustments to the calendar widget calendar_wdg = table.get_widget("schedule") for name, value in self.calendar_options.items(): calendar_wdg.set_option(name, value) widget.add(table) return widget
def get_message(my): search_type_obj = my.parent.get_search_type_obj() title = search_type_obj.get_title() subject = my.get_subject() notification_message = my.notification.get_value("message") message = "%s %s Note Entry" % (title, my.parent.get_name()) if notification_message: message = "%s (%s)" % (message, notification_message) submit_desc = '' from pyasm.prod.biz import Submission if isinstance(my.parent, Submission): update_info = [''] # add more info about the file and bin snapshot = Snapshot.get_latest_by_sobject(my.parent, "publish") xpath = "snapshot/file[@type='main']" xml = snapshot.get_xml_value('snapshot') file = None if xml.get_node(xpath) is not None: file = my._get_file_obj(snapshot) else: snapshots = snapshot.get_all_ref_snapshots() snapshot_file_objects = [] if snapshots: snapshot = snapshots[0] file = my._get_file_obj(snapshot, type=None) if file: file_name = file.get_file_name() web_path = file.get_web_path() from pyasm.web import WebContainer host = WebContainer.get_web().get_base_url() update_info.append('Browse: %s %s%s' % (file_name, host.to_string(), web_path)) bins = my.parent.get_bins() bin_labels = [bin.get_label() for bin in bins] update_info.append('Bin: %s' % ', '.join(bin_labels)) update_info.append('Artist: %s' % my.parent.get_value('artist')) update_info.append('Description: %s' % my.parent.get_value('description')) # get notes search = Note.get_search_by_sobjects([my.parent]) if search: search.add_order_by("context") search.add_order_by("timestamp desc") notes = search.get_sobjects() last_context = None note_list = [] for i, note in enumerate(notes): context = note.get_value('context') # explicit compare to None if last_context == None or context != last_context: note_list.append("[ %s ] " % context) last_context = context #child_notes = my.notes_dict.get(note.get_id()) # draw note item date = Date(db=note.get_value('timestamp')) note_list.append( '(%s) %s' % (date.get_display_time(), note.get_value("note"))) update_info.append('Notes: \n %s' % '\n'.join(note_list)) submit_desc = '\n'.join(update_info) update_desc = my.sobject.get_update_description() command_desc = my.command.get_description() message = '%s\n\nReport from transaction:\n%s\n\n%s\n%s' \ % (message, update_desc, command_desc, submit_desc) return message
def get_display(self): web = WebContainer.get_web() widget = Widget() if not self.search_type: self.search_type = self.options.get("search_type") assert self.search_type sobject_filter = self.sobject_filter web_state = WebState.get() web_state.add_state("ref_search_type", self.search_type) div = FilterboxWdg() widget.add(div) # add the sobject filter if self.sobject_filter: div.add(self.sobject_filter) # add a milestone filter milestone_filter = FilterSelectWdg("milestone_filter", label="Milestone: ") milestones = Search("sthpw/milestone").get_sobjects() milestone_filter.set_sobjects_for_options(milestones, "code", "code") milestone_filter.add_empty_option(label='-- Any Milestones --') milestone_filter.set_submit_onchange(False) milestone = milestone_filter.get_value() div.add_advanced_filter(milestone_filter) # add a process filter process_filter = ProcessFilterSelectWdg(name=self.process_filter_name, label='Process: ') process_filter.set_search_type(self.search_type) process_filter.set_submit_onchange(False) div.add_advanced_filter(process_filter) user_filter = None user = Environment.get_user_name() # it has a special colunn 'assigned' if not UserFilterWdg.has_restriction(): user_filter = UserFilterWdg() user_filter.set_search_column('assigned') user = user_filter.get_value() div.add_advanced_filter(user_filter) # add a task properties search search_columns = ['status', 'description'] task_search_filter = SearchFilterWdg(name='task_prop_search', \ columns=search_columns, label='Task Search: ') div.add_advanced_filter(task_search_filter) # add a retired filter retired_filter = RetiredFilterWdg() div.add_advanced_filter(retired_filter) # set a limit to only see set amount of sobjects at a time search_limit = SearchLimitWdg() search_limit.set_limit(50) search_limit.set_style(SearchLimitWdg.LESS_DETAIL) div.add_bottom(search_limit) div.add_advanced_filter(HtmlElement.br(2)) start_date_wdg = CalendarInputWdg("start_date_filter", label="From: ", css='med') start_date_wdg.set_persist_on_submit() div.add_advanced_filter(start_date_wdg) start_date = start_date_wdg.get_value() # these dates are actually used for search filtering processed_start_date = None processed_end_date = None if start_date: date = Date(db_date=start_date) # this guarantees a valid date( today ) is invalid input is detected processed_start_date = date.get_db_date() if start_date != processed_start_date: start_date_wdg.set_value(self.INVALID) # add hints hint = HintWdg("The 'From' and 'To' dates apply to bid dates.") #span.add(hint) end_date_wdg = CalendarInputWdg("end_date_filter", label="To: ", css='med') end_date_wdg.set_persist_on_submit() div.add_advanced_filter(end_date_wdg) div.add_advanced_filter(hint) end_date = end_date_wdg.get_value() if end_date: date = Date(db_date=end_date) processed_end_date = date.get_db_date() if end_date != processed_end_date: end_date_wdg.set_value(self.INVALID) # show sub task checkbox sub_task_cb = FilterCheckboxWdg('show_sub_tasks', label='show sub tasks', css='med') div.add_advanced_filter(sub_task_cb) div.add_advanced_filter(HtmlElement.br(2)) task_filter = TaskStatusFilterWdg() div.add_advanced_filter(task_filter) shot_filter = None if self.search_type == 'prod/shot': shot_filter = SObjectStatusFilterWdg() div.add_advanced_filter(shot_filter) # add refresh icon ''' refresh = IconRefreshWdg(long=False) calendar_div.add(refresh) calendar_div.add(SpanWdg(' ', css='small')) ''' # get all of the assets search = Search(self.search_type) if sobject_filter: sobject_filter.alter_search(search) if shot_filter: shot_statuses = shot_filter.get_statuses() shot_statuses_selected = shot_filter.get_values() if shot_statuses != shot_statuses_selected: search.add_filters("status", shot_filter.get_values() ) assets = search.get_sobjects() if not assets: # drawing the empty table prevents the loss of some prefs data table = TableWdg("sthpw/task", self.task_view) #widget.add(HtmlElement.h3("No assets found")) widget.add(table) return widget # this assumes looking at one project only project_search_type = assets[0].get_search_type() ids = SObject.get_values(assets, 'id') # get all of the tasks search = Search("sthpw/task") if processed_start_date and start_date_wdg.get_value(True) != self.INVALID: search.add_where("(bid_start_date >= '%s' or actual_start_date >='%s')" \ % (processed_start_date, processed_start_date)) if processed_end_date and end_date_wdg.get_value(True) != self.INVALID: search.add_where("(bid_end_date <= '%s' or actual_end_date <='%s')" \ % (processed_end_date, processed_end_date)) # filter out sub pipeline tasks if not sub_task_cb.is_checked(): search.add_regex_filter('process', '/', op='NEQ') search.add_filter("search_type", project_search_type) search.add_filters("search_id", ids ) # order by the search ids of the asset as the were defined in the # previous search search.add_enum_order_by("search_id", ids) if user != "": search.add_filter("assigned", user) if milestone != "": search.add_filter("milestone_code", milestone) process_filter.alter_search(search) task_search_filter.alter_search(search) if not self.show_all_task_approvals: #task_filter = TaskStatusFilterWdg(task_pipeline="task") #widget.add(task_filter) task_statuses = task_filter.get_processes() task_statuses_selected = task_filter.get_values() # one way to show tasks with obsolete statuses when the user # check all the task status checkboxes if task_statuses != task_statuses_selected: search.add_filters("status", task_filter.get_values() ) # filter for retired ... # NOTE: this must be above the search limit filter # because it uses a get count which commits the retired flag if retired_filter.get_value() == 'true': search.set_show_retired(True) # alter_search() will run set_search() implicitly search_limit.alter_search(search) # define the table table = TableWdg("sthpw/task", self.task_view) # get all of the tasks tasks = search.get_sobjects() sorted_tasks = self.process_tasks(tasks, search) widget.add( HtmlElement.br() ) table.set_sobjects(sorted_tasks) # make some adjustments to the calendar widget calendar_wdg = table.get_widget("schedule") for name,value in self.calendar_options.items(): calendar_wdg.set_option(name, value) widget.add(table) return widget
def _get_bar(my, percent, proc_count, task): '''get a vertical bar indicating the progress of a task ''' sobject = my.get_current_sobject() bar = DivWdg() if my.desc_checkbox_value == "on": bar.add_style('margin-right: 20px') else: bar.add_style('width: 10px') bar.add_style('float: left') cur_percent = 100.0 increment = 100.0 / proc_count # get some task info assigned = 'unassigned' process = task.get_value('process') if task.get_value('assigned').strip(): assigned = task.get_value('assigned') task_desc = task.get_value('description') if not task_desc: task_desc = 'n/a' start_date = task.get_value("bid_start_date") end_date = task.get_value("bid_end_date") if start_date: start_date = Date(db_date=start_date, show_warning=False).get_display_date() else: start_date = "?" if end_date: end_date = Date(db_date=end_date, show_warning=False).get_display_date() else: end_date = "?" # remove some spacing characters task_desc = re.sub('(\n|\r|\t)', ' ', task_desc) task_desc = re.sub('"', "'", task_desc) task_status = task.get_value('status') display_percent = percent if percent < 0: task_status = "%s <font color=red>(obsolete)</font>" % task_status display_percent = 0 msg = '<b>%s</b><br/><hr>%s<br/><span style=padding-left:1em>desc: %s</span><br/>' \ '<span style=padding-left:1em>status:%s (%s%%)</span><br/>'\ '<span style=padding-left:1em>%s - %s</span>'\ % (process, assigned, task_desc, task_status, display_percent, start_date, end_date) if WebContainer.get_web().get_browser() == "IE": bar.add_event('onmouseover', "hint_bubble.show(event, '%s')" %msg) else: bar.add_tip(msg) from pyasm.widget import IconWdg end_date = task.get_value("bid_end_date") end_date = Date(db_date=end_date, show_warning=False) now_date = Date(show_warning=False) if now_date.get_utc() > end_date.get_utc() and percent != 100: alert_color = "#f00" else: alert_color = None for x in xrange(proc_count): cur_percent -= increment div = DivWdg() content = ' ' # unidentified status probably if percent < 0: content = '—' div.add_style('text-decoration: blink') div.add(content) div.add_style('width: 10px') if cur_percent < percent or cur_percent == 0: if alert_color: div.add_style("background-color: %s" % alert_color) else: div.add_style("background-color: %s" % my._get_color_code(percent)) bar_height = my.get_option("bar_height") if not bar_height: bar_height = my.bar_select_value if not bar_height: bar_height = '3' div.add_style("height: %spx" % bar_height) # IE needs to set the font size to reduce the overall size div.add_style("font-size: %spx" % bar_height ) if sobject.is_retired(): div.add_class('task_status_bar_retired') else: if my.label_select_value == "abbr": div.add_style("margin: -1px") #div.add_class("task_status_bar") #div.add_style("margin-top: 2px") div.add_border() bar.add(div) if my.desc_checkbox_value == "on": span = SpanWdg(task_desc) span.add_style('font-size: 0.8em') bar.add( span ) return bar
def add_initial_tasks(sobject, pipeline_code=None, processes=[], contexts=[], skip_duplicate=True, mode='standard',start_offset=0): '''add initial tasks based on the pipeline of the sobject''' from pipeline import Pipeline def _get_context(existing_task_dict, process_name, context=None): existed = False if not existing_task_dict: if context: context = context else: context = process_name else: compare_key = "%s:%s" %(process_name, context) max_num = 0 for item in existing_task_dict.keys(): item_stripped = re.sub('/\d+$', '', item) #if item.startswith(compare_key): if item_stripped == compare_key: existing_context = item.replace('%s:'%process_name,'') suffix = existing_context.split('/')[-1] try: num = int(suffix) except: num = 0 if num > max_num: max_num = num existed = True if existed: context = "%s/%0.3d" % (context, max_num+1) return context # get pipeline if not pipeline_code: pipeline_code = sobject.get_value("pipeline_code") if pipeline_code in ['', '__default__']: pipeline = SearchType.create("sthpw/pipeline") pipeline.set_value("code", "__default__") pipeline.set_value("pipeline", ''' <pipeline> <process name='publish'/> </pipeline> ''') # FIXME: HACK to initialize virtual pipeline pipeline.set_pipeline(pipeline.get_value("pipeline")) else: pipeline = Pipeline.get_by_code(pipeline_code) if not pipeline: print "WARNING: pipeline '%s' does not exist" % pipeline_code return [] #TODO: add recursive property here if processes: process_names = processes else: process_names = pipeline.get_process_names(recurse=True, type=["node","approval"]) # remember which ones already exist existing_tasks = Task.get_by_sobject(sobject, order=False) existing_task_dict = {} for x in existing_tasks: key1 = '%s:%s' %(x.get_value('process'),x.get_value("context")) existing_task_dict[key1] = True # for backward compatibility, if the process has been created, we will skip later below # we may remove this in the future #key2 = '%s' %(x.get_value('process')) #existing_task_dict[key2] = True # create all of the tasks description = "" tasks = [] start_date = Date() start_date.add_days(start_offset) bid_duration_unit = ProdSetting.get_value_by_key("bid_duration_unit") if not bid_duration_unit: bid_duration_unit = 'hour' # that's the date range in 5 days (not hours) default_duration = 5 default_bid_duration = 8 if bid_duration_unit == 'minute': default_bid_duration = 60 last_task = None # this is the explicit mode for creating task for a specific process:context combo if mode=='context': for context_combo in contexts: process_name, context = context_combo.split(':') # depend_id is None since these are arbitrary tasks depend_id = None # first check if it already exists when skip_duplicate is True key1 = '%s:%s' %(process_name, context) task_existed = False for item in existing_task_dict: if item.startswith(key1): task_existed = True break if skip_duplicate and task_existed: continue process_obj = pipeline.get_process(process_name) if not process_obj: continue context=_get_context(existing_task_dict,process_name, context) pipe_code = process_obj.get_task_pipeline() attrs = process_obj.get_attributes() duration = attrs.get("duration") if duration: duration = int(duration) else: duration = default_duration bid_duration = attrs.get("bid_duration") if not bid_duration: bid_duration = default_bid_duration else: bid_duration = int(bid_duration) end_date = start_date.copy() # for a task to be x days long, we need duration x-1. end_date.add_days(duration-1) start_date_str = start_date.get_db_date() end_date_str = end_date.get_db_date() # Create the task last_task = Task.create(sobject, process_name, description, depend_id=depend_id, pipeline_code=pipe_code, start_date=start_date_str, end_date=end_date_str, context=context, bid_duration=bid_duration) # this avoids duplicated tasks for process connecting to multiple processes new_key = '%s:%s' %(last_task.get_value('process'), last_task.get_value("context") ) existing_task_dict[new_key] = True # for backward compatibility, if the process has been created, we will skip later below tasks.append(last_task) start_date = end_date.copy() # start the day after start_date.add_days(1) return tasks for process_name in process_names: if last_task: depend_id = last_task.get_id() else: depend_id = None process_obj = pipeline.get_process(process_name) if not process_obj: continue attrs = process_obj.get_attributes() duration = attrs.get("duration") if duration: duration = int(duration) else: duration = default_duration bid_duration = attrs.get("bid_duration") if not bid_duration: bid_duration = default_bid_duration else: bid_duration = int(bid_duration) end_date = start_date.copy() if duration >= 1: # for a task to be x days long, we need duration x-1. end_date.add_days(duration-1) # output contexts could be duplicated from 2 different outout processes if mode == 'simple process': output_contexts = [process_name] else: output_contexts = pipeline.get_output_contexts(process_obj.get_name(), show_process=False) pipe_code = process_obj.get_task_pipeline() start_date_str = start_date.get_db_date() end_date_str = end_date.get_db_date() for context in output_contexts: # first check if it already exists when skip_duplicate is True key1 = '%s:%s' %(process_name, context) task_existed = False for item in existing_task_dict: if item.startswith(key1): task_existed = True break if skip_duplicate and task_existed: continue if contexts and context not in contexts: continue context = _get_context(existing_task_dict, process_name, context) last_task = Task.create(sobject, process_name, description, depend_id=depend_id, pipeline_code=pipe_code, start_date=start_date_str, end_date=end_date_str, context=context, bid_duration=bid_duration) # this avoids duplicated tasks for process connecting to multiple processes new_key = '%s:%s' %(last_task.get_value('process'), last_task.get_value("context") ) existing_task_dict[new_key] = True # for backward compatibility, if the process has been created, we will skip later below tasks.append(last_task) start_date = end_date.copy() # start the day after start_date.add_days(1) return tasks
def get_display(self): # get all of the options direction = self.get_option("direction") if not direction: direction = "dst" icon_size = self.get_option("icon_size") if not icon_size: icon_size = 60 try: sobject = self.get_current_sobject() except IndexError: return '' if not hasattr(self, 'info'): return '' connections, dst_sobjects, sobj = self.info.get( sobject.get_search_key()) src_sobject = sobject # may not need this due to preprocess if isinstance(src_sobject, SObjectConnection): connection = src_sobject src_sobject = connection.get_sobject(direction="src") div = DivWdg() div.set_id("connection_%s" % src_sobject.get_id()) # set the ajax options self.set_ajax_top(div) self.set_ajax_option("search_key", src_sobject.get_search_key()) self.register_cmd("pyasm.widget.SObjectConnectionRemoveCbk") table = Table() table.set_max_width() table.set_class("minimal") count = 0 for dst_sobject in dst_sobjects: tr = table.add_row() if not dst_sobject: table.add_cell("referenced to retired or deleted asset....") continue if dst_sobject.is_retired(): tr.add_class("retired_row") thumb = ThumbWdg() thumb.set_show_filename(True) thumb.set_show_orig_icon(True) thumb.set_icon_size(icon_size) thumb.set_sobject(dst_sobject) td = table.add_cell(thumb) td.add_style("padding: 1px") td.add_style("width: 20%") id = dst_sobject.get_id() name = dst_sobject.get_name() code = dst_sobject.get_code() if code == str(id): pass elif name == code: td = table.add_cell(name) td.add_style("width: 20%") else: td = table.add_cell("%s<br/>%s" % (name, code)) td.add_style("width: 20%") if dst_sobject.has_value("title"): td = table.add_cell("%s" % dst_sobject.get_value("title")) elif dst_sobject.has_value("description"): td = table.add_cell("%s" % dst_sobject.get_value("description")) td.add_style("width: 30%") if dst_sobject.has_value("keywords"): td = table.add_cell("%s" % dst_sobject.get_value("keywords")) td.add_style("width: 20%") if dst_sobject.has_value("timestamp"): td = table.add_cell("%s" % Date( dst_sobject.get_value("timestamp")).get_display_time()) td.add_style("width: 20%") update = UpdateWdg() update.set_sobject(dst_sobject) update.set_option('delete', 'false') table.add_cell(update) # remove connection connection = connections[count] connection_id = connection.get_id() self.set_ajax_option("connection_id", connection_id) refresh_script = self.get_refresh_script(False) remove = IconButtonWdg("Remove Connection", IconWdg.DELETE) remove.add_event("onclick", refresh_script) table.add_cell(remove) count += 1 div.add(table) return div
def _get_bar(self, percent, proc_count, task): '''get a vertical bar indicating the progress of a task ''' sobject = self.get_current_sobject() bar = DivWdg() if self.desc_checkbox_value == "on": bar.add_style('margin-right: 20px') else: bar.add_style('width: 10px') bar.add_style('float: left') cur_percent = 100.0 increment = 100.0 / proc_count # get some task info assigned = 'unassigned' process = task.get_value('process') if task.get_value('assigned').strip(): assigned = task.get_value('assigned') task_desc = task.get_value('description') if not task_desc: task_desc = 'n/a' start_date = task.get_value("bid_start_date") end_date = task.get_value("bid_end_date") if start_date: start_date = Date(db_date=start_date, show_warning=False).get_display_date() else: start_date = "?" if end_date: end_date = Date(db_date=end_date, show_warning=False).get_display_date() else: end_date = "?" # remove some spacing characters task_desc = re.sub('(\n|\r|\t)', ' ', task_desc) task_desc = re.sub('"', "'", task_desc) task_status = task.get_value('status') display_percent = percent if percent < 0: task_status = "%s <font color=red>(obsolete)</font>" % task_status display_percent = 0 msg = '<b>%s</b><br/><hr>%s<br/><span style=padding-left:1em>desc: %s</span><br/>' \ '<span style=padding-left:1em>status:%s (%s%%)</span><br/>'\ '<span style=padding-left:1em>%s - %s</span>'\ % (process, assigned, task_desc, task_status, display_percent, start_date, end_date) if WebContainer.get_web().get_browser() == "IE": bar.add_event('onmouseover', "hint_bubble.show(event, '%s')" % msg) else: bar.add_tip(msg) from pyasm.widget import IconWdg end_date = task.get_value("bid_end_date") end_date = Date(db_date=end_date, show_warning=False) now_date = Date(show_warning=False) if now_date.get_utc() > end_date.get_utc() and percent != 100: alert_color = "#f00" else: alert_color = None for x in xrange(proc_count): cur_percent -= increment div = DivWdg() content = ' ' # unidentified status probably if percent < 0: content = '—' div.add_style('text-decoration: blink') div.add(content) div.add_style('width: 10px') if cur_percent < percent or cur_percent == 0: if alert_color: div.add_style("background-color: %s" % alert_color) else: div.add_style("background-color: %s" % self._get_color_code(percent)) bar_height = self.get_option("bar_height") if not bar_height: bar_height = self.bar_select_value if not bar_height: bar_height = '3' div.add_style("height: %spx" % bar_height) # IE needs to set the font size to reduce the overall size div.add_style("font-size: %spx" % bar_height) if sobject.is_retired(): div.add_class('task_status_bar_retired') else: if self.label_select_value == "abbr": div.add_style("margin: -1px") #div.add_class("task_status_bar") #div.add_style("margin-top: 2px") div.add_border() bar.add(div) if self.desc_checkbox_value == "on": span = SpanWdg(task_desc) span.add_style('font-size: 0.8em') bar.add(span) return bar