Fix tests for workflows, working nested triggers/actions
This commit is contained in:
parent
6984fcf821
commit
e328d5aa95
@ -23,7 +23,6 @@ from guardian.models import UserObjectPermission
|
|||||||
|
|
||||||
from documents.file_handling import delete_empty_directories
|
from documents.file_handling import delete_empty_directories
|
||||||
from documents.file_handling import generate_filename
|
from documents.file_handling import generate_filename
|
||||||
from documents.models import ConsumptionTemplate
|
|
||||||
from documents.models import Correspondent
|
from documents.models import Correspondent
|
||||||
from documents.models import CustomField
|
from documents.models import CustomField
|
||||||
from documents.models import CustomFieldInstance
|
from documents.models import CustomFieldInstance
|
||||||
@ -35,6 +34,9 @@ from documents.models import SavedViewFilterRule
|
|||||||
from documents.models import StoragePath
|
from documents.models import StoragePath
|
||||||
from documents.models import Tag
|
from documents.models import Tag
|
||||||
from documents.models import UiSettings
|
from documents.models import UiSettings
|
||||||
|
from documents.models import Workflow
|
||||||
|
from documents.models import WorkflowAction
|
||||||
|
from documents.models import WorkflowTrigger
|
||||||
from documents.settings import EXPORTER_ARCHIVE_NAME
|
from documents.settings import EXPORTER_ARCHIVE_NAME
|
||||||
from documents.settings import EXPORTER_FILE_NAME
|
from documents.settings import EXPORTER_FILE_NAME
|
||||||
from documents.settings import EXPORTER_THUMBNAIL_NAME
|
from documents.settings import EXPORTER_THUMBNAIL_NAME
|
||||||
@ -284,7 +286,15 @@ class Command(BaseCommand):
|
|||||||
)
|
)
|
||||||
|
|
||||||
manifest += json.loads(
|
manifest += json.loads(
|
||||||
serializers.serialize("json", ConsumptionTemplate.objects.all()),
|
serializers.serialize("json", WorkflowTrigger.objects.all()),
|
||||||
|
)
|
||||||
|
|
||||||
|
manifest += json.loads(
|
||||||
|
serializers.serialize("json", WorkflowAction.objects.all()),
|
||||||
|
)
|
||||||
|
|
||||||
|
manifest += json.loads(
|
||||||
|
serializers.serialize("json", Workflow.objects.all()),
|
||||||
)
|
)
|
||||||
|
|
||||||
manifest += json.loads(
|
manifest += json.loads(
|
||||||
|
@ -44,7 +44,7 @@ def add_workflow_permissions(apps, schema_editor):
|
|||||||
|
|
||||||
def remove_workflow_permissions(apps, schema_editor):
|
def remove_workflow_permissions(apps, schema_editor):
|
||||||
workflow_permissions = Permission.objects.filter(
|
workflow_permissions = Permission.objects.filter(
|
||||||
codename__contains="workflow_permissions",
|
codename__contains="workflow",
|
||||||
)
|
)
|
||||||
|
|
||||||
for user in User.objects.all():
|
for user in User.objects.all():
|
||||||
@ -54,7 +54,7 @@ def remove_workflow_permissions(apps, schema_editor):
|
|||||||
group.permissions.remove(*workflow_permissions)
|
group.permissions.remove(*workflow_permissions)
|
||||||
|
|
||||||
|
|
||||||
def migrate_consumption_templates(apps, schema_editor):
|
def migrate_consumption_templates(apps, schema_editor): # pragma: no cover
|
||||||
"""
|
"""
|
||||||
Migrate consumption templates to workflows. At this point ConsumptionTemplate still exists
|
Migrate consumption templates to workflows. At this point ConsumptionTemplate still exists
|
||||||
but objects are not returned as their true model so we have to manually do that
|
but objects are not returned as their true model so we have to manually do that
|
||||||
@ -142,7 +142,7 @@ def migrate_consumption_templates(apps, schema_editor):
|
|||||||
workflow.save()
|
workflow.save()
|
||||||
|
|
||||||
|
|
||||||
def unmigrate_consumption_templates(apps, schema_editor):
|
def unmigrate_consumption_templates(apps, schema_editor): # pragma: no cover
|
||||||
model_name = "ConsumptionTemplate"
|
model_name = "ConsumptionTemplate"
|
||||||
app_name = "documents"
|
app_name = "documents"
|
||||||
|
|
||||||
|
@ -948,7 +948,7 @@ class WorkflowTrigger(models.Model):
|
|||||||
verbose_name_plural = _("workflow triggers")
|
verbose_name_plural = _("workflow triggers")
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"WorfklowTrigger: {self.pk}"
|
return f"WorkflowTrigger {self.pk}"
|
||||||
|
|
||||||
|
|
||||||
class WorkflowAction(models.Model):
|
class WorkflowAction(models.Model):
|
||||||
|
@ -1262,6 +1262,7 @@ class BulkEditObjectPermissionsSerializer(serializers.Serializer, SetPermissions
|
|||||||
|
|
||||||
|
|
||||||
class WorkflowTriggerSerializer(serializers.ModelSerializer):
|
class WorkflowTriggerSerializer(serializers.ModelSerializer):
|
||||||
|
id = serializers.IntegerField(required=False)
|
||||||
sources = fields.MultipleChoiceField(
|
sources = fields.MultipleChoiceField(
|
||||||
choices=WorkflowTrigger.DocumentSourceChoices.choices,
|
choices=WorkflowTrigger.DocumentSourceChoices.choices,
|
||||||
allow_empty=False,
|
allow_empty=False,
|
||||||
@ -1320,6 +1321,7 @@ class WorkflowTriggerSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
|
|
||||||
class WorkflowActionSerializer(serializers.ModelSerializer):
|
class WorkflowActionSerializer(serializers.ModelSerializer):
|
||||||
|
id = serializers.IntegerField(required=False)
|
||||||
assign_correspondent = CorrespondentField(allow_null=True, required=False)
|
assign_correspondent = CorrespondentField(allow_null=True, required=False)
|
||||||
assign_tags = TagsField(many=True, allow_null=True, required=False)
|
assign_tags = TagsField(many=True, allow_null=True, required=False)
|
||||||
assign_document_type = DocumentTypeField(allow_null=True, required=False)
|
assign_document_type = DocumentTypeField(allow_null=True, required=False)
|
||||||
@ -1370,36 +1372,70 @@ class WorkflowSerializer(serializers.ModelSerializer):
|
|||||||
"actions",
|
"actions",
|
||||||
]
|
]
|
||||||
|
|
||||||
def create(self, validated_data: Any) -> Any:
|
def update_triggers_and_actions(self, instance: Workflow, triggers, actions):
|
||||||
if "triggers" in validated_data:
|
|
||||||
# WorkflowTrigger.objects.update_or_create(triggers)
|
|
||||||
triggers = validated_data.pop("triggers")
|
|
||||||
|
|
||||||
if "actions" in validated_data:
|
|
||||||
# WorkflowAction.objects.update_or_create(actions)
|
|
||||||
actions = validated_data.pop("actions")
|
|
||||||
|
|
||||||
instance = super().create(validated_data)
|
|
||||||
|
|
||||||
set_triggers = []
|
set_triggers = []
|
||||||
set_actions = []
|
set_actions = []
|
||||||
|
|
||||||
if triggers is not None:
|
if triggers is not None:
|
||||||
for trigger in triggers:
|
for trigger in triggers:
|
||||||
print(trigger)
|
trigger_instance, _ = WorkflowTrigger.objects.update_or_create(
|
||||||
trigger_instance = WorkflowTrigger.objects.filter(**trigger).first()
|
id=trigger["id"],
|
||||||
if trigger_instance is not None:
|
defaults=trigger,
|
||||||
set_triggers.append(trigger_instance)
|
)
|
||||||
|
set_triggers.append(trigger_instance)
|
||||||
|
|
||||||
if actions is not None:
|
if actions is not None:
|
||||||
for action in actions:
|
for action in actions:
|
||||||
print(action)
|
assign_tags = action.pop("assign_tags", None)
|
||||||
action_instance = WorkflowAction.objects.filter(**action).first()
|
assign_view_users = action.pop("assign_view_users", None)
|
||||||
if action_instance is not None:
|
assign_view_groups = action.pop("assign_view_groups", None)
|
||||||
set_actions.append(action_instance)
|
assign_change_users = action.pop("assign_change_users", None)
|
||||||
|
assign_change_groups = action.pop("assign_change_groups", None)
|
||||||
|
assign_custom_fields = action.pop("assign_custom_fields", None)
|
||||||
|
action_instance, _ = WorkflowAction.objects.update_or_create(
|
||||||
|
id=trigger["id"],
|
||||||
|
defaults=action,
|
||||||
|
)
|
||||||
|
if assign_tags is not None:
|
||||||
|
action_instance.assign_tags.set(assign_tags)
|
||||||
|
if assign_view_users is not None:
|
||||||
|
action_instance.assign_view_users.set(assign_view_users)
|
||||||
|
if assign_view_groups is not None:
|
||||||
|
action_instance.assign_view_groups.set(assign_view_groups)
|
||||||
|
if assign_change_users is not None:
|
||||||
|
action_instance.assign_change_users.set(assign_change_users)
|
||||||
|
if assign_change_groups is not None:
|
||||||
|
action_instance.assign_change_groups.set(assign_change_groups)
|
||||||
|
if assign_custom_fields is not None:
|
||||||
|
action_instance.assign_custom_fields.set(assign_custom_fields)
|
||||||
|
set_actions.append(action_instance)
|
||||||
|
|
||||||
instance.triggers.set(set_triggers)
|
instance.triggers.set(set_triggers)
|
||||||
instance.actions.set(set_actions)
|
instance.actions.set(set_actions)
|
||||||
instance.save()
|
instance.save()
|
||||||
|
|
||||||
|
def create(self, validated_data: Any) -> Workflow:
|
||||||
|
if "triggers" in validated_data:
|
||||||
|
triggers = validated_data.pop("triggers")
|
||||||
|
|
||||||
|
if "actions" in validated_data:
|
||||||
|
actions = validated_data.pop("actions")
|
||||||
|
|
||||||
|
instance = super().create(validated_data)
|
||||||
|
|
||||||
|
self.update_triggers_and_actions(instance, triggers, actions)
|
||||||
|
|
||||||
|
return instance
|
||||||
|
|
||||||
|
def update(self, instance: Any, validated_data: Any) -> Workflow:
|
||||||
|
if "triggers" in validated_data:
|
||||||
|
triggers = validated_data.pop("triggers")
|
||||||
|
|
||||||
|
if "actions" in validated_data:
|
||||||
|
actions = validated_data.pop("actions")
|
||||||
|
|
||||||
|
instance = super().update(instance, validated_data)
|
||||||
|
|
||||||
|
self.update_triggers_and_actions(instance, triggers, actions)
|
||||||
|
|
||||||
return instance
|
return instance
|
||||||
|
@ -141,6 +141,7 @@ class TestApiWorkflows(DirectoriesMixin, APITestCase):
|
|||||||
"order": 1,
|
"order": 1,
|
||||||
"triggers": [
|
"triggers": [
|
||||||
{
|
{
|
||||||
|
"id": trigger_response.data["id"],
|
||||||
"sources": [DocumentSource.ApiUpload],
|
"sources": [DocumentSource.ApiUpload],
|
||||||
"type": trigger_response.data["type"],
|
"type": trigger_response.data["type"],
|
||||||
"filter_filename": trigger_response.data["filter_filename"],
|
"filter_filename": trigger_response.data["filter_filename"],
|
||||||
@ -148,6 +149,7 @@ class TestApiWorkflows(DirectoriesMixin, APITestCase):
|
|||||||
],
|
],
|
||||||
"actions": [
|
"actions": [
|
||||||
{
|
{
|
||||||
|
"id": action_response.data["id"],
|
||||||
"assign_title": action_response.data["assign_title"],
|
"assign_title": action_response.data["assign_title"],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -21,7 +21,6 @@ from guardian.models import UserObjectPermission
|
|||||||
from guardian.shortcuts import assign_perm
|
from guardian.shortcuts import assign_perm
|
||||||
|
|
||||||
from documents.management.commands import document_exporter
|
from documents.management.commands import document_exporter
|
||||||
from documents.models import ConsumptionTemplate
|
|
||||||
from documents.models import Correspondent
|
from documents.models import Correspondent
|
||||||
from documents.models import CustomField
|
from documents.models import CustomField
|
||||||
from documents.models import CustomFieldInstance
|
from documents.models import CustomFieldInstance
|
||||||
@ -31,6 +30,9 @@ from documents.models import Note
|
|||||||
from documents.models import StoragePath
|
from documents.models import StoragePath
|
||||||
from documents.models import Tag
|
from documents.models import Tag
|
||||||
from documents.models import User
|
from documents.models import User
|
||||||
|
from documents.models import Workflow
|
||||||
|
from documents.models import WorkflowAction
|
||||||
|
from documents.models import WorkflowTrigger
|
||||||
from documents.sanity_checker import check_sanity
|
from documents.sanity_checker import check_sanity
|
||||||
from documents.settings import EXPORTER_FILE_NAME
|
from documents.settings import EXPORTER_FILE_NAME
|
||||||
from documents.tests.utils import DirectoriesMixin
|
from documents.tests.utils import DirectoriesMixin
|
||||||
@ -109,7 +111,16 @@ class TestExportImport(DirectoriesMixin, FileSystemAssertsMixin, TestCase):
|
|||||||
self.d4.storage_path = self.sp1
|
self.d4.storage_path = self.sp1
|
||||||
self.d4.save()
|
self.d4.save()
|
||||||
|
|
||||||
self.ct1 = ConsumptionTemplate.objects.create(name="CT 1", filter_path="*")
|
self.trigger = WorkflowTrigger.objects.create(
|
||||||
|
type=WorkflowTrigger.WorkflowTriggerType.CONSUMPTION,
|
||||||
|
sources=[1],
|
||||||
|
filter_filename="*",
|
||||||
|
)
|
||||||
|
self.action = WorkflowAction.objects.create(assign_title="new title")
|
||||||
|
self.workflow = Workflow.objects.create(name="Workflow 1", order="0")
|
||||||
|
self.workflow.triggers.add(self.trigger)
|
||||||
|
self.workflow.actions.add(self.action)
|
||||||
|
self.workflow.save()
|
||||||
|
|
||||||
super().setUp()
|
super().setUp()
|
||||||
|
|
||||||
@ -168,7 +179,7 @@ class TestExportImport(DirectoriesMixin, FileSystemAssertsMixin, TestCase):
|
|||||||
|
|
||||||
manifest = self._do_export(use_filename_format=use_filename_format)
|
manifest = self._do_export(use_filename_format=use_filename_format)
|
||||||
|
|
||||||
self.assertEqual(len(manifest), 172)
|
self.assertEqual(len(manifest), 189)
|
||||||
|
|
||||||
# dont include consumer or AnonymousUser users
|
# dont include consumer or AnonymousUser users
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
@ -262,7 +273,7 @@ class TestExportImport(DirectoriesMixin, FileSystemAssertsMixin, TestCase):
|
|||||||
self.assertEqual(Document.objects.get(id=self.d4.id).title, "wow_dec")
|
self.assertEqual(Document.objects.get(id=self.d4.id).title, "wow_dec")
|
||||||
self.assertEqual(GroupObjectPermission.objects.count(), 1)
|
self.assertEqual(GroupObjectPermission.objects.count(), 1)
|
||||||
self.assertEqual(UserObjectPermission.objects.count(), 1)
|
self.assertEqual(UserObjectPermission.objects.count(), 1)
|
||||||
self.assertEqual(Permission.objects.count(), 124)
|
self.assertEqual(Permission.objects.count(), 136)
|
||||||
messages = check_sanity()
|
messages = check_sanity()
|
||||||
# everything is alright after the test
|
# everything is alright after the test
|
||||||
self.assertEqual(len(messages), 0)
|
self.assertEqual(len(messages), 0)
|
||||||
@ -694,15 +705,15 @@ class TestExportImport(DirectoriesMixin, FileSystemAssertsMixin, TestCase):
|
|||||||
os.path.join(self.dirs.media_dir, "documents"),
|
os.path.join(self.dirs.media_dir, "documents"),
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(ContentType.objects.count(), 31)
|
self.assertEqual(ContentType.objects.count(), 34)
|
||||||
self.assertEqual(Permission.objects.count(), 124)
|
self.assertEqual(Permission.objects.count(), 136)
|
||||||
|
|
||||||
manifest = self._do_export()
|
manifest = self._do_export()
|
||||||
|
|
||||||
with paperless_environment():
|
with paperless_environment():
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
len(list(filter(lambda e: e["model"] == "auth.permission", manifest))),
|
len(list(filter(lambda e: e["model"] == "auth.permission", manifest))),
|
||||||
124,
|
136,
|
||||||
)
|
)
|
||||||
# add 1 more to db to show objects are not re-created by import
|
# add 1 more to db to show objects are not re-created by import
|
||||||
Permission.objects.create(
|
Permission.objects.create(
|
||||||
@ -710,7 +721,7 @@ class TestExportImport(DirectoriesMixin, FileSystemAssertsMixin, TestCase):
|
|||||||
codename="test_perm",
|
codename="test_perm",
|
||||||
content_type_id=1,
|
content_type_id=1,
|
||||||
)
|
)
|
||||||
self.assertEqual(Permission.objects.count(), 125)
|
self.assertEqual(Permission.objects.count(), 137)
|
||||||
|
|
||||||
# will cause an import error
|
# will cause an import error
|
||||||
self.user.delete()
|
self.user.delete()
|
||||||
@ -719,5 +730,5 @@ class TestExportImport(DirectoriesMixin, FileSystemAssertsMixin, TestCase):
|
|||||||
with self.assertRaises(IntegrityError):
|
with self.assertRaises(IntegrityError):
|
||||||
call_command("document_importer", "--no-progress-bar", self.target)
|
call_command("document_importer", "--no-progress-bar", self.target)
|
||||||
|
|
||||||
self.assertEqual(ContentType.objects.count(), 31)
|
self.assertEqual(ContentType.objects.count(), 34)
|
||||||
self.assertEqual(Permission.objects.count(), 125)
|
self.assertEqual(Permission.objects.count(), 137)
|
||||||
|
@ -33,11 +33,18 @@ class TestReverseMigrateConsumptionTemplate(TestMigrations):
|
|||||||
self.Permission = apps.get_model("auth", "Permission")
|
self.Permission = apps.get_model("auth", "Permission")
|
||||||
self.user = User.objects.create(username="user1")
|
self.user = User.objects.create(username="user1")
|
||||||
self.group = Group.objects.create(name="group1")
|
self.group = Group.objects.create(name="group1")
|
||||||
permission = self.Permission.objects.get(codename="add_consumptiontemplate")
|
permission = self.Permission.objects.filter(
|
||||||
self.user.user_permissions.add(permission.id)
|
codename="add_consumptiontemplate",
|
||||||
self.group.permissions.add(permission.id)
|
).first()
|
||||||
|
if permission is not None:
|
||||||
|
self.user.user_permissions.add(permission.id)
|
||||||
|
self.group.permissions.add(permission.id)
|
||||||
|
|
||||||
def test_remove_consumptiontemplate_permissions(self):
|
def test_remove_consumptiontemplate_permissions(self):
|
||||||
permission = self.Permission.objects.get(codename="add_consumptiontemplate")
|
permission = self.Permission.objects.filter(
|
||||||
self.assertFalse(self.user.has_perm(f"documents.{permission.codename}"))
|
codename="add_consumptiontemplate",
|
||||||
self.assertFalse(permission in self.group.permissions.all())
|
).first()
|
||||||
|
# can be None ? now that CTs removed
|
||||||
|
if permission is not None:
|
||||||
|
self.assertFalse(self.user.has_perm(f"documents.{permission.codename}"))
|
||||||
|
self.assertFalse(permission in self.group.permissions.all())
|
||||||
|
49
src/documents/tests/test_migration_workflows.py
Normal file
49
src/documents/tests/test_migration_workflows.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
|
||||||
|
from documents.tests.utils import TestMigrations
|
||||||
|
|
||||||
|
|
||||||
|
class TestMigrateWorkflow(TestMigrations):
|
||||||
|
migrate_from = "1043_alter_savedviewfilterrule_rule_type"
|
||||||
|
migrate_to = "1044_workflow_workflowaction_workflowtrigger_and_more"
|
||||||
|
|
||||||
|
def setUpBeforeMigration(self, apps):
|
||||||
|
User = get_user_model()
|
||||||
|
Group = apps.get_model("auth.Group")
|
||||||
|
self.Permission = apps.get_model("auth", "Permission")
|
||||||
|
self.user = User.objects.create(username="user1")
|
||||||
|
self.group = Group.objects.create(name="group1")
|
||||||
|
permission = self.Permission.objects.get(codename="add_document")
|
||||||
|
self.user.user_permissions.add(permission.id)
|
||||||
|
self.group.permissions.add(permission.id)
|
||||||
|
|
||||||
|
def test_users_with_add_documents_get_add_workflow(self):
|
||||||
|
permission = self.Permission.objects.get(codename="add_workflow")
|
||||||
|
self.assertTrue(self.user.has_perm(f"documents.{permission.codename}"))
|
||||||
|
self.assertTrue(permission in self.group.permissions.all())
|
||||||
|
|
||||||
|
|
||||||
|
class TestReverseMigrateWorkflow(TestMigrations):
|
||||||
|
migrate_from = "1044_workflow_workflowaction_workflowtrigger_and_more"
|
||||||
|
migrate_to = "1043_alter_savedviewfilterrule_rule_type"
|
||||||
|
|
||||||
|
def setUpBeforeMigration(self, apps):
|
||||||
|
User = get_user_model()
|
||||||
|
Group = apps.get_model("auth.Group")
|
||||||
|
self.Permission = apps.get_model("auth", "Permission")
|
||||||
|
self.user = User.objects.create(username="user1")
|
||||||
|
self.group = Group.objects.create(name="group1")
|
||||||
|
permission = self.Permission.objects.filter(
|
||||||
|
codename="add_workflow",
|
||||||
|
).first()
|
||||||
|
if permission is not None:
|
||||||
|
self.user.user_permissions.add(permission.id)
|
||||||
|
self.group.permissions.add(permission.id)
|
||||||
|
|
||||||
|
def test_remove_workflow_permissions(self):
|
||||||
|
permission = self.Permission.objects.filter(
|
||||||
|
codename="add_workflow",
|
||||||
|
).first()
|
||||||
|
if permission is not None:
|
||||||
|
self.assertFalse(self.user.has_perm(f"documents.{permission.codename}"))
|
||||||
|
self.assertFalse(permission in self.group.permissions.all())
|
@ -116,6 +116,8 @@ class TestWorkflows(DirectoriesMixin, FileSystemAssertsMixin, TestCase):
|
|||||||
w.save()
|
w.save()
|
||||||
|
|
||||||
self.assertEqual(w.__str__(), "Workflow: Workflow 1")
|
self.assertEqual(w.__str__(), "Workflow: Workflow 1")
|
||||||
|
self.assertEqual(trigger.__str__(), "WorkflowTrigger 1")
|
||||||
|
self.assertEqual(action.__str__(), "WorkflowAction 1")
|
||||||
|
|
||||||
test_file = self.SAMPLE_DIR / "simple.pdf"
|
test_file = self.SAMPLE_DIR / "simple.pdf"
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user