0
0
mirror of https://github.com/wagtail/wagtail.git synced 2024-11-30 01:46:24 +01:00

Rewrite methods to account for revisions. Test and fix initial exceptions. Add database constraint on unique in progress workflow

This commit is contained in:
jacobtm 2019-11-19 11:54:45 +00:00 committed by Matt Westcott
parent 77e4f39e38
commit 5416bdf4ba

View File

@ -2491,16 +2491,20 @@ class Task(models.Model):
else:
return content_type.get_object_for_this_type(id=self.id)
@transaction.atomic
def start(self, workflow_state):
task_state = TaskState(workflow_state=workflow_state)
task_state.status = 'in_progress'
task_state.page_revision = workflow_state.page.get_latest_revision()
task_state.task = self
task_state.save()
workflow_state.current_state = task_state
workflow_state.save()
return task_state
@transaction.atomic
def on_action(self, workflow_state, task_state, action_name):
latest_revision = workflow_state.page.get_latest_revision()
if action_name == 'approve':
task_state.approve()
workflow_state.update()
@ -2559,9 +2563,9 @@ class WorkflowState(models.Model):
('cancelled', _("Cancelled")),
)
page = models.ForeignKey('Page', on_delete=models.CASCADE, verbose_name=_("page"))
workflow = models.ForeignKey('Workflow', on_delete=models.CASCADE, verbose_name=_('workflow'))
status = models.fields.CharField(choices=WORKFLOW_STATUS_CHOICES, blank=False, null=False, verbose_name=_("status"), max_length=50)
page = models.ForeignKey('Page', on_delete=models.CASCADE, verbose_name=_("page"), related_name='workflow_states')
workflow = models.ForeignKey('Workflow', on_delete=models.CASCADE, verbose_name=_('workflow'), related_name='workflow_states')
status = models.fields.CharField(choices=WORKFLOW_STATUS_CHOICES, blank=False, null=False, verbose_name=_("status"), max_length=50, default='in_progress')
created_at = models.DateTimeField(auto_now=True, verbose_name=_("created at"))
requested_by = models.ForeignKey(settings.AUTH_USER_MODEL,
verbose_name=_('requested by'),
@ -2574,11 +2578,47 @@ class WorkflowState(models.Model):
verbose_name=_("current task state"))
def __str__(self):
return _("Workflow '{0}' on Page '{1}'").format(self.workflow, self.page)
return _("Workflow '{0}' on Page '{1}': {2}").format(self.workflow, self.page, self.status)
def update(self):
try:
current_status = self.current_task_state.status
except AttributeError:
current_status = None
if not current_status or current_status == 'approved':
next_task = self.get_next_task()
if next_task:
self.current_task_state = next_task.start(self)
self.save()
else:
self.finish()
elif current_status == 'rejected' or current_status == 'cancelled':
self.status = current_status
self.save()
def get_next_task(self):
return Task.objects.filter(workflow_tasks__workflow=self.workflow).exclude(task_states__page_revision=self.page.get_latest_revision()).order_by('workflow_tasks__sort_order').first()
def cancel(self):
self.current_task_state.status = 'cancelled'
self.current_task_state.save()
self.status = 'cancelled'
self.save()
def finish(self):
self.status = 'approved'
self.save()
if self.current_task_state:
self.current_task_state.page_revision.publish()
else:
self.page.get_latest_revision().publish()
class Meta:
verbose_name = _('Workflow state')
verbose_name_plural = _('Workflow states')
constraints = [
models.UniqueConstraint(fields=['page'], condition=Q(status='in_progress'), name='unique_in_progress_workflow')
]
class TaskState(models.Model):
@ -2587,12 +2627,13 @@ class TaskState(models.Model):
('approved', _("Approved")),
('rejected', _("Rejected")),
('skipped', _("Skipped")),
('cancelled', _("Cancelled")),
)
workflow_state = models.ForeignKey('WorkflowState', on_delete=models.CASCADE, verbose_name=_('workflow state'))
page_revision = models.ForeignKey('PageRevision', on_delete=models.CASCADE, verbose_name=_('page revision'))
task = models.ForeignKey('Task', on_delete=models.CASCADE, verbose_name=_('task'))
status = models.fields.CharField(choices=TASK_STATUS_CHOICES, blank=False, null=False, verbose_name=_("status"), max_length=50)
workflow_state = models.ForeignKey('WorkflowState', on_delete=models.CASCADE, verbose_name=_('workflow state'), related_name='task_states')
page_revision = models.ForeignKey('PageRevision', on_delete=models.CASCADE, verbose_name=_('page revision'), related_name='task_states')
task = models.ForeignKey('Task', on_delete=models.CASCADE, verbose_name=_('task'), related_name='task_states')
status = models.fields.CharField(choices=TASK_STATUS_CHOICES, blank=False, null=False, verbose_name=_("status"), max_length=50, default='in_progress')
started_at = models.DateTimeField(verbose_name=_('started at'), auto_now=True)
finished_at = models.DateTimeField(verbose_name=_('finished at'), blank=True, null=True)
content_type = models.ForeignKey(
@ -2613,7 +2654,7 @@ class TaskState(models.Model):
self.content_type = ContentType.objects.get_for_model(self)
def __str__(self):
return _("Task '{0}' on Page Revision '{1}'").format(self.workflow, self.page_revision)
return _("Task '{0}' on Page Revision '{1}': {2}").format(self.task, self.page_revision, self.status)
@cached_property
def specific(self):
@ -2637,6 +2678,24 @@ class TaskState(models.Model):
else:
return content_type.get_object_for_this_type(id=self.id)
def approve(self):
self.status = 'approved'
self.finished_at = timezone.now()
self.save()
return self
def reject(self):
self.status = 'rejected'
self.finished_at = timezone.now()
self.save()
return self
def cancel(self):
self.status = 'cancelled'
self.finished_at = timezone.now()
self.save()
return self
class Meta:
verbose_name = _('Task state')
verbose_name_plural = _('Task states')