예제 #1
0
def build_cycle(workflow, cycle=None, current_user=None):
  """Build a cycle with it's child objects"""

  if not workflow.tasks:
    logger.error("Starting a cycle has failed on Workflow with "
                 "slug == '%s' and id == '%s'", workflow.slug, workflow.id)
    pusher.update_or_create_notifications(workflow, date.today(),
                                          "cycle_start_failed")
    return

  # Determine the relevant Workflow
  cycle = cycle or models.Cycle()

  # Use Admin role when this is called via the cron job.
  if not current_user:
    current_user = workflow.get_persons_for_rolename("Admin")[0]
  # Populate the top-level Cycle object
  cycle.workflow = workflow
  cycle.is_current = True
  cycle.context = workflow.context
  cycle.title = workflow.title
  cycle.description = workflow.description
  cycle.is_verification_needed = workflow.is_verification_needed
  cycle.status = models.Cycle.ASSIGNED

  # Populate CycleTaskGroups based on Workflow's TaskGroups
  for task_group in workflow.task_groups:
    cycle_task_group = models.CycleTaskGroup(
        context=cycle.context,
        cycle=cycle,
        task_group=task_group,
        title=task_group.title,
        description=task_group.description,
        end_date=cycle.end_date,
        modified_by=current_user,
        contact=task_group.contact,
        status=models.CycleTaskGroup.ASSIGNED,
        sort_index=task_group.sort_index,
    )

    # preserve the old cycle creation for old workflows, so each object
    # gets its own cycle task
    if workflow.is_old_workflow:
      create_old_style_cycle(cycle, task_group, cycle_task_group, current_user)
    else:
      for task_group_task in task_group.task_group_tasks:
        cycle_task_group_object_task = _create_cycle_task(
            task_group_task, cycle, cycle_task_group, current_user)

        for task_group_object in task_group.task_group_objects:
          object_ = task_group_object.object
          Relationship(source=cycle_task_group_object_task,
                       destination=object_)

  update_cycle_dates(cycle)
  workflow.repeat_multiplier += 1
  workflow.next_cycle_start_date = workflow.calc_next_adjusted_date(
      workflow.min_task_start_date)
  return cycle
예제 #2
0
    def test_generates_correct_url_for_inactive_cycle(self, *mocks):
        """The method should return correct URL for inactive Cycles."""
        workflow = models.Workflow(id=111)
        cycle = models.Cycle(id=22, workflow=workflow)

        expected_url = (u"http://www.foo.com/"
                        u"workflows/111#history"
                        u"/cycle/22")
        self.assertEqual(expected_url, cycle.cycle_inactive_url)
예제 #3
0
    def test_url_for_inactive_cycle(self, *_):
        """The method should return correct URL for inactive Cycles."""
        workflow = models.Workflow(id=111)
        cycle = models.Cycle(slug="CYCLE-22", workflow=workflow)

        expected_url = (u"http://www.foo.com/"
                        u"workflows/111#history"
                        u"&query=%22cycle%20slug%22%3D%22CYCLE-22%22")
        self.assertEqual(expected_url, cycle.cycle_inactive_url)
예제 #4
0
    def test_generates_correct_url_for_active_cycle(self, *mocks):
        """The method should return correct URL for active Cycles."""
        workflow = models.Workflow(id=111)
        cycle = models.Cycle(id=22, workflow=workflow)

        # by default, a cycle is considered active
        expected_url = (u"http://www.foo.com/"
                        u"workflows/111#current"
                        u"/cycle/22")
        self.assertEqual(expected_url, cycle.cycle_url)
예제 #5
0
    def test_url_for_active_cycle(self, *_):
        """The method should return correct URL for active Cycles."""
        workflow = models.Workflow(id=111)
        cycle = models.Cycle(slug="CYCLE-22", workflow=workflow)

        # by default, a cycle is considered active
        expected_url = (u"http://www.foo.com/"
                        u"workflows/111#current"
                        u"&query=%22cycle%20slug%22%3D%22CYCLE-22%22")
        self.assertEqual(expected_url, cycle.cycle_url)
