oarepo-workflows 2.0.0.dev7__tar.gz → 2.0.0.dev9__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/PKG-INFO +1 -1
  2. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/__init__.py +3 -3
  3. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/base.py +2 -2
  4. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/model/presets/services/records/permission_policy.py +4 -11
  5. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/services/components/workflow.py +8 -0
  6. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/services/permissions/__init__.py +2 -2
  7. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/services/permissions/generators.py +49 -0
  8. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/services/permissions/record_permission_policy.py +12 -17
  9. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/.gitignore +0 -0
  10. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/LICENSE +0 -0
  11. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/README.md +0 -0
  12. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/errors.py +0 -0
  13. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/ext.py +0 -0
  14. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/ext_config.py +0 -0
  15. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/initial_config.py +0 -0
  16. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/model/__init__.py +0 -0
  17. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/model/presets/__init__.py +0 -0
  18. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/model/presets/records/__init__.py +0 -0
  19. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/model/presets/records/draft_record.py +0 -0
  20. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/model/presets/records/parent_record.py +0 -0
  21. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/model/presets/records/parent_record_metadata.py +0 -0
  22. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/model/presets/records/record.py +0 -0
  23. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/model/presets/records/workflows_mapping.py +0 -0
  24. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/model/presets/services/__init__.py +0 -0
  25. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/model/presets/services/records/__init__.py +0 -0
  26. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/model/presets/services/records/parent_record_schema.py +0 -0
  27. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/model/presets/services/records/record_schema.py +0 -0
  28. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/model/presets/services/records/service_config.py +0 -0
  29. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/proxies.py +0 -0
  30. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/records/__init__.py +0 -0
  31. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/records/systemfields/__init__.py +0 -0
  32. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/records/systemfields/state.py +0 -0
  33. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/records/systemfields/workflow.py +0 -0
  34. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/requests/__init__.py +0 -0
  35. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/requests/events.py +0 -0
  36. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/requests/generators/__init__.py +0 -0
  37. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/requests/generators/auto.py +0 -0
  38. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/requests/generators/conditionals.py +0 -0
  39. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/requests/generators/multiple_entities.py +0 -0
  40. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/requests/generators/recipient_generator.py +0 -0
  41. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/requests/permissions.py +0 -0
  42. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/requests/policy.py +0 -0
  43. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/requests/requests.py +0 -0
  44. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/resolvers/__init__.py +0 -0
  45. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/resolvers/auto_approve/__init__.py +0 -0
  46. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/resolvers/multiple_entities/__init__.py +0 -0
  47. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/services/__init__.py +0 -0
  48. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/services/auto_approve/__init__.py +0 -0
  49. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/services/components/__init__.py +0 -0
  50. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/services/multiple_entities/__init__.py +0 -0
  51. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/services/permissions/workflow_permissions.py +0 -0
  52. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/services/results.py +0 -0
  53. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/oarepo_workflows/services/uow.py +0 -0
  54. {oarepo_workflows-2.0.0.dev7 → oarepo_workflows-2.0.0.dev9}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oarepo-workflows
3
- Version: 2.0.0.dev7
3
+ Version: 2.0.0.dev9
4
4
  Summary: OARepo module allowing record workflow functionality
5
5
  Project-URL: Homepage, https://github.com/oarepo/oarepo-workflows
6
6
  Author-email: Ronald Krist <krist@cesnet.cz>
@@ -13,7 +13,7 @@ from oarepo_workflows.services.permissions import (
13
13
  FromRecordWorkflow,
14
14
  IfInState,
15
15
  WorkflowPermission,
16
- WorkflowRecordPermissionPolicy,
16
+ WorkflowRecordPermissionPolicyMixin,
17
17
  )
18
18
 
19
19
  from .base import Workflow
@@ -27,7 +27,7 @@ from .requests import (
27
27
  WorkflowTransitions,
28
28
  )
29
29
 
30
- __version__ = "2.0.0dev7"
30
+ __version__ = "2.0.0dev9"
31
31
  """Version of the library."""
32
32
 
33
33
 
