Exemple #1
0
 def resolve(self, user, project, resolution=COMPLETED):
     "Resolve the task."
     status = self.statuses.get(project=project)
     status.status = RESOLVED
     status.resolution = resolution
     status.save()
     flag = RESOLVED + resolution
     status_changed.send(sender=status, user=user, flag=flag)
Exemple #2
0
    def activate(self, user):
        "Activate the tracker across all related projects."

        self.activate_children(user)
        for status in self.statuses.all():
            status.status = ACTIVE
            status.save()
            status_changed.send(sender=status, user=user, flag=ACTIVATED)
Exemple #3
0
    def resolve(self, user, resolution=COMPLETED, bubble_up=True):
        """Resolve the step.

        Resolve the current step and, if `bubble_up` is True, resolve the
        parent or the parents.

        Arguments:
        user -- the user that is resolving the step; used for the signal
        resolution -- an integer specifying the resolution type (see
                      todo.workflow)
        bubble_up -- a boolean which if True will make the method resolve the
                     parent(s) of the current step as well.

        More on the `bubble_up` behavior:  When `bubble_up` is True, and if the
        step was resolved successfully and it is the last one among its
        siblings, its parent will be resolved successfully too and if in turn
        the parent is the last one among *its* siblings, the parent's parent
        will be resolved etc.  The resolution *bubbles up*.  On the other hand,
        if the step has failed (note that it must be a review step to be able
        to fail in the first place), the immediate parent of the current step
        is resolved as failed as well and a fresh clone is made so that the
        required actions can take place again.  This time, however, the
        parent's parent is not touched.  The bubbling stops after the first
        parent.

        """
        self.status = RESOLVED
        self.resolution = resolution
        self.save()
        flag = RESOLVED + resolution
        status_changed.send(sender=self, user=user, flag=flag)

        if not bubble_up:
            # don't do anything more
            return
        if ((self.is_last() and self.is_only_active()) or
            self.is_last_open()):
            if self.parent:
                # resolve the parent Step(s)
                if self.resolution == FAILED:
                    # if the step has failed, resolve only the immediate parent
                    # and make a fresh copy of it.  The parent needs to be
                    # a Step, not the Task (can't clone a Task), hence check
                    # for self.parent.
                    bubble_up = False
                    # `clone` will call the prototype's `spawn` method which by 
                    # default activates the created todos
                    self.parent.clone(user)
                self.parent.resolve(user, self.resolution, bubble_up)
            else:
                # no parent means this is a top-level step and the task is
                # possibly ready to be resolved. This left for the user to
                # decide however.
                pass
        elif self.next_step() and self.next_step().status_is('new'):
            self.next_step().activate(user)
Exemple #4
0
 def activate(self, user):
     if self.has_children:
         self.activate_children(user)
         # it's `active`, because one of the children is `next`
         self.status = ACTIVE
     else:
         # no children, `next` it
         self.status = NEXT
     self.save()
     status_changed.send(sender=self, user=user, flag=self.status)
Exemple #5
0
 def activate(self, user):
     if self.has_children is True:
         self.activate_children(user)
         # it's `active`, because one of the children is `next`
         self.status = 2
     else:
         # no children, `next` it
         self.status = 3
     self.save()
     status_changed.send(sender=self, user=user, action=self.status)
Exemple #6
0
    def spawn(self, user, cloning_allowed=True, **custom_fields):
        """Create an instance of the model related to the proto, with children.
        
        This method creates an instance of the model related to the current
        prototype, e.g. in case of a ProtoTracker, it will create a Tracker.
        It also creates all the children of the newly created Tracker, Task
        or Step (the 'todo' objects).

        The todo objects will be created with properties as set on the
        prototypes and nestings. You can override them by passing custom
        values in the keyword arguments.

        A `project` keyword argument is required when spawning trackers or
        tasks. It must be an instance of todo.models.Project. The created todo 
        objects will be related to the project passed.

        A special iterable `locales` keyword argument can be passed to create
        multiple trees of todo objects, one per locale in `locales`. Only
        todo objects with clone_per_locale set to True will be cloned in this
        way.

        The method always returns just one, top-level todo object, even if
        more were created as children.

        """
        if self.type in (1, 2) and 'project' not in custom_fields:
            raise TypeError("Pass a project to spawn trackers and tasks.")
        todo = self._spawn_instance(**custom_fields)
        todo.save()
        status_changed.send(sender=todo, user=user, action=todo.status)
        if self.type in (1, 3):
            # trackers and steps
            to_be_removed = self.inheritable
            custom_fields.update(parent=todo)
        else:
            # tasks
            # Steps are related to Tasks via the `task` property which is set 
            # above, and the top-level steps have the `parent` property set 
            # to None. Here, we're removing `parent` to make sure the child
            # steps are `parent`-less. (`parent` might have been used before
            # to create relationships between Trackers or Trackers/Tasks). 
            to_be_removed = self.inheritable + ('parent',)
            custom_fields.update(task=todo)
        for prop in to_be_removed:
            # these properties are inheritable by the current todo object,
            # but not by its children. they should not propagate further down.
            if prop in custom_fields:
                del custom_fields[prop]
        self._spawn_children(user, cloning_allowed, **custom_fields)
        return todo
