def not_done_tasks_notify(tasks): """Notification handling for tasks that moved to active state. It will - create notification for tasks if it's needed - delete all notifications for related cycles """ if not tasks: return cycles = set() declined_tasks = set() for task in tasks: cycles.add(task.cycle) if task.status == models.CycleTaskGroupObjectTask.DECLINED: declined_tasks.add(task) # delete all notifications for cycles about all tasks completed if cycles: pusher.get_notification_query( *(list(cycles)), **{ "notification_names": ["all_cycle_tasks_completed"] }).delete(synchronize_session="fetch") if declined_tasks: pusher.create_notifications_for_objects( pusher.get_notification_type("cycle_task_declined"), datetime.date.today(), *(list(declined_tasks)))
def not_done_tasks_notify(tasks, day): """Notification handling for tasks that moved to active state. It will - create notification for tasks if it's needed - delete all notifications for related cycles """ if not tasks: return cycles = {task.cycle for task in tasks} # delete all notifications for cycles about all tasks completed if cycles: pusher.get_notification_query( *(list(cycles)), **{"notification_names": ["all_cycle_tasks_completed"]} ).delete( synchronize_session=False ) # recreate notifications if it's necessary for task in tasks: pusher.update_or_create_notifications( task, task.end_date, get_notif_name_by_wf(task.cycle.workflow), "cycle_task_due_today", "cycle_task_overdue", day=day )
def done_tasks_notify(tasks): """Notification handling for tasks that moved in done state. It will - delete all notifications for done tasks - create notification for related cycle if all tasks in done state """ if not tasks: return pusher.get_notification_query(*tasks).delete(synchronize_session="fetch") cycle_tasks_dict = collections.defaultdict(list) cycles_dict = {} task_ids = [] for obj in tasks: cycle_tasks_dict[obj.cycle].append(obj) cycles_dict[obj.cycle.id] = obj.cycle task_ids.append(obj.id) task_query = all_models.CycleTaskGroupObjectTask.query.filter( all_models.CycleTaskGroupObjectTask.cycle_id.in_(cycles_dict.keys()), all_models.CycleTaskGroupObjectTask.id.notin_(task_ids), ).options( db.Load(all_models.CycleTaskGroupObjectTask).undefer_group( "CycleTaskGroupObjectTask_complete")).all() for task in task_query: cycle_tasks_dict[cycles_dict[task.cycle_id]].append(task) done_cycles = [ cycle for cycle, cycle_tasks in cycle_tasks_dict.iteritems() if all(task.is_done for task in cycle_tasks) ] pusher.create_notifications_for_objects("all_cycle_tasks_completed", datetime.date.today(), *done_cycles)
def not_done_tasks_notify(tasks, day): """Notification handling for tasks that moved to active state. It will - create notification for tasks if it's needed - delete all notifications for related cycles """ if not tasks: return cycles = {task.cycle for task in tasks} # delete all notifications for cycles about all tasks completed if cycles: pusher.get_notification_query( *(list(cycles)), **{ "notification_names": ["all_cycle_tasks_completed"] }).delete(synchronize_session=False) # recreate notifications if it's necessary for task in tasks: pusher.update_or_create_notifications(task, task.end_date, get_notif_name_by_wf( task.cycle.workflow), "cycle_task_due_today", "cycle_task_overdue", day=day)
def not_done_tasks_notify(tasks): """Notification handling for tasks that moved to active state. It will - create notification for tasks if it's needed - delete all notifications for related cycles """ if not tasks: return cycles = set() declined_tasks = set() for task in tasks: cycles.add(task.cycle) if task.status == models.CycleTaskGroupObjectTask.DECLINED: declined_tasks.add(task) # delete all notifications for cycles about all tasks completed if cycles: pusher.get_notification_query( *(list(cycles)), **{"notification_names": ["all_cycle_tasks_completed"]} ).delete( synchronize_session="fetch" ) if declined_tasks: pusher.create_notifications_for_objects( pusher.get_notification_type("cycle_task_declined"), datetime.date.today(), *(list(declined_tasks)) )
def handle_cycle_modify(obj): if not inspect(obj).attrs.is_current.history.has_changes(): return if not obj.is_current: # delete all notifications for cycle tasks pusher.get_notification_query( *list(obj.cycle_task_group_object_tasks)).delete( synchronize_session="fetch")
def handle_cycle_modify(obj): if not inspect(obj).attrs.is_current.history.has_changes(): return if not obj.is_current: # delete all notifications for cycle tasks pusher.get_notification_query( *list(obj.cycle_task_group_object_tasks) ).delete(synchronize_session="fetch")
def done_tasks_notify(tasks, day): """Notification handling for tasks that moved in done state. It will - delete all notifications for done tasks - create notification for related cycle if all tasks in done state """ if not tasks: return pusher.get_notification_query(*tasks).delete( synchronize_session=False ) cycle_tasks_dict = collections.defaultdict(list) cycles_dict = {} task_ids = [] for obj in tasks: cycle_tasks_dict[obj.cycle].append(obj) cycles_dict[obj.cycle.id] = obj.cycle task_ids.append(obj.id) task_query = all_models.CycleTaskGroupObjectTask.query.filter( all_models.CycleTaskGroupObjectTask.cycle_id.in_(cycles_dict.keys()), all_models.CycleTaskGroupObjectTask.id.notin_(task_ids), ).options( db.Load( all_models.CycleTaskGroupObjectTask ).undefer_group( "CycleTaskGroupObjectTask_complete" ) ).all() for task in task_query: cycle_tasks_dict[cycles_dict[task.cycle_id]].append(task) done_cycles = [cycle for cycle, cycle_tasks in cycle_tasks_dict.iteritems() if all(task.is_done for task in cycle_tasks)] # this filtration is required for correct work of # '/admin/generate_wf_tasks_notifications' endpoint existing_notifications = pusher.get_notification_query( *done_cycles, **{"notification_names": ["all_cycle_tasks_completed"]} ).all() cycles_with_notifications_ids = [notif.object_id for notif in existing_notifications] done_cycles_without_notifs = [cycle for cycle in done_cycles if cycle.id not in cycles_with_notifications_ids] pusher.create_notifications_for_objects("all_cycle_tasks_completed", datetime.date.today(), *done_cycles_without_notifs, day=day)
def handle_cycle_created(obj, manually): today = datetime.date.today() if manually: create_notification = "manual_cycle_created" else: create_notification = "cycle_created" pusher.update_or_create_notifications(obj, today, create_notification) if not obj.is_current: return notification_names = [get_notif_name_by_wf(obj.workflow), create_notification, "cycle_task_overdue", "cycle_task_due_today"] tasks = list(obj.cycle_task_group_object_tasks) query = pusher.get_notification_query( *tasks, **{"notification_names": notification_names}) exists_notifications = collections.defaultdict(set) for notification in query: exists_notifications[notification.notification_type_id].add( notification.object_id) for notification_type in pusher.get_notification_types(*notification_names): object_ids = exists_notifications[notification_type.id] notify_tasks = [t for t in tasks if not (t.id in object_ids or t.is_done)] if create_notification == notification_type.name: pusher.create_notifications_for_objects(notification_type, today, *notify_tasks) else: for task in notify_tasks: pusher.create_notifications_for_objects(notification_type, task.end_date, task)
def handle_cycle_created(obj, manually): today = datetime.date.today() if manually: create_notification = "manual_cycle_created" else: create_notification = "cycle_created" pusher.update_or_create_notifications(obj, today, create_notification) if not obj.is_current: return notification_names = [ get_notif_name_by_wf(obj.workflow), create_notification, "cycle_task_overdue", "cycle_task_due_today" ] tasks = list(obj.cycle_task_group_object_tasks) query = pusher.get_notification_query( *tasks, **{"notification_names": notification_names}) exists_notifications = collections.defaultdict(set) for notification in query: exists_notifications[notification.notification_type_id].add( notification.object_id) for notification_type in pusher.get_notification_types( *notification_names): object_ids = exists_notifications[notification_type.id] notify_tasks = [ t for t in tasks if not (t.id in object_ids or t.is_done) ] if create_notification == notification_type.name: pusher.create_notifications_for_objects(notification_type, today, *notify_tasks) else: for task in notify_tasks: pusher.create_notifications_for_objects( notification_type, task.end_date, task)
def not_done_tasks_notify(tasks): """Notification handling for tasks that moved to active state. It will - create notification for tasks if it's needed - delete all notifications for related cycles """ if not tasks: return cycles = set() notification_send_at_tasks_dict = collections.defaultdict(list) notification_types = set() for task in tasks: cycles.add(task.cycle) if task.status == models.CycleTaskGroupObjectTask.DECLINED: notification_send_at_tasks_dict[ ("cycle_task_declined", datetime.date.today()) ].append(task) notification_types.add("cycle_task_declined") for n_type in [get_notif_name_by_wf(task.cycle.workflow), "cycle_task_due_today", "cycle_task_overdue"]: notification_send_at_tasks_dict[ (n_type, task.end_date) ].append(task) notification_types.add(n_type) # delete all notifications for cycles about all tasks compleated and # all tasks notifications that required to be updated pusher.get_notification_query( *(list(cycles) + tasks), **{"notification_names": [ "all_cycle_tasks_completed" ] + list(notification_types)} ).delete( synchronize_session="fetch" ) notification_type_query = pusher.get_notification_types(*notification_types) notification_types_dict = {t.name: t for t in notification_type_query} for pair, pair_tasks in notification_send_at_tasks_dict.iteritems(): notification_type_name, send_at = pair notification_type = notification_types_dict[notification_type_name] pusher.create_notifications_for_objects(notification_type, send_at, *pair_tasks)
def handle_cycle_task_status_change(obj): if obj.is_done: query = pusher.get_notification_query(obj) query.delete(synchronize_session="fetch") # if all tasks are in inactive states then add notification to cycle if all(task.is_done for task in obj.cycle.cycle_task_group_object_tasks): pusher.update_or_create_notifications(obj.cycle, datetime.date.today(), "all_cycle_tasks_completed") else: pusher.get_notification_query( obj.cycle, **{ "notification_names": ["all_cycle_tasks_completed"] }).delete(synchronize_session="fetch") if obj.status == models.CycleTaskGroupObjectTask.DECLINED: pusher.update_or_create_notifications(obj, datetime.date.today(), "cycle_task_declined") pusher.update_or_create_notifications( obj, obj.end_date, get_notif_name_by_wf(obj.cycle.workflow), "cycle_task_due_today", "cycle_task_overdue")
def handle_cycle_task_status_change(obj): if obj.is_done: query = pusher.get_notification_query(obj) query.delete(synchronize_session="fetch") # if all tasks are in inactive states then add notification to cycle if all(task.is_done for task in obj.cycle.cycle_task_group_object_tasks): pusher.update_or_create_notifications( obj.cycle, datetime.date.today(), "all_cycle_tasks_completed") else: pusher.get_notification_query( obj.cycle, **{"notification_names": ["all_cycle_tasks_completed"]} ).delete(synchronize_session="fetch") if obj.status == models.CycleTaskGroupObjectTask.DECLINED: pusher.update_or_create_notifications( obj, datetime.date.today(), "cycle_task_declined") pusher.update_or_create_notifications( obj, obj.end_date, get_notif_name_by_wf(obj.cycle.workflow), "cycle_task_due_today", "cycle_task_overdue")
def done_tasks_notify(tasks): """Notification handling for tasks that moved in done state. It will - delete all notifications for done tasks - create notification for related cycle if all tasks in done state """ if not tasks: return pusher.get_notification_query(*tasks).delete(synchronize_session="fetch") cycle_tasks_dict = collections.defaultdict(list) cycles_dict = {} task_ids = [] for obj in tasks: cycle_tasks_dict[obj.cycle].append(obj) cycles_dict[obj.cycle.id] = obj.cycle task_ids.append(obj.id) task_query = all_models.CycleTaskGroupObjectTask.query.filter( all_models.CycleTaskGroupObjectTask.cycle_id.in_(cycles_dict.keys()), all_models.CycleTaskGroupObjectTask.id.notin_(task_ids), ).options( db.Load( all_models.CycleTaskGroupObjectTask ).undefer_group( "CycleTaskGroupObjectTask_complete" ) ).all() for task in task_query: cycle_tasks_dict[cycles_dict[task.cycle_id]].append(task) done_cycles = [cycle for cycle, cycle_tasks in cycle_tasks_dict.iteritems() if all(task.is_done for task in cycle_tasks)] pusher.create_notifications_for_objects("all_cycle_tasks_completed", datetime.date.today(), *done_cycles)
def handle_workflow_modify(sender, obj=None, src=None, service=None): """Update or add notifications on a workflow update.""" if obj.status != obj.ACTIVE or obj.unit is None: return if not obj.next_cycle_start_date: obj.next_cycle_start_date = obj.min_task_start_date pusher.update_or_create_notifications( obj, obj.next_cycle_start_date, "{}_workflow_starts_in".format(obj.unit), "cycle_start_failed") query = pusher.get_notification_query( *list(obj.tasks), **{"notification_names": ["cycle_start_failed"]}) notif_type = pusher.get_notification_type("cycle_start_failed") exist_task_ids = set(query.distinct(Notification.object_id)) for task in obj.tasks: if task.id not in exist_task_ids: pusher.push(task, notif_type, task.start_date)
def handle_cycle_created(obj, manually): today = datetime.date.today() if manually: create_notification = "manual_cycle_created" else: create_notification = "cycle_created" pusher.update_or_create_notifications(obj, today, create_notification) if not obj.is_current: return task_notif_name = get_notif_name_by_wf(obj.workflow) notification_names = [ task_notif_name, create_notification, "cycle_task_overdue", "cycle_task_due_today" ] notif_dict = [pusher.get_notification_type(n) for n in notification_names] tasks = list(obj.cycle_task_group_object_tasks) query = pusher.get_notification_query( *tasks, **{"notification_names": notification_names}) exists_notifications = collections.defaultdict(set) for notification in query: exists_notifications[notification.notification_type_id].add( notification.object_id) for notification_type in notif_dict: object_ids = exists_notifications[notification_type.id] repeatable_notification = (notification_type.name in pusher.REPEATABLE_NOTIFICATIONS) for task in tasks: if task.id in object_ids or task.is_done: continue if create_notification == notification_type.name: send_on = today else: send_on = task.end_date send_on -= datetime.timedelta(notification_type.advance_notice) if repeatable_notification: send_on = max(send_on, today) if send_on >= today: pusher.push(task, notification_type, send_on, repeatable_notification)
def handle_cycle_created(obj, manually): today = datetime.date.today() if manually: create_notification = "manual_cycle_created" else: create_notification = "cycle_created" pusher.update_or_create_notifications(obj, today, create_notification) if not obj.is_current: return task_notif_name = get_notif_name_by_wf(obj.workflow) notification_names = [task_notif_name, create_notification, "cycle_task_overdue", "cycle_task_due_today"] notif_dict = [pusher.get_notification_type(n) for n in notification_names] tasks = list(obj.cycle_task_group_object_tasks) query = pusher.get_notification_query( *tasks, **{"notification_names": notification_names}) exists_notifications = collections.defaultdict(set) for notification in query: exists_notifications[notification.notification_type_id].add( notification.object_id) for notification_type in notif_dict: object_ids = exists_notifications[notification_type.id] repeatable_notification = ( notification_type.name in pusher.REPEATABLE_NOTIFICATIONS ) for task in tasks: if task.id in object_ids or task.is_done: continue if create_notification == notification_type.name: send_on = today else: send_on = task.end_date send_on -= datetime.timedelta(notification_type.advance_notice) if repeatable_notification: send_on = max(send_on, today) if send_on >= today: pusher.push(task, notification_type, send_on, repeatable_notification)