diff --git a/river/core/classworkflowobject.py b/river/core/classworkflowobject.py index 8adbf53..2703795 100644 --- a/river/core/classworkflowobject.py +++ b/river/core/classworkflowobject.py @@ -1,6 +1,6 @@ from django.contrib import auth from django.contrib.contenttypes.models import ContentType -from django.db.models import F, Q, IntegerField, Min +from django.db.models import F, Q, Min, CharField from django.db.models.functions import Cast from django_cte import With @@ -47,12 +47,12 @@ def get_available_approvals(self, as_user): ).with_cte( those_with_max_priority ).annotate( - object_id_as_int=Cast('object_id', IntegerField()), + object_id_as_str=Cast('object_id', CharField(max_length=200)), min_priority=those_with_max_priority.col.min_priority ).filter(min_priority=F("priority")) return workflow_objects.join( - approvals_with_max_priority, object_id_as_int=workflow_objects.col.pk + approvals_with_max_priority, object_id_as_str=Cast(workflow_objects.col.pk, CharField(max_length=200)) ).with_cte( workflow_objects ).filter(transition__source_state=getattr(workflow_objects.col, self.field_name + "_id")) diff --git a/river/tests/core/test__instance_api.py b/river/tests/core/test__instance_api.py index 1cd7687..0030346 100644 --- a/river/tests/core/test__instance_api.py +++ b/river/tests/core/test__instance_api.py @@ -3,9 +3,10 @@ from hamcrest import assert_that, equal_to, has_item, has_property, raises, calling, has_length, is_not, all_of, none, has_items from river.models import TransitionApproval, PENDING, CANCELLED, APPROVED, Transition, JUMPED -from river.models.factories import UserObjectFactory, StateObjectFactory, TransitionApprovalMetaFactory, PermissionObjectFactory, WorkflowFactory, TransitionMetaFactory +from river.models.factories import UserObjectFactory, StateObjectFactory, TransitionApprovalMetaFactory, PermissionObjectFactory, WorkflowFactory, \ + TransitionMetaFactory from river.tests.matchers import has_permission, has_transition -from river.tests.models import BasicTestModel, ModelWithTwoStateFields +from river.tests.models import BasicTestModel, ModelWithTwoStateFields, ModelWithStringPrimaryKey from river.tests.models.factories import BasicTestModelObjectFactory, ModelWithTwoStateFieldsObjectFactory from river.utils.exceptions import RiverException @@ -1766,3 +1767,30 @@ def test_shouldJumpToASpecificStateWhenThereAreMultipleNextState(self): ) ) ) + + def test_shouldNotCrashWhenAModelObjectWithStringPrimaryKeyIsApproved(self): + state1 = StateObjectFactory(label="state1") + state2 = StateObjectFactory(label="state2") + + content_type = ContentType.objects.get_for_model(ModelWithStringPrimaryKey) + authorized_permission = PermissionObjectFactory(content_type=content_type) + authorized_user = UserObjectFactory(user_permissions=[authorized_permission]) + workflow = WorkflowFactory(initial_state=state1, content_type=content_type, field_name="status") + + transition_meta = TransitionMetaFactory.create( + workflow=workflow, + source_state=state1, + destination_state=state2, + ) + TransitionApprovalMetaFactory.create( + workflow=workflow, + transition_meta=transition_meta, + priority=0, + permissions=[authorized_permission] + ) + + workflow_object = ModelWithStringPrimaryKey.objects.create() + + assert_that(workflow_object.status, equal_to(state1)) + workflow_object.river.status.approve(as_user=authorized_user) + assert_that(workflow_object.status, equal_to(state2)) diff --git a/river/tests/models/__init__.py b/river/tests/models/__init__.py index dc7b1fa..9003c6e 100644 --- a/river/tests/models/__init__.py +++ b/river/tests/models/__init__.py @@ -1,3 +1,5 @@ +from uuid import uuid4 + from django.db import models from river.models.fields.state import StateField @@ -28,3 +30,8 @@ class ModelForSlowCase2(models.Model): class ModelWithTwoStateFields(models.Model): status1 = StateField() status2 = StateField() + + +class ModelWithStringPrimaryKey(models.Model): + custom_pk = models.CharField(max_length=200, primary_key=True, default=uuid4()) + status = StateField()