Exemple #7
0
def create(request, obj):
    if obj == 'tasks':
        form_class = AddTasksForm
    else:
        form_class = AddTrackersForm

    if request.method == 'POST':
        form = form_class(request.POST)
        parent_form = ChooseParentForm(request.POST)
        if form.is_valid() and parent_form.is_valid():
            fields = form.cleaned_data
            parent_clean = parent_form.cleaned_data
            parent = parent_clean['tracker']
            if (parent is None and
                parent_clean['parent_summary'] and
                parent_clean['parent_project']):
                # user wants to create a new tracker which will be the parent
                parent = Tracker(summary=parent_clean['parent_summary'],
                                 project=parent_clean['parent_project'],
                                 locale=parent_clean['parent_locale'],
                                 suffix=parent_clean['parent_suffix'])
                parent.save()
                # send the 'created' signal
                status_changed.send(sender=parent, user=request.user,
                                    action=parent.status)
                parent.activate(request.user)
            if parent is not None:
                # For consistency's sake, if a parent is specified, try to
                # use its values for `project` and `locale` to create the
                # task, ignoring values provided by the user in the form.
                fields['project'] = parent.project
                if parent.locale:
                    fields['locales'] = [parent.locale]
            fields['parent'] = parent
            prototype = form.cleaned_data.pop('prototype')
            if prototype.clone_per_locale is True:
                for todo in prototype.spawn_per_locale(request.user, **fields):
                    todo.activate(request.user)
            else:
                todo = prototype.spawn(request.user, **fields) 
                todo.activate(request.user)
            return HttpResponseRedirect(reverse('todo.views.demo.%s' % obj[:-1],
                                                args=[todo.pk]))
    else:
        form = form_class()
        parent_form = ChooseParentForm()
    return render_to_response('todo/new_%s.html' % obj[:-1],
                              {'form': form,
                               'parent_form': parent_form,})
Exemple #8
0
    def _spawn_instance(self, user, activate, **custom_fields):
        "Create an instance of the model related to the proto."

        related_model = self.get_related_model()
        # fields that are accepted by the spawned object
        accepted_fields = [f.name for f in related_model._meta.fields]
        # models can define additional accepted fields (e.g. 'suffix')
        accepted_fields += related_model.extra_fields
        # remove projects from custom_fields since related_model.__init__ 
        # (regardless of which model it stands for) does not accept them as 
        # argument; store the value for later use, though.
        projects = custom_fields.pop('projects', None)
        # remove empty/unknown values from custom_fields and overwrite other 
        # attributes
        custom_fields = [(k, v) for k, v in custom_fields.items()
                                if v and k in accepted_fields]
        # fields (with values) which will be inherited by the spawned object
        fields = dict([(f, getattr(self, f)) for f in self.inheritable])
        # custom fields override fields from the proto
        fields.update(custom_fields)
        todo = related_model(prototype=self, **fields)
        # store the string representation of the todo as its property before 
        # it is saved, in order to avoid a query made by todo.get_repr
        todo.repr = todo.format_repr(**fields)
        if self.type == STEP_TYPE:
            if activate and todo.should_be_activated():
                # a Step can only be related to a single Project (or, more 
                # often, to no projects at all), so its status is stored 
                # directly as a property.
                todo.status = ACTIVE
            todo.save()
        else:
            # save it so that it has an ID
            todo.save()
            # in order to create relations between Trackers/Tasks and Projects, 
            # create required {Tracker,Task}InProject objects handling the 
            # many-to-many relation; set the status to 'active' is requested.
            todo.assign_to_projects(projects,
                                    status=ACTIVE if activate else None)
        status_changed.send(sender=todo, user=user, flag=CREATED)
        return todo
Exemple #9
0
 def reset_time(self, user):
     if self.status == NEXT:
         # the step must be a 'next' step.  Resetting the timer is simply
         # sending the signal about the step being 'nexted' again.
         status_changed.send(sender=self, user=user, flag=NEXTED)
Exemple #10
0
 def resolve(self, user, resolution=1):
     self.status = 5
     self.resolution = resolution
     self.save()
     status_changed.send(sender=self, user=user, action=self.status)
Exemple #11
0
 def activate(self, user):
     self.activate_children(user)
     self.status = 2
     self.save()
     status_changed.send(sender=self, user=user, action=self.status)