Skip to content

Commit 770639d

Browse files
author
Jens Kürten
committed
Merge branch 'main' of github.com:cslab/functions-sdk-python into custom-operations
2 parents 848c3bd + 6b7928b commit 770639d

32 files changed

+1493
-179
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Functions are deeply integrated in the CIM Database Cloud Webhooks technology. T
1212

1313
Python 3.10+
1414

15-
csfunctions is build with [Pydantic 2](https://docs.pydantic.dev/latest/)
15+
csfunctions is built with [Pydantic 2](https://docs.pydantic.dev/latest/)
1616

1717
## Installation
1818
Install using pip:

csfunctions/actions/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
from .abort_and_show_error import AbortAndShowErrorAction
66
from .base import ActionNames
77
from .dummy import DummyAction
8+
from .start_workflow import StartWorkflowAction
89

9-
ActionUnion = Union[AbortAndShowErrorAction, DummyAction]
10+
ActionUnion = Union[AbortAndShowErrorAction, DummyAction, StartWorkflowAction]
1011
Action = Annotated[ActionUnion, Field(discriminator="name")]
1112

1213
__all__ = [
@@ -15,4 +16,5 @@
1516
"DummyAction",
1617
"AbortAndShowErrorAction",
1718
"ActionUnion",
19+
"StartWorkflowAction",
1820
]

csfunctions/actions/base.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
class ActionNames(str, Enum):
77
ABORT_AND_SHOW_ERROR = "abort_and_show_error"
88
DUMMY = "dummy"
9+
START_WORKFLOW = "start_workflow"
910

1011

1112
class BaseAction(BaseModel):
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
from typing import Literal, Optional
2+
3+
from pydantic import BaseModel, Field
4+
5+
from .base import ActionNames, BaseAction
6+
7+
8+
class Subject(BaseModel):
9+
subject_id: str = Field(..., description="ID of the subject, eg. a role name or personalnummer")
10+
subject_type: Literal["Person", "PCS Role", "Common Role"] = Field(
11+
..., description="Type of the subject: Person, PCS Role or Common Role"
12+
)
13+
14+
15+
class TaskConfiguration(BaseModel):
16+
task_id: str = Field(..., description="Identifier for the task")
17+
responsible: Optional[Subject] = Field(default=None, description="Responsible subject for the task")
18+
recipients: list[Subject] = Field(
19+
default_factory=list,
20+
description="List of recipients for the task (only used by information tasks)",
21+
)
22+
description: str | None = Field(
23+
default=None,
24+
description="Description of the task. If not set, the existing description will be kept. "
25+
"(max. 1024 characters)",
26+
max_length=1024,
27+
)
28+
title: str | None = Field(
29+
default=None,
30+
description="Title of the task. If not set, the existing title will be kept. (max. 60 characters)",
31+
max_length=60,
32+
)
33+
34+
35+
class StartWorkflowAction(BaseAction):
36+
name: Literal[ActionNames.START_WORKFLOW] = ActionNames.START_WORKFLOW
37+
template_id: str = Field(..., description="ID of the workflow template to start")
38+
cdb_project_id: str | None = Field(
39+
default=None,
40+
description="ID of the project in which the workflow should be started",
41+
)
42+
title: str = Field(..., description="Title of the workflow (max. 255 characters)", max_length=255)
43+
attachment_ids: list[str] = Field(
44+
default_factory=list,
45+
description="List of cdb_object_ids to attach to the workflow",
46+
)
47+
global_briefcase_object_ids: list[str] = Field(
48+
default_factory=list,
49+
description="List of cdb_object_ids to attach to the global briefcase",
50+
)
51+
task_configurations: list[TaskConfiguration] = Field(
52+
default_factory=list, description="List of task configurations"
53+
)

csfunctions/events/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@
1717
from .dummy import DummyEvent, DummyEventData
1818
from .engineering_change_release_check import EngineeringChangeReleaseCheckData, EngineeringChangeReleaseCheckEvent
1919
from .engineering_change_released import EngineeringChangeReleasedData, EngineeringChangeReleasedEvent
20+
from .engineering_change_status_change_check import (
21+
EngineeringChangeStatusChangeCheckData,
22+
EngineeringChangeStatusChangeCheckEvent,
23+
)
24+
from .engineering_change_status_changed import EngineeringChangeStatusChangedData, EngineeringChangeStatusChangedEvent
2025
from .field_value_calculation import FieldValueCalculationData, FieldValueCalculationEvent
2126
from .part_create_check import PartCreateCheckData, PartCreateCheckEvent
2227
from .part_field_calculation import PartFieldCalculationData, PartFieldCalculationEvent
@@ -37,6 +42,8 @@
3742
DummyEvent,
3843
EngineeringChangeReleasedEvent,
3944
EngineeringChangeReleaseCheckEvent,
45+
EngineeringChangeStatusChangedEvent,
46+
EngineeringChangeStatusChangeCheckEvent,
4047
WorkflowTaskTriggerEvent,
4148
DocumentCreateCheckEvent,
4249
DocumentModifyCheckEvent,
@@ -58,6 +65,8 @@
5865
DummyEventData,
5966
EngineeringChangeReleasedData,
6067
EngineeringChangeReleaseCheckData,
68+
EngineeringChangeStatusChangedData,
69+
EngineeringChangeStatusChangeCheckData,
6170
WorkflowTaskTriggerEventData,
6271
DocumentCreateCheckData,
6372
DocumentModifyCheckData,
@@ -88,6 +97,8 @@
8897
"DummyEventData",
8998
"EngineeringChangeReleasedData",
9099
"EngineeringChangeReleaseCheckData",
100+
"EngineeringChangeStatusChangedData",
101+
"EngineeringChangeStatusChangeCheckData",
91102
"WorkflowTaskTriggerEventData",
92103
"DocumentReleasedDialogData",
93104
"PartReleasedDialogData",

csfunctions/events/base.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ class EventNames(str, Enum):
1919
DOCUMENT_MODIFY_CHECK = "document_modify_check"
2020
PART_CREATE_CHECK = "part_create_check"
2121
PART_MODIFY_CHECK = "part_modify_check"
22+
ENGINEERING_CHANGE_STATUS_CHANGED = "engineering_change_status_changed"
23+
ENGINEERING_CHANGE_STATUS_CHANGE_CHECK = "engineering_change_status_change_check"
2224
CUSTOM_OPERATION_DOCUMENT = "custom_operation_document"
2325
CUSTOM_OPERATION_PART = "custom_operation_part"
2426

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from typing import Literal
2+
3+
from pydantic import BaseModel, Field
4+
5+
from csfunctions.objects import Document, EngineeringChange, Part
6+
7+
from .base import BaseEvent, EventNames
8+
9+
10+
class EngineeringChangeStatusChangeCheckData(BaseModel):
11+
engineering_change: EngineeringChange = Field(
12+
..., description="The engineering change that will have its status modified"
13+
)
14+
target_status: int = Field(..., description="The target status of the engineering change")
15+
documents: list[Document] = Field(..., description="List of documents attached to the engineering change")
16+
parts: list[Part] = Field(..., description="List of parts attached to the engineering change")
17+
18+
19+
class EngineeringChangeStatusChangeCheckEvent(BaseEvent):
20+
name: Literal[EventNames.ENGINEERING_CHANGE_STATUS_CHANGE_CHECK] = EventNames.ENGINEERING_CHANGE_STATUS_CHANGE_CHECK
21+
data: EngineeringChangeStatusChangeCheckData
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from typing import Literal
2+
3+
from pydantic import BaseModel, Field
4+
5+
from csfunctions.objects import Document, EngineeringChange, Part
6+
7+
from .base import BaseEvent, EventNames
8+
9+
10+
class EngineeringChangeStatusChangedData(BaseModel):
11+
engineering_change: EngineeringChange = Field(
12+
..., description="The engineering change that had its status modified"
13+
)
14+
prev_status: int = Field(..., description="The previous status of the engineering change")
15+
documents: list[Document] = Field(..., description="List of documents attached to the engineering change")
16+
parts: list[Part] = Field(..., description="List of parts attached to the engineering change")
17+
18+
19+
class EngineeringChangeStatusChangedEvent(BaseEvent):
20+
name: Literal[EventNames.ENGINEERING_CHANGE_STATUS_CHANGED] = EventNames.ENGINEERING_CHANGE_STATUS_CHANGED
21+
data: EngineeringChangeStatusChangedData

csfunctions/handler.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import json
2+
import logging
23
import os
34
import sys
45
import traceback
@@ -16,6 +17,8 @@
1617
from csfunctions.response import ResponseUnion
1718
from csfunctions.service import Service
1819

20+
logger = logging.getLogger(__name__)
21+
1922

2023
class FunctionNotRegistered(ValueError):
2124
"""
@@ -68,15 +71,17 @@ def link_objects(event: Event):
6871
# e.g. all parts would be in Event.data.parts = list[Part]
6972

7073
for field_name in data.model_fields_set:
71-
# go through each field in data and look for fields that are lists
72-
# objects will always be passed in a list
74+
# go through each field in data and look for fields that are lists of BaseObjects
75+
# or direct BaseObjects
7376

7477
field = getattr(data, field_name)
7578
if isinstance(field, list):
7679
for obj in field:
7780
# the list might contain entries that are not objects, so we check first
7881
if isinstance(obj, BaseObject):
7982
obj.link_objects(data)
83+
elif isinstance(field, BaseObject):
84+
field.link_objects(data)
8085

8186

8287
def execute(function_name: str, request_body: str, function_dir: str = "src") -> str:
@@ -115,6 +120,7 @@ def execute(function_name: str, request_body: str, function_dir: str = "src") ->
115120
response.event_id = request.event.event_id
116121

117122
except Exception as e: # pylint: disable=broad-except
123+
logger.error("An error occurred while executing function %s", function_name, exc_info=True)
118124
response = ErrorResponse(message=str(e), error_type=type(e).__name__, trace=traceback.format_exc(), id="")
119125

120126
return response.model_dump_json()

docs/assets/connect_function.png

13.5 KB
Loading

0 commit comments

Comments
 (0)