예제 #6
0
def update_workflow_state(workflow):
  today = date.today()
  calculator = workflow_cycle_calculator.get_cycle_calculator(workflow)

  # Start the first cycle if min_start_date < today < max_end_date
  if workflow.status == "Active" and workflow.recurrences and calculator.tasks:
    start_date, end_date = calculator.workflow_date_range()
    # Only create the cycle if we're mid-cycle
    if (start_date <= today <= end_date) \
            and not workflow.cycles:
      cycle = models.Cycle()
      cycle.workflow = workflow
      cycle.calculator = calculator
      # Other cycle attributes will be set in build_cycle.
      build_cycle(
          cycle,
          None,
          base_date=workflow.non_adjusted_next_cycle_start_date)
      notification.handle_cycle_created(None, obj=cycle)

    adjust_next_cycle_start_date(calculator, workflow)

    db.session.add(workflow)
    db.session.flush()
    return

  if not calculator.tasks:
    workflow.next_cycle_start_date = None
    workflow.non_adjusted_next_cycle_start_date = None
    return

  for cycle in workflow.cycles:
    if cycle.is_current:
      return

  if workflow.status == 'Draft':
    return

  if workflow.status == "Inactive":
    if workflow.cycles:
      workflow.status = "Active"
      db.session.add(workflow)
      db.session.flush()
      return

  # Active workflow with no recurrences and no active cycles, workflow is
  # now Inactive
  workflow.status = 'Inactive'
  db.session.add(workflow)
  db.session.flush()
예제 #7
0
def start_recurring_cycles():
    # Get all workflows that should start a new cycle today
    # The next_cycle_start_date is precomputed and stored when a cycle is created
    today = date.today()
    workflows = db.session.query(models.Workflow)\
        .filter(
        models.Workflow.next_cycle_start_date == today,
        models.Workflow.recurrences == True  # noqa
    ).all()

    # For each workflow, start and save a new cycle.
    for workflow in workflows:
        cycle = models.Cycle()
        cycle.workflow = workflow
        cycle.calculator = workflow_cycle_calculator.get_cycle_calculator(
            workflow)
        cycle.context = workflow.context
        # We can do this because we selected only workflows with
        # next_cycle_start_date = today
        cycle.start_date = date.today()

        # Flag the cycle to be saved
        db.session.add(cycle)

        if workflow.non_adjusted_next_cycle_start_date:
            base_date = workflow.non_adjusted_next_cycle_start_date
        else:
            base_date = date.today()

        # Create the cycle (including all child objects)
        build_cycle(cycle, base_date=base_date)

        # Update the workflow next_cycle_start_date to push it ahead based on the
        # frequency.
        adjust_next_cycle_start_date(cycle.calculator,
                                     workflow,
                                     move_forward=True)

        db.session.add(workflow)

        notification.handle_workflow_modify(None, workflow)
        notification.handle_cycle_created(None, obj=cycle)

    db.session.commit()
    db.session.flush()
예제 #8
0
def build_cycle(workflow, cycle=None, current_user=None):
  """Build a cycle with it's child objects"""
  build_failed = False

  if not workflow.tasks:
    logger.error("Starting a cycle has failed on Workflow with "
                 "slug == '%s' and id == '%s', due to empty setup",
                 workflow.slug, workflow.id)
    build_failed = True

  # Use Admin role when this is called via the cron job.
  if not current_user:
    admins = workflow.get_persons_for_rolename("Admin")
    if admins:
      current_user = admins[0]
    else:
      logger.error("Cannot start cycle on Workflow with slug == '%s' and "
                   "id == '%s', cause it doesn't have Admins",
                   workflow.slug, workflow.id)
      build_failed = True

  if build_failed:
    pusher.update_or_create_notifications(workflow, date.today(),
                                          "cycle_start_failed")
    return

  # Determine the relevant Workflow
  cycle = cycle or models.Cycle()

  # Populate the top-level Cycle object
  cycle.workflow = workflow
  cycle.is_current = True
  cycle.context = workflow.context
  cycle.title = workflow.title
  cycle.description = workflow.description
  cycle.is_verification_needed = workflow.is_verification_needed
  cycle.status = models.Cycle.ASSIGNED

  # Populate CycleTaskGroups based on Workflow's TaskGroups
  for task_group in workflow.task_groups:
    cycle_task_group = models.CycleTaskGroup(
        context=cycle.context,
        cycle=cycle,
        task_group=task_group,
        title=task_group.title,
        description=task_group.description,
        end_date=cycle.end_date,
        modified_by=current_user,
        contact=task_group.contact,
        status=models.CycleTaskGroup.ASSIGNED,
    )

    # preserve the old cycle creation for old workflows, so each object
    # gets its own cycle task
    if workflow.is_old_workflow:
      create_old_style_cycle(cycle, task_group, cycle_task_group, current_user)
    else:
      for task_group_task in task_group.task_group_tasks:
        cycle_task_group_object_task = _create_cycle_task(
            task_group_task, cycle, cycle_task_group, current_user)
        related_objs = [obj for obj in task_group.related_objects()
                        if not isinstance(obj, (
                            all_models.TaskGroupTask, all_models.Workflow
                        ))]
        for obj in related_objs:
          Relationship(source=cycle_task_group_object_task,
                       destination=obj)

  update_cycle_dates(cycle)
  workflow.repeat_multiplier += 1
  workflow.next_cycle_start_date = workflow.calc_next_adjusted_date(
      workflow.min_task_start_date)
  return cycle