@@ -38,7 +38,7 @@ __all__ = (
38
38
  "IfInState",
39
39
  "Workflow",
40
40
  "WorkflowPermission",
41
- "WorkflowRecordPermissionPolicy",
41
+ "WorkflowRecordPermissionPolicyMixin",
42
42
  "WorkflowRequest",
43
43
  "WorkflowRequestEscalation",
44
44
  "WorkflowRequestPolicy",
@@ -12,7 +12,7 @@ from __future__ import annotations
12
12
  import dataclasses
13
13
  from typing import TYPE_CHECKING, Any, Protocol
14
14
 
15
- from . import WorkflowRecordPermissionPolicy
15
+ from . import WorkflowRecordPermissionPolicyMixin
16
16
  from .requests import WorkflowRequestPolicy
17
17
  from .services.permissions import DefaultWorkflowPermissions
18
18
 
@@ -69,7 +69,7 @@ class Workflow:
69
69
 
70
70
  This is just a sanity check to raise an error as soon as possible.
71
71
  """
72
- if issubclass(self.permission_policy_cls, WorkflowRecordPermissionPolicy):
72
+ if issubclass(self.permission_policy_cls, WorkflowRecordPermissionPolicyMixin):
73
73
  raise TypeError(
74
74
  f"Workflow permission policy {self.permission_policy_cls} is not a "
75
75
  f"subclass of WorkflowRecordPermissionPolicy."
@@ -17,18 +17,16 @@ from __future__ import annotations
17
17
 
18
18
  from typing import TYPE_CHECKING, Any, override
19
19
 
20
- from invenio_records_permissions.policies.records import RecordPermissionPolicy
21
- from oarepo_model.customizations import Customization, ReplaceBaseClass
20
+ from oarepo_model.customizations.prepend_mixin import PrependMixin
22
21
  from oarepo_model.presets import Preset
23
22
 
24
- from oarepo_workflows.services.permissions.record_permission_policy import (
25
- WorkflowRecordPermissionPolicy,
26
- )
23
+ from oarepo_workflows.services.permissions import WorkflowRecordPermissionPolicyMixin
27
24
 
28
25
  if TYPE_CHECKING:
29
26
  from collections.abc import Generator
30
27
 
31
28
  from oarepo_model.builder import InvenioModelBuilder
29
+ from oarepo_model.customizations import Customization
32
30
  from oarepo_model.model import InvenioModel
33
31
 
34
32
 
@@ -44,9 +42,4 @@ class WorkflowsPermissionPolicyPreset(Preset):
44
42
  model: InvenioModel,
45
43
  dependencies: dict[str, Any],
46
44
  ) -> Generator[Customization]:
47
- yield ReplaceBaseClass(
48
- "PermissionPolicy",
49
- RecordPermissionPolicy,
50
- WorkflowRecordPermissionPolicy,
51
- subclass=True,
52
- )
45
+ yield PrependMixin("PermissionPolicy", WorkflowRecordPermissionPolicyMixin)
@@ -14,6 +14,9 @@ from typing import TYPE_CHECKING, Any, override
14
14
  from invenio_records_resources.services.records.components.base import ServiceComponent
15
15
  from oarepo_runtime.typing import require_kwargs
16
16
 
17
+ from oarepo_workflows import current_oarepo_workflows
18
+ from oarepo_workflows.errors import InvalidWorkflowError
19
+
17
20
  if TYPE_CHECKING:
18
21
  from flask_principal import Identity
19
22
  from invenio_drafts_resources.records import Record
@@ -50,4 +53,9 @@ class WorkflowComponent(ServiceComponent):
50
53
  workflow_id = data["parent"]["workflow"]
51
54
  except KeyError:
52
55
  return
56
+ if workflow_id not in current_oarepo_workflows.workflow_by_code:
57
+ raise InvalidWorkflowError(
58
+ f"Workflow {workflow_id} does not exist in the configuration.",
59
+ record=data or record,
60
+ )
53
61
  record.parent.workflow = workflow_id # type: ignore[reportAttributeAccessIssue, reportOptionalMemberAccess]
@@ -10,7 +10,7 @@
10
10
  from __future__ import annotations
11
11
 
12
12
  from .generators import FromRecordWorkflow, IfInState, WorkflowPermission
13
- from .record_permission_policy import WorkflowRecordPermissionPolicy
13
+ from .record_permission_policy import WorkflowRecordPermissionPolicyMixin
14
14
  from .workflow_permissions import DefaultWorkflowPermissions
15
15
 
16
16
  __all__ = (
@@ -18,5 +18,5 @@ __all__ = (
18
18
  "FromRecordWorkflow",
19
19
  "IfInState",
20
20
  "WorkflowPermission",
21
- "WorkflowRecordPermissionPolicy",
21
+ "WorkflowRecordPermissionPolicyMixin",
22
22
  )
@@ -37,6 +37,55 @@ if TYPE_CHECKING:
37
37
  from oarepo_workflows.services.permissions import DefaultWorkflowPermissions
38
38
 
39
39
 
40
+ def query_filters_from_all_workflows(action: str, **context: Any) -> list[dsl.query.Query]:
41
+ """Get query filters to match records depending on the records' workflow."""
42
+ workflows = current_oarepo_workflows.record_workflows
43
+ queries = []
44
+ for workflow in workflows:
45
+ q_in_workflow = dsl.Q("term", **{"parent.workflow": workflow.code})
46
+ workflow_filters = workflow.permissions(action, **context).query_filters
47
+ if not workflow_filters:
48
+ workflow_filters = [dsl.Q("match_none")]
49
+ query = reduce(lambda f1, f2: f1 | f2, workflow_filters) & q_in_workflow
50
+ queries.append(query)
51
+ return [q for q in queries if q]
52
+
53
+
54
+ class InAnyWorkflow(Generator):
55
+ """InAnyWorkflow generator.
56
+
57
+ Warning: if some workflow uses generators with excludes, they can clash with needs in different workflows leading
58
+ to the generator excluding users even though they are allowed in the workflow without the excludes generator.
59
+ This is due to how flask allows() is implemented.
60
+
61
+ Eg. If workflow 1 defines provides need for User 1 and Workflow 2 excludes User 1,
62
+ the generator will treat user 1 as excluded despite being allowed in the first workflow.
63
+ """
64
+
65
+ def __init__(self, action: str) -> None:
66
+ """Construct the generator."""
67
+ self._action = action
68
+
69
+ @override
70
+ def needs(self, **context: Any) -> Sequence[Need]:
71
+ ret = set()
72
+ for workflow in current_oarepo_workflows.record_workflows:
73
+ ret |= set(workflow.permissions(self._action, **context).needs)
74
+ return list(ret)
75
+
76
+ @override
77
+ def excludes(self, **context: Any) -> Sequence[Need]:
78
+ ret = set()
79
+ for workflow in current_oarepo_workflows.record_workflows:
80
+ ret |= set(workflow.permissions(self._action, **context).excludes)
81
+ return list(ret)
82
+
83
+ @override
84
+ def query_filter(self, **context: Any) -> dsl.query.Query:
85
+ queries = query_filters_from_all_workflows(self._action, **context)
86
+ return reduce(operator.or_, queries)
87
+
88
+
40
89
  class FromRecordWorkflow(Generator):
41
90
  """Permission delegating check to workflow.
42
91
 
@@ -9,31 +9,34 @@
9
9
 
10
10
  from __future__ import annotations
11
11
 
12
- from functools import reduce
13
12
  from typing import TYPE_CHECKING
14
13
 
15
- from invenio_records_permissions import RecordPermissionPolicy
16
14
  from invenio_records_permissions.generators import (
17
15
  AnyUser,
16
+ AuthenticatedUser,
18
17
  SystemProcess,
19
18
  )
20
- from invenio_search.engine import dsl
21
19
 
22
- from ...proxies import current_oarepo_workflows
23
- from .generators import FromRecordWorkflow
20
+ from .generators import FromRecordWorkflow, SameAs, query_filters_from_all_workflows
24
21
 
25
22
  if TYPE_CHECKING:
23
+ from invenio_records_permissions import RecordPermissionPolicy as InvenioRecordPermissionPolicy
26
24
  from opensearch_dsl.query import Query
25
+ else:
26
+ InvenioRecordPermissionPolicy = object
27
27
 
28
28
 
29
- class WorkflowRecordPermissionPolicy(RecordPermissionPolicy):
29
+ class WorkflowRecordPermissionPolicyMixin(InvenioRecordPermissionPolicy):
30
30
  """Permission policy to be used in permission presets directly on RecordServiceConfig.permission_policy_cls.
31
31
 
32
32
  Do not use this class in Workflow constructor.
33
33
  """
34
34
 
35
35
  can_commit_files = (FromRecordWorkflow("commit_files"),)
36
- can_create = (FromRecordWorkflow("create"),)
36
+ can_create = (
37
+ SystemProcess(),
38
+ AuthenticatedUser(),
39
+ )
37
40
  can_create_files = (FromRecordWorkflow("create_files"),)
38
41
  can_delete = (FromRecordWorkflow("delete"),)
39
42
  can_delete_draft = (FromRecordWorkflow("delete_draft"),)
@@ -116,6 +119,7 @@ class WorkflowRecordPermissionPolicy(RecordPermissionPolicy):
116
119
  can_remove_record = (FromRecordWorkflow("remove_record"),)
117
120
  can_review = (FromRecordWorkflow("review"),)
118
121
  can_view = (FromRecordWorkflow("view"),)
122
+ can_view_deposit_page = (SameAs("can_create"),)
119
123
 
120
124
  @property
121
125
  def query_filters(self) -> list[Query]:
@@ -127,13 +131,4 @@ class WorkflowRecordPermissionPolicy(RecordPermissionPolicy):
127
131
  "read_all_records",
128
132
  ):
129
133
  return super().query_filters # type: ignore[no-any-return]
130
- workflows = current_oarepo_workflows.record_workflows
131
- queries = []
132
- for workflow in workflows:
133
- q_in_workflow = dsl.Q("term", **{"parent.workflow": workflow.code})
134
- workflow_filters = workflow.permissions(self.action, **self.over).query_filters
135
- if not workflow_filters:
136
- workflow_filters = [dsl.Q("match_none")]
137
- query = reduce(lambda f1, f2: f1 | f2, workflow_filters) & q_in_workflow
138
- queries.append(query)
139
- return [q for q in queries if q]
134
+ return query_filters_from_all_workflows(self.action, **self.over)