Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tp2000 1471 task workflow #1298

Draft
wants to merge 57 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
340439c
App initial commit.
paulpepper-trade Aug 29, 2024
301644a
TP2000-1472 Revise task-related models (#1288)
dalecannon Sep 19, 2024
ee4871d
TP2000-1473 Register task-related models in admin site (#1289)
dalecannon Sep 20, 2024
9faac8b
Merge branch 'master' into TP2000-1471--task-workflow
paulpepper-trade Sep 20, 2024
0595097
Merge branch 'master' into TP2000-1471--task-workflow
dalecannon Oct 29, 2024
de2733c
Implement prototype UI for tasks (#1308)
dalecannon Oct 31, 2024
ddfea35
TP2000-1487: Create Subtask Form (#1319)
marya-shariq Nov 11, 2024
ead85bc
TP2000-1540, TP2000-1541, TP2000-1546 & TP2000-1553 queues, workflows…
paulpepper-trade Nov 12, 2024
4d7dda9
TP2000-1543 Prototype workflow template detail view (#1322)
dalecannon Nov 12, 2024
77760e5
PR template tweaks
paulpepper-trade Nov 12, 2024
80c0b80
Merge branch 'master' into TP2000-1471--task-workflow
paulpepper-trade Nov 12, 2024
5ec8f38
Black formatting
paulpepper-trade Nov 12, 2024
d1d18ed
TP2000-1545 Add task template reordering capability to workflow temp…
dalecannon Nov 14, 2024
84e3c16
TP2000-48 & TP2000-1549 Task template create and detail views (#1326)
paulpepper-trade Nov 15, 2024
f2bead0
TP2000-1551 Task template update views and forms (#1327)
paulpepper-trade Nov 15, 2024
d103846
Fix typo in macro import
paulpepper-trade Nov 15, 2024
d0466d4
Merge branch 'master' into TP2000-1471--task-workflow
paulpepper-trade Nov 15, 2024
01db672
TP2000-1569 Embellish create subtask journey (#1325)
LaurenMullally Nov 18, 2024
baf7f61
Add support view support for task workflow deletion (#1329)
paulpepper-trade Nov 18, 2024
f4f351c
TP2000-1544 Prototype workflow template create & update views (#1328)
dalecannon Nov 18, 2024
bc787f8
Fix double quotes lint error from create subtask form pr
LaurenMullally Nov 18, 2024
a28e7bd
TP2000-1573 Implement workflow template delete view (#1330)
dalecannon Nov 19, 2024
2ff7858
Tp 2000 1489 delete subtask (#1332)
marya-shariq Nov 21, 2024
e9a4546
deleted comments
marya-shariq Nov 21, 2024
993ec64
TP2000-1488 Edit Subtasks (#1334)
LaurenMullally Nov 25, 2024
f55394a
Tp2000 1589 - temporary list views tile (#1338)
marya-shariq Nov 25, 2024
5884cfc
Merge branch 'master' into TP2000-1471--task-workflow
paulpepper-trade Nov 25, 2024
7dfe059
TP2000-1590 TaskWorkflow summary info support (#1337)
paulpepper-trade Nov 25, 2024
997d36a
Update TaskWorkflowTemplate.create_task_workflow() method and unit te…
dalecannon Nov 28, 2024
4540d83
TP2000-1556 Implement workflow create view (#1340)
dalecannon Nov 28, 2024
2ea9f5c
TP2000-1555 Implement workflow detail view (#1341)
dalecannon Nov 28, 2024
708944c
TP2000-1602 Implement workflow delete view (#1342)
dalecannon Nov 28, 2024
02044ba
Factor out workflow item management helper functions into view mixin …
dalecannon Dec 4, 2024
2bafa60
Merge branch 'master' into TP2000-1471--task-workflow
paulpepper-trade Dec 5, 2024
442fd3e
Tp2000 1592 workflow template list view (#1348)
marya-shariq Dec 5, 2024
363bced
TP2000-1582 Enable customisable queue field name on QueueItem subcla…
dalecannon Dec 6, 2024
ec10b14
Include user param in form.save() call (#1350)
paulpepper-trade Dec 6, 2024
3e67a87
Merge branch 'master' into TP2000-1471--task-workflow
paulpepper-trade Dec 9, 2024
821d5e8
TP2000-1557 Implement workflow edit view (#1347)
dalecannon Dec 10, 2024
d9937d1
TP2000-1580 Task workflow combined list view pt2 (#1353)
paulpepper-trade Dec 10, 2024
31cafe9
Merge branch 'master' into TP2000-1471--task-workflow
paulpepper-trade Dec 10, 2024
206cc7d
TP2000-1615 Various errors (#1357)
paulpepper-trade Dec 17, 2024
ab3854f
Tp2000 1594 ordering of workflow templates list view (#1356)
marya-shariq Dec 17, 2024
10f14de
Merge branch 'master' into TP2000-1471--task-workflow
paulpepper-trade Dec 17, 2024
dd663ac
Add migrations.
paulpepper-trade Dec 17, 2024
5824196
Fix failing test (#1362)
paulpepper-trade Dec 17, 2024
4f054b6
Fix UI bug (#1364)
paulpepper-trade Dec 18, 2024
d1c3505
TP2000-1600 Add Subtask filter to Task admin view (#1344)
LaurenMullally Dec 19, 2024
1f94a81
Merge branch 'master' into TP2000-1471--task-workflow
paulpepper-trade Dec 23, 2024
82a1f69
Merge branch 'master' into TP2000-1471--task-workflow
paulpepper-trade Jan 2, 2025
9b99475
Add simple TaskWorkflowAdmin view (#1373)
LaurenMullally Jan 3, 2025
755fac6
Tp2000 1542 workflow template admin support (#1374)
marya-shariq Jan 9, 2025
69e65e5
Merge branch 'master' into TP2000-1471--task-workflow
paulpepper-trade Jan 10, 2025
c6c0a43
TP2000-1652 Enhance workflow, workflow template admin views (#1381)
dalecannon Jan 15, 2025
b60a3c9
Merge branch 'master' into TP2000-1471--task-workflow
paulpepper-trade Jan 15, 2025
6d9e368
TP2000-1658 Correct usage of select_for_update() in QueueItem instan…
dalecannon Jan 16, 2025
676edc5
Merge branch 'master' into TP2000-1471--task-workflow
paulpepper-trade Jan 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# TP-??? Your PR title here
# TP2000-??? Your PR title here
<!---
<--- 50 characters
* Include the JIRA ticket number, eg TP-123, to automatically link.
* Use 50 characters maximum.
* Do not end with a full-stop.
Expand All @@ -22,12 +23,12 @@ What is this PR doing, e.g. implementations, algorithms, etc.?
--->

<!---
Optionally let reviewers know they need to run migrations or update dependencies before
Let reviewers know they need to run migrations or update dependencies before
testing by adding the following section:
## Checklist
- Requires migrations?
- Requires dependency updates?
--->
## Checklist
- Requires migrations? Yes / No
- Requires dependency updates? Yes / No

<!---
Links to relevant material
Expand Down
24 changes: 24 additions & 0 deletions common/jinja2/common/homepage.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,30 @@
</article>
{% endif %}

<article class="masonry-card">
<h3 class="govuk-heading-m">Tasks and Workflows - TEST ONLY</h3>
<p class="govuk-body">
<a href="{{ url('workflow:task-ui-list') }}"
class="govuk-link"
>Tasks</a>
</p>
<p class="govuk-body"></p>
<a href="{{ url('workflow:task-workflow-ui-list') }}"
class="govuk-link"
>Workflows</a>
</p>
<p class="govuk-body"></p>
<a href="{{ url('workflow:task-and-workflow-ui-list') }}"
class="govuk-link"
>Tasks and Workflows</a>
</p>
<p class="govuk-body"></p>
<a href="{{ url('workflow:task-workflow-template-ui-list') }}"
class="govuk-link"
>Workflow templates</a>
</p>
</article>

<article class="masonry-card">
<h3 class="govuk-heading-m">Resources</h3>
<p class="govuk-body">
Expand Down
2 changes: 2 additions & 0 deletions common/jinja2/layouts/detail.jinja
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
{% extends "layouts/layout.jinja" %}

{% from "components/tabs/macro.njk" import govukTabs %}
{% from "components/breadcrumbs.jinja" import breadcrumbs %}

{% block breadcrumb %}
Expand Down
35 changes: 35 additions & 0 deletions common/models/mixins/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Mixins for models."""

from django.db import models
from django.db.models import signals


class TimestampedMixin(models.Model):
Expand All @@ -11,3 +12,37 @@ class TimestampedMixin(models.Model):

class Meta:
abstract = True


class WithSignalManagerMixin:
"""A mixin that overrides default Manager methods to send pre_save signals
for model instances."""

def bulk_create(self, objs, **kwargs) -> list:
for obj in objs:
signals.pre_save.send(sender=self.model, instance=obj)
return super().bulk_create(objs, **kwargs)


class WithSignalQuerysetMixin:
"""A mixin that overrides default QuerySet methods to send pre_save signals
for model instances."""

def update(self, **kwargs) -> int:
old_instances_map = {}
pk_list = []
for old_instance in self.iterator():
old_instances_map[old_instance.pk] = old_instance
pk_list.append(old_instance.pk)

rows_updated = super().update(**kwargs)

for new_instance in self.model.objects.filter(pk__in=pk_list):
old_instance = old_instances_map.get(new_instance.pk)
signals.pre_save.send(
sender=self.model,
instance=new_instance,
old_instance=old_instance,
)

return rows_updated
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import accessibleAutocomplete from "accessible-autocomplete";
import PropTypes from "prop-types";

function UnassignUserForm({ users }) {
const elementId = "assignments-select";
const elementName = "assignments";
const elementId = "assignees-select";
const elementName = "assignees";
const label = "Unassign user";
const hint = "Select a user to unassign";

Expand Down Expand Up @@ -66,7 +66,7 @@ UnassignUserForm.propTypes = {
PropTypes.shape({
pk: PropTypes.number.isRequired,
name: PropTypes.string.isRequired,
})
}),
),
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,20 @@ exports[`UnassignUserForm renders form 1`] = `
>
<label
className="govuk-label"
htmlFor="assignments-select"
htmlFor="assignees-select"
>
Unassign user
</label>
<div
className="govuk-hint"
id="assignments-hint"
id="assignees-hint"
>
Select a user to unassign
</div>
<select
data-testid="unassign-user-select"
id="assignments-select"
name="assignments"
id="assignees-select"
name="assignees"
required={true}
>
<option
Expand Down
1 change: 1 addition & 0 deletions common/static/common/scss/application.scss
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ $govuk-image-url-function: frontend-image-url;
@import "regulations";
@import "workbaskets";
@import "reference_documents";
@import "tasks";
@import "versions";
@import "fake-link";
@import "violations";
Expand Down
44 changes: 34 additions & 10 deletions common/tests/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import factory
from django.contrib.auth import get_user_model
from django.db.models import signals
from factory.fuzzy import FuzzyChoice
from factory.fuzzy import FuzzyText
from faker import Faker
Expand All @@ -30,7 +31,8 @@
from measures.validators import OrderNumberCaptureCode
from publishing.models import ProcessingState
from quotas.validators import QuotaEventType
from tasks.models import UserAssignment
from tasks.models import ProgressState
from tasks.models import TaskAssignee
from workbaskets.validators import WorkflowStatus

User = get_user_model()
Expand Down Expand Up @@ -1533,40 +1535,62 @@ class Meta:
model = "notifications.CrownDependenciesEnvelopeFailedNotification"


class CategoryFactory(factory.django.DjangoModelFactory):
name = factory.Faker("bs")

class Meta:
model = "tasks.Category"


class ProgressStateFactory(factory.django.DjangoModelFactory):
name = FuzzyChoice(ProgressState.State.values)

class Meta:
model = "tasks.ProgressState"
django_get_or_create = ("name",)


class TaskFactory(factory.django.DjangoModelFactory):
title = factory.Faker("sentence")
description = factory.Faker("sentence")
category = factory.SubFactory(CategoryFactory)
progress_state = factory.SubFactory(ProgressStateFactory)
workbasket = factory.SubFactory(WorkBasketFactory)
creator = factory.SubFactory(UserFactory)

class Meta:
model = "tasks.Task"


class UserAssignmentFactory(factory.django.DjangoModelFactory):
class SubTaskFactory(TaskFactory):
parent_task = factory.SubFactory(TaskFactory)


@factory.django.mute_signals(signals.pre_save)
class TaskAssigneeFactory(factory.django.DjangoModelFactory):
user = factory.SubFactory(UserFactory)
assigned_by = factory.SubFactory(UserFactory)
assignment_type = FuzzyChoice(UserAssignment.AssignmentType.values)
assignment_type = FuzzyChoice(TaskAssignee.AssignmentType.values)
task = factory.SubFactory(TaskFactory)

class Meta:
model = "tasks.UserAssignment"
model = "tasks.TaskAssignee"


class AssignedWorkBasketFactory(WorkBasketFactory):
"""Creates a workbasket which has an assigned worker and reviewer."""

@factory.post_generation
def user_assignments(self, create, extracted, **kwargs):
def create_workbasket_assignments(self, create, extracted, **kwargs):
if not create:
return

task = TaskFactory.create(workbasket=self)
UserAssignmentFactory.create(
assignment_type=UserAssignment.AssignmentType.WORKBASKET_WORKER,
TaskAssigneeFactory.create(
assignment_type=TaskAssignee.AssignmentType.WORKBASKET_WORKER,
task=task,
)
UserAssignmentFactory.create(
assignment_type=UserAssignment.AssignmentType.WORKBASKET_REVIEWER,
TaskAssigneeFactory.create(
assignment_type=TaskAssignee.AssignmentType.WORKBASKET_REVIEWER,
task=task,
)

Expand Down
39 changes: 39 additions & 0 deletions common/tests/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,45 @@ def test_make_real_edit_create_delete():
assert workbasket.tracked_models.count() == 0


@mock.patch("django.db.transaction.get_connection")
def test_tablelock_as_context_manager(mock_get_connection):
mock_cursor = mock.MagicMock()
mock_get_connection.return_value.cursor.return_value.__enter__.return_value = (
mock_cursor
)

instance = factories.TestModel1Factory.create()
model = instance._meta.model
lock = util.TableLock.EXCLUSIVE

with util.TableLock(model, lock=lock):
assert model.objects.select_for_update().get(pk=instance.pk)
mock_cursor.execute.assert_called_once_with(
f"LOCK TABLE {model._meta.db_table} IN {lock} MODE",
)


@mock.patch("django.db.transaction.get_connection")
def test_tablelock_as_decorator(mock_get_connection):
mock_cursor = mock.MagicMock()
mock_get_connection.return_value.cursor.return_value.__enter__.return_value = (
mock_cursor
)

instance = factories.TestModel1Factory.create()
model = instance._meta.model
lock = util.TableLock.EXCLUSIVE

@util.TableLock.acquire_lock(model, lock=lock)
def decorated_function():
return True

assert decorated_function()
mock_cursor.execute.assert_called_once_with(
f"LOCK TABLE {model._meta.db_table} IN {lock} MODE",
)


@pytest.mark.parametrize(
"date_range,compared_date_range,expected",
(
Expand Down
6 changes: 3 additions & 3 deletions common/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from common.views import HealthCheckView
from common.views import handler403
from common.views import handler500
from tasks.models import UserAssignment
from tasks.models import TaskAssignee
from workbaskets.validators import WorkflowStatus

pytestmark = pytest.mark.django_db
Expand Down Expand Up @@ -281,9 +281,9 @@ def test_homepage_cards_contain_expected_links(superuser_client):
def test_homepage_card_currently_working_on(status, valid_user, valid_user_client):
test_reason = "test reason"
workbasket = factories.WorkBasketFactory.create(status=status, reason=test_reason)
factories.UserAssignmentFactory.create(
factories.TaskAssigneeFactory.create(
user=valid_user,
assignment_type=UserAssignment.AssignmentType.WORKBASKET_REVIEWER,
assignment_type=TaskAssignee.AssignmentType.WORKBASKET_REVIEWER,
task__workbasket=workbasket,
)
TrackedModelCheckFactory.create(
Expand Down
Loading
Loading