dagster-dingtalk 0.1.14__tar.gz → 0.1.15__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dagster-dingtalk
3
- Version: 0.1.14
3
+ Version: 0.1.15
4
4
  Summary: A dagster plugin for the DingTalk
5
5
  Author: YiZixuan
6
6
  Author-email: sqkkyzx@qq.com
@@ -16,32 +16,37 @@ Description-Content-Type: text/markdown
16
16
 
17
17
  # 钉钉与 Dagster 集成
18
18
 
19
- ---
19
+ 该 Dagster 集成是为了更便捷的调用钉钉(DingTalk)的API,集成提供了两个 Dagster Resource。
20
20
 
21
- ## 介绍
21
+ ## 安装
22
+ 要安装库,请在现有的Dagster环境中使用pip。
22
23
 
23
- 该 Dagster 集成是为了更便捷的调用钉钉(DingTalk)的API,集成提供了两个 Dagster Resource。
24
+ ```bash
25
+ pip install dagster-dingtalk
26
+ ```
27
+
28
+ ## 资源
24
29
 
30
+ ### DingTalkWebhookResource
25
31
 
26
- ## DingTalkWebhookResource
32
+ ---
27
33
 
28
34
  该资源允许定义单个钉钉自定义机器人的 Webhook 端点,以便于发送文本、Markdown、Link、 ActionCard、FeedCard 消息,消息具体样式可参考
29
35
  [钉钉开放平台 | 自定义机器人发送消息的消息类型](https://open.dingtalk.com/document/orgapp/custom-bot-send-message-type)。
30
36
 
31
- ### 配置项:
37
+ #### 配置:
32
38
 
33
39
  - **access_token** (str):
34
40
  机器人 Webhook 地址中的 access_token 值。
35
41
  - **secret** (str, optional):
36
42
  如使用加签安全配置,则需传签名密钥。默认值为 None。
37
43
  - **alias** (str, optional):
38
- 如提供别名,可以在使用 `MultiDingTalkWebhookResource` 中使用别名进行 webhook 选择。默认值为 None。
44
+ 别名,仅用作标记。默认值为 None。
39
45
  - **base_url** (str, optional):
40
46
  通用地址,一般无需更改。默认值为 “https://oapi.dingtalk.com/robot/send”。
41
47
 
42
- ### 用例:
48
+ #### 用例 1:使用单个资源
43
49
 
44
- ##### 1. 使用单个资源:
45
50
  ```python
46
51
  from dagster_dingtalk import DingTalkWebhookResource
47
52
  from dagster import op, In, OpExecutionContext, job, Definitions
@@ -61,7 +66,10 @@ defs = Definitions(
61
66
  )
62
67
  ```
63
68
 
64
- ##### 2. 启动时动态构建企业内部应用资源, 可参考 [Dagster文档 | 在启动时配置资源](https://docs.dagster.io/concepts/resources#configuring-resources-at-launch-time)
69
+ #### 用例 2:启动时动态构建 Webhook 资源
70
+
71
+ 如果你事先不确定会用到哪个 webhook 机器人,或是需要根据代码逻辑动态选择 webhook ,dagster 提供了一种 [在运行时配置资源](https://docs.dagster.io/concepts/resources#configuring-resources-at-launch-time)
72
+ 的原生支持。以下是示例:
65
73
 
66
74
  ```python
67
75
  from dagster_dingtalk import DingTalkWebhookResource
@@ -94,30 +102,13 @@ def schedule_user_info():
94
102
  ))
95
103
  ```
96
104
 
97
- ### 注意:
98
-
99
- 应该永远避免直接将密钥字符串直接配置给资源,这会导致在 dagster 前端用户界面暴露密钥。
100
- 应当从环境变量中读取密钥。你可以在代码中注册临时的环境变量,或从系统中引入环境变量。
101
-
102
- ```python
103
- import os
104
- from dagster import EnvVar
105
- from dagster_dingtalk import DingTalkWebhookResource
106
-
107
- # 直接在代码中注册临时的环境变量
108
- os.environ.update({'access_token_name': "<your-access_token>"})
109
- os.environ.update({'secret_name': "<your-secret>"})
110
-
111
- webhook = DingTalkWebhookResource(access_token=EnvVar("access_token_name"), secret=EnvVar("secret_name"))
112
- ```
113
-
114
- ## DingTalkAppResource
115
105
 
116
- Dagster 资源允许定义一个钉钉的 API Client,更加便捷地调用钉钉服务端企业内部应用 API
106
+ ### DingTalkAppResource
117
107
 
118
- [钉钉服务端 API](https://open.dingtalk.com/document/orgapp/api-overview) 企业内部应用部分的第三方封装。
108
+ ---
119
109
 
120
- 通过此资源,可以调用部分钉钉服务端 API。具体封装的 API 可以在 IDE 中通过引入 `DingTalkAppClient` 类来查看 IDE 提示:
110
+ Dagster 资源允许定义一个可以调用 [钉钉服务端 API](https://open.dingtalk.com/document/orgapp/api-overview) Client,
111
+ 具有一些常用 HTTP API 的封装。你可以在 IDE 中通过引入 `DingTalkAppClient` 类来查看 IDE 提示:
121
112
 
122
113
  ```python
123
114
  from dagster_dingtalk import DingTalkAppClient
@@ -125,7 +116,18 @@ from dagster_dingtalk import DingTalkAppClient
125
116
  dingtalk: DingTalkAppClient
126
117
  ```
127
118
 
128
- ### 配置项:
119
+ **请注意:`DingTalkAppClient` 未使用钉钉官方 SDK 实现,并采用了 ASCII 字符来命名实例方法。**
120
+
121
+ > 这是为了与
122
+ > [钉钉服务端 API 文档](https://open.dingtalk.com/document/orgapp/api-overview) 里的中文 API
123
+ > 保持完全一致命名,以便于更符合直觉地进行调用和快速查阅文档。因此,可以按
124
+ > [钉钉服务端 API 文档](https://open.dingtalk.com/document/orgapp/api-overview)
125
+ > 中的层级,通过链式调用来发起 API 请求。例如:
126
+ >
127
+ > `dingtalk.智能人事.花名册.获取花名册元数据()`
128
+
129
+
130
+ #### 配置:
129
131
 
130
132
  - **AppID** (str):
131
133
  应用应用唯一标识 AppID,作为缓存标识符使用。不传入则不缓存鉴权。
@@ -138,9 +140,7 @@ dingtalk: DingTalkAppClient
138
140
  - **ClientSecret** (str):
139
141
  应用的 Client Secret ,原 AppSecret 和 SuiteSecret
140
142
 
141
- ### 用例
142
-
143
- ##### 1. 使用单一的企业内部应用资源。
143
+ #### 用例 1:使用确定的企业内部应用配置资源
144
144
 
145
145
  ```python
146
146
  from dagster_dingtalk import DingTalkAppResource, DingTalkAppClient
@@ -165,7 +165,9 @@ defs = Definitions(
165
165
  )})
166
166
  ```
167
167
 
168
- ##### 2. 启动时动态构建企业内部应用资源, 可参考 [Dagster文档 | 在启动时配置资源](https://docs.dagster.io/concepts/resources#configuring-resources-at-launch-time)
168
+ #### 用例 2:运行时动态构建企业内部应用资源
169
+
170
+ 可参考 [Dagster文档 | 在启动时配置资源](https://docs.dagster.io/concepts/resources#configuring-resources-at-launch-time)
169
171
 
170
172
  ```python
171
173
  from dagster_dingtalk import DingTalkAppResource, DingTalkAppClient
@@ -204,7 +206,22 @@ def schedule_user_info():
204
206
  ))
205
207
  ```
206
208
 
207
- ### 注意:
208
209
 
209
- 应该永远避免直接将密钥字符串直接配置给资源,这会导致在 dagster 前端用户界面暴露密钥。你可以在代码中注册临时的环境变量,或从系统中引入环境变量。
210
+ ## 提醒:
211
+
212
+ 应该永远避免直接将密钥字符串直接配置给资源,这会导致在 dagster 前端用户界面暴露密钥。
213
+ 应当从环境变量中读取密钥。你可以在代码中注册临时的环境变量,或从系统中引入环境变量。
214
+
215
+ ```python
216
+ import os
217
+ from dagster import EnvVar
218
+ from dagster_dingtalk import DingTalkWebhookResource
219
+
220
+ # 直接在代码中注册临时的环境变量
221
+ os.environ.update({'access_token_name': "<your-access_token>"})
222
+ os.environ.update({'secret_name': "<your-secret>"})
223
+
224
+ webhook = DingTalkWebhookResource(access_token=EnvVar("access_token_name"), secret=EnvVar("secret_name"))
225
+ ```
226
+
210
227
 
@@ -1,31 +1,36 @@
1
1
  # 钉钉与 Dagster 集成
2
2
 
3
- ---
3
+ 该 Dagster 集成是为了更便捷的调用钉钉(DingTalk)的API,集成提供了两个 Dagster Resource。
4
4
 
5
- ## 介绍
5
+ ## 安装
6
+ 要安装库,请在现有的Dagster环境中使用pip。
6
7
 
7
- 该 Dagster 集成是为了更便捷的调用钉钉(DingTalk)的API,集成提供了两个 Dagster Resource。
8
+ ```bash
9
+ pip install dagster-dingtalk
10
+ ```
11
+
12
+ ## 资源
8
13
 
14
+ ### DingTalkWebhookResource
9
15
 
10
- ## DingTalkWebhookResource
16
+ ---
11
17
 
12
18
  该资源允许定义单个钉钉自定义机器人的 Webhook 端点,以便于发送文本、Markdown、Link、 ActionCard、FeedCard 消息,消息具体样式可参考
13
19
  [钉钉开放平台 | 自定义机器人发送消息的消息类型](https://open.dingtalk.com/document/orgapp/custom-bot-send-message-type)。
14
20
 
15
- ### 配置项:
21
+ #### 配置:
16
22
 
17
23
  - **access_token** (str):
18
24
  机器人 Webhook 地址中的 access_token 值。
19
25
  - **secret** (str, optional):
20
26
  如使用加签安全配置,则需传签名密钥。默认值为 None。
21
27
  - **alias** (str, optional):
22
- 如提供别名,可以在使用 `MultiDingTalkWebhookResource` 中使用别名进行 webhook 选择。默认值为 None。
28
+ 别名,仅用作标记。默认值为 None。
23
29
  - **base_url** (str, optional):
24
30
  通用地址,一般无需更改。默认值为 “https://oapi.dingtalk.com/robot/send”。
25
31
 
26
- ### 用例:
32
+ #### 用例 1:使用单个资源
27
33
 
28
- ##### 1. 使用单个资源:
29
34
  ```python
30
35
  from dagster_dingtalk import DingTalkWebhookResource
31
36
  from dagster import op, In, OpExecutionContext, job, Definitions
@@ -45,7 +50,10 @@ defs = Definitions(
45
50
  )
46
51
  ```
47
52
 
48
- ##### 2. 启动时动态构建企业内部应用资源, 可参考 [Dagster文档 | 在启动时配置资源](https://docs.dagster.io/concepts/resources#configuring-resources-at-launch-time)
53
+ #### 用例 2:启动时动态构建 Webhook 资源
54
+
55
+ 如果你事先不确定会用到哪个 webhook 机器人,或是需要根据代码逻辑动态选择 webhook ,dagster 提供了一种 [在运行时配置资源](https://docs.dagster.io/concepts/resources#configuring-resources-at-launch-time)
56
+ 的原生支持。以下是示例:
49
57
 
50
58
  ```python
51
59
  from dagster_dingtalk import DingTalkWebhookResource
@@ -78,30 +86,13 @@ def schedule_user_info():
78
86
  ))
79
87
  ```
80
88
 
81
- ### 注意:
82
-
83
- 应该永远避免直接将密钥字符串直接配置给资源,这会导致在 dagster 前端用户界面暴露密钥。
84
- 应当从环境变量中读取密钥。你可以在代码中注册临时的环境变量,或从系统中引入环境变量。
85
-
86
- ```python
87
- import os
88
- from dagster import EnvVar
89
- from dagster_dingtalk import DingTalkWebhookResource
90
-
91
- # 直接在代码中注册临时的环境变量
92
- os.environ.update({'access_token_name': "<your-access_token>"})
93
- os.environ.update({'secret_name': "<your-secret>"})
94
-
95
- webhook = DingTalkWebhookResource(access_token=EnvVar("access_token_name"), secret=EnvVar("secret_name"))
96
- ```
97
-
98
- ## DingTalkAppResource
99
89
 
100
- Dagster 资源允许定义一个钉钉的 API Client,更加便捷地调用钉钉服务端企业内部应用 API
90
+ ### DingTalkAppResource
101
91
 
102
- [钉钉服务端 API](https://open.dingtalk.com/document/orgapp/api-overview) 企业内部应用部分的第三方封装。
92
+ ---
103
93
 
104
- 通过此资源,可以调用部分钉钉服务端 API。具体封装的 API 可以在 IDE 中通过引入 `DingTalkAppClient` 类来查看 IDE 提示:
94
+ Dagster 资源允许定义一个可以调用 [钉钉服务端 API](https://open.dingtalk.com/document/orgapp/api-overview) Client,
95
+ 具有一些常用 HTTP API 的封装。你可以在 IDE 中通过引入 `DingTalkAppClient` 类来查看 IDE 提示:
105
96
 
106
97
  ```python
107
98
  from dagster_dingtalk import DingTalkAppClient
@@ -109,7 +100,18 @@ from dagster_dingtalk import DingTalkAppClient
109
100
  dingtalk: DingTalkAppClient
110
101
  ```
111
102
 
112
- ### 配置项:
103
+ **请注意:`DingTalkAppClient` 未使用钉钉官方 SDK 实现,并采用了 ASCII 字符来命名实例方法。**
104
+
105
+ > 这是为了与
106
+ > [钉钉服务端 API 文档](https://open.dingtalk.com/document/orgapp/api-overview) 里的中文 API
107
+ > 保持完全一致命名,以便于更符合直觉地进行调用和快速查阅文档。因此,可以按
108
+ > [钉钉服务端 API 文档](https://open.dingtalk.com/document/orgapp/api-overview)
109
+ > 中的层级,通过链式调用来发起 API 请求。例如:
110
+ >
111
+ > `dingtalk.智能人事.花名册.获取花名册元数据()`
112
+
113
+
114
+ #### 配置:
113
115
 
114
116
  - **AppID** (str):
115
117
  应用应用唯一标识 AppID,作为缓存标识符使用。不传入则不缓存鉴权。
@@ -122,9 +124,7 @@ dingtalk: DingTalkAppClient
122
124
  - **ClientSecret** (str):
123
125
  应用的 Client Secret ,原 AppSecret 和 SuiteSecret
124
126
 
125
- ### 用例
126
-
127
- ##### 1. 使用单一的企业内部应用资源。
127
+ #### 用例 1:使用确定的企业内部应用配置资源
128
128
 
129
129
  ```python
130
130
  from dagster_dingtalk import DingTalkAppResource, DingTalkAppClient
@@ -149,7 +149,9 @@ defs = Definitions(
149
149
  )})
150
150
  ```
151
151
 
152
- ##### 2. 启动时动态构建企业内部应用资源, 可参考 [Dagster文档 | 在启动时配置资源](https://docs.dagster.io/concepts/resources#configuring-resources-at-launch-time)
152
+ #### 用例 2:运行时动态构建企业内部应用资源
153
+
154
+ 可参考 [Dagster文档 | 在启动时配置资源](https://docs.dagster.io/concepts/resources#configuring-resources-at-launch-time)
153
155
 
154
156
  ```python
155
157
  from dagster_dingtalk import DingTalkAppResource, DingTalkAppClient
@@ -188,6 +190,21 @@ def schedule_user_info():
188
190
  ))
189
191
  ```
190
192
 
191
- ### 注意:
192
193
 
193
- 应该永远避免直接将密钥字符串直接配置给资源,这会导致在 dagster 前端用户界面暴露密钥。你可以在代码中注册临时的环境变量,或从系统中引入环境变量。
194
+ ## 提醒:
195
+
196
+ 应该永远避免直接将密钥字符串直接配置给资源,这会导致在 dagster 前端用户界面暴露密钥。
197
+ 应当从环境变量中读取密钥。你可以在代码中注册临时的环境变量,或从系统中引入环境变量。
198
+
199
+ ```python
200
+ import os
201
+ from dagster import EnvVar
202
+ from dagster_dingtalk import DingTalkWebhookResource
203
+
204
+ # 直接在代码中注册临时的环境变量
205
+ os.environ.update({'access_token_name': "<your-access_token>"})
206
+ os.environ.update({'secret_name': "<your-secret>"})
207
+
208
+ webhook = DingTalkWebhookResource(access_token=EnvVar("access_token_name"), secret=EnvVar("secret_name"))
209
+ ```
210
+
@@ -1,10 +1,9 @@
1
1
  # noinspection PyProtectedMember
2
2
  from dagster._core.libraries import DagsterLibraryRegistry
3
+ from dagster_dingtalk.version import __version__
3
4
 
4
- from dagster_dingtalk.resources import DingTalkAppResource
5
- from dagster_dingtalk.resources import DingTalkWebhookResource
5
+ from dagster_dingtalk.resources import DingTalkAppResource, DingTalkWebhookResource
6
6
  from dagster_dingtalk.app_client import DingTalkClient as DingTalkAppClient
7
- # from dagster_dingtalk.operations import DingTalkWebhookOp
8
- from dagster_dingtalk.version import __version__
7
+ import dagster_dingtalk.operations as DingTalkOp
9
8
 
10
9
  DagsterLibraryRegistry.register("dagster-dingtalk", __version__)
@@ -5,7 +5,10 @@ from datetime import datetime
5
5
  from enum import Enum
6
6
  from pathlib import Path
7
7
  from typing import List, Literal, Dict, Tuple
8
+
9
+ import httpx
8
10
  from httpx import Client
11
+ from pydantic import BaseModel, Field
9
12
 
10
13
 
11
14
  # noinspection NonAsciiCharacters
@@ -26,6 +29,7 @@ class DingTalkClient:
26
29
  self.通讯录管理 = 通讯录管理_API(self)
27
30
  self.文档文件 = 文档文件_API(self)
28
31
  self.互动卡片 = 互动卡片_API(self)
32
+ self.OA审批 = OA审批_API(self)
29
33
 
30
34
  def __get_access_token(self) -> str:
31
35
  access_token_cache = Path("/tmp/.dingtalk_cache")
@@ -210,6 +214,7 @@ class 文档文件_API:
210
214
  def __init__(self, _client:DingTalkClient):
211
215
  self.__client:DingTalkClient = _client
212
216
  self.媒体文件 = 文档文件_媒体文件_API(_client)
217
+ self.文件传输 = 文档文件_文件传输_API(_client)
213
218
 
214
219
  # noinspection NonAsciiCharacters
215
220
  class 文档文件_媒体文件_API:
@@ -238,6 +243,84 @@ class 文档文件_媒体文件_API:
238
243
  response = self.__client.oapi.post(url=f"/media/upload?type={media_type}", files={'media': f})
239
244
  return response.json()
240
245
 
246
+ # noinspection NonAsciiCharacters
247
+ class 文档文件_文件传输_API:
248
+ def __init__(self, _client:DingTalkClient):
249
+ self.__client:DingTalkClient = _client
250
+
251
+ def 获取文件上传信息(self, space_id:int, union_id:str, multi_part:bool = False) -> dict:
252
+ """
253
+ 调用本接口,上传图片、语音媒体资源文件以及普通文件,接口返回媒体资源标识 media_id。
254
+
255
+ https://open.dingtalk.com/document/orgapp/upload-media-files
256
+
257
+ :param space_id: 空间Id。
258
+ :param union_id: 操作者unionId。
259
+ :param multi_part: 是否需要分片上传。默认值为 False
260
+
261
+ :return:
262
+ {
263
+ "uploadKey": str,
264
+ "storageDriver": str,
265
+ "protocol": str,
266
+ "headerSignatureInfo": {
267
+ "resourceUrls" : ["resourceUrl"],
268
+ "headers" : {
269
+ "key" : "header_value"
270
+ },
271
+ }
272
+ }
273
+ """
274
+ response = self.__client.api.post(
275
+ url=f"/v1.0/storage/spaces/{space_id}/files/uploadInfos/query",
276
+ params={'unionId': union_id},
277
+ json={
278
+ "protocol": "HEADER_SIGNATURE",
279
+ "multipart": multi_part
280
+ }
281
+ )
282
+ return response.json()
283
+
284
+ def 提交文件(self, url:str, headers:dict, file_path:Path|str, space_id:int, union_id:str,
285
+ upload_key:str, convert_to_online_doc:bool = False) -> dict:
286
+ """
287
+ 调用本接口,上传图片、语音媒体资源文件以及普通文件,接口返回媒体资源标识 media_id。
288
+
289
+ https://open.dingtalk.com/document/orgapp/upload-media-files
290
+
291
+ :param url: 获取文件上传信息得到的 resourceUrl。
292
+ :param headers: 获取文件上传信息得到的 headers。
293
+ :param file_path: 文件路径
294
+ :param space_id: 空间Id。
295
+ :param union_id: 操作者unionId。
296
+ :param upload_key: 添加文件唯一标识。
297
+ :param convert_to_online_doc: 是否转换成在线文档。默认值 False
298
+
299
+ :return:
300
+ {
301
+ "uploadKey": str,
302
+ "storageDriver": str,
303
+ "protocol": str,
304
+ "headerSignatureInfo": dict,
305
+ }
306
+ """
307
+ with open(file_path, 'rb') as f:
308
+ httpx.put(
309
+ url=url,
310
+ files={"file":f},
311
+ headers=headers
312
+ )
313
+
314
+ response = self.__client.api.post(
315
+ url = f"/v2.0/storage/spaces/files/{space_id}/commit?unionId={union_id}",
316
+ json = {
317
+ "uploadKey": upload_key,
318
+ "name": file_path.split("/")[-1],
319
+ "convertToOnlineDoc": convert_to_online_doc
320
+ }
321
+ )
322
+ return response.json()
323
+
241
324
  # noinspection NonAsciiCharacters
242
325
  class 互动卡片_API:
243
326
  def __init__(self, _client:DingTalkClient):
@@ -325,3 +408,171 @@ class 互动卡片_API:
325
408
  )
326
409
 
327
410
  return response.json()
411
+
412
+ # noinspection NonAsciiCharacters
413
+ class OA审批_API:
414
+ def __init__(self, _client:DingTalkClient):
415
+ self.__client:DingTalkClient = _client
416
+ self.审批实例 = OA审批_审批实例_API(_client)
417
+ self.审批钉盘 = OA审批_审批钉盘_API(_client)
418
+
419
+ # noinspection NonAsciiCharacters
420
+ class OA审批_审批实例_API:
421
+ def __init__(self, _client:DingTalkClient):
422
+ self.__client:DingTalkClient = _client
423
+
424
+ class CommentAttachment(BaseModel):
425
+ spaceId: str = Field(description="钉盘空间ID")
426
+ fileSize: str = Field(description="文件大小")
427
+ fileId: str = Field(description="文件ID")
428
+ fileName: str = Field(description="文件名称")
429
+ fileType: str = Field(description="文件类型")
430
+
431
+ def 获取单个审批实例详情(self, instance_id:str) -> dict:
432
+ """
433
+ 调用本接口可以获取审批实例详情数据,根据审批实例ID,获取审批实例详情,包括审批实例标题、发起人的userId、审批人userId、操作记录列表等内容。
434
+
435
+ https://open.dingtalk.com/document/orgapp/obtains-the-details-of-a-single-approval-instance-pop
436
+
437
+ :param instance_id: 审批实例ID。
438
+
439
+ :return:
440
+ {
441
+ "success": boolean,
442
+ "result": {}
443
+ }
444
+ """
445
+ response = self.__client.api.get(url="/v1.0/workflow/processInstances", params={'processInstanceId': instance_id})
446
+ return response.json()
447
+
448
+ def 撤销审批实例(self, instance_id:str, is_system:bool = True, remark:str|None = None, operating_user_id:str = None) -> dict:
449
+ """
450
+ 撤销发起的处于流程中的审批实例。审批发起15秒内不能撤销审批流程。本接口只能撤销流程中的审批实例,不能撤销已审批完成的审批实例。
451
+
452
+ https://open.dingtalk.com/document/orgapp/revoke-an-approval-instance
453
+
454
+ :param instance_id: 审批实例ID。
455
+ :param is_system: 是否通过系统操作。默认为 True。当为 false 时,需要传发起人才能撤销。
456
+ :param remark: 终止说明。
457
+ :param operating_user_id: 操作人的userId。is_system 为 false 时必填。
458
+
459
+ :return:
460
+ {
461
+ "success": boolean,
462
+ "result": {}
463
+ }
464
+ """
465
+ response = self.__client.api.post(
466
+ url="/v1.0/workflow/processInstances",
467
+ json={
468
+ "processInstanceId" : instance_id,
469
+ "isSystem" : is_system,
470
+ "remark" : remark,
471
+ "operatingUserId" : operating_user_id
472
+ }
473
+ )
474
+ return response.json()
475
+
476
+ def 添加审批评论(
477
+ self, instance_id:str, text:str, comment_user_id: str,
478
+ photos: List[str]|None = None, attachments: List[CommentAttachment]|None = None
479
+ ) -> dict:
480
+ """
481
+ 调用本接口可以获取审批实例详情数据,根据审批实例ID,获取审批实例详情,包括审批实例标题、发起人的userId、审批人userId、操作记录列表等内容。
482
+
483
+ 其中,添加审批评论附件需调用获取审批钉盘空间信息接口,获取钉盘空间的上传权限,并获取审批钉盘空间spaceId。
484
+
485
+ https://open.dingtalk.com/document/orgapp/obtains-the-details-of-a-single-approval-instance-pop
486
+
487
+ :param instance_id: 审批实例 ID。
488
+ :param text: 评论的内容。
489
+ :param comment_user_id: 评论人的 UserId
490
+ :param photos: 图片的 URL 链接的列表,默认为 None。
491
+ :param attachments: 附件列表,默认为 None。添加审批评论附件需将文件上传至审批钉盘空间,可以获取到相关接口参数。
492
+
493
+ :return:
494
+ {
495
+ "success": boolean,
496
+ "result": boolean
497
+ }
498
+ """
499
+
500
+ data = {
501
+ 'processInstanceId': instance_id,
502
+ 'text': text,
503
+ 'commentUserId': comment_user_id,
504
+ }
505
+
506
+ if photos or attachments:
507
+ data.update({'file': {"photos": photos, "attachments": attachments}})
508
+
509
+ response = self.__client.api.post(
510
+ url="/v1.0/workflow/processInstances/comments",
511
+ json=data
512
+ )
513
+ return response.json()
514
+
515
+ def 获取审批实例ID列表(
516
+ self, process_code:str, start_time:datetime, end_time:datetime, next_token: int = 0, max_results: int = 20,
517
+ statuses: Literal["RUNNING", "TERMINATED", "COMPLETED"]|None = None, user_ids = List[str]
518
+ ) -> dict:
519
+ """
520
+ 获取权限范围内的相关部门审批实例ID列表。
521
+
522
+ https://open.dingtalk.com/document/orgapp/obtain-an-approval-list-of-instance-ids
523
+
524
+ :param user_ids:
525
+ :param process_code: 审批流模板的 code。
526
+ :param start_time: 审批实例开始时间。
527
+ :param end_time: 审批实例结束时间。
528
+ :param next_token: 分页游标, 首次调用传 0, 默认值为 0
529
+ :param max_results: 分页小,最多传20,默认值为 20
530
+ :param statuses: 筛选流程实例状态,默认为 None,表示不筛选。 RUNNING-审批中 TERMINATED-已撤销 COMPLETED-审批完成
531
+
532
+ :return:
533
+ {
534
+ "success": boolean,
535
+ "result": {}
536
+ }
537
+ """
538
+ response = self.__client.api.post(
539
+ url="/v1.0/workflow/processes/instanceIds/query",
540
+ json={
541
+ "processCode" : process_code,
542
+ "startTime" : int(start_time.timestamp()*1000),
543
+ "endTime" : int(end_time.timestamp()*1000),
544
+ "nextToken" : next_token,
545
+ "maxResults" : max_results,
546
+ "userIds" : user_ids,
547
+ "statuses" : statuses
548
+ })
549
+ return response.json()
550
+
551
+ # noinspection NonAsciiCharacters
552
+ class OA审批_审批钉盘_API:
553
+ def __init__(self, _client:DingTalkClient):
554
+ self.__client:DingTalkClient = _client
555
+
556
+ def 获取审批钉盘空间信息(self, user_id:str) -> dict:
557
+ """
558
+ 获取审批钉盘空间的ID并授予当前用户上传附件的权限。
559
+
560
+ https://open.dingtalk.com/document/orgapp/obtains-the-information-about-approval-nail-disk
561
+
562
+ :param user_id: 用户的userId。
563
+
564
+ :return:
565
+ {
566
+ "success": bool,
567
+ "result": {
568
+ "spaceId": int
569
+ }
570
+ }
571
+ """
572
+ response = self.__client.api.post(
573
+ url="/v1.0/workflow/processInstances/spaces/infos/query",
574
+ json={
575
+ "userId" : user_id,
576
+ "agentId" : self.__client.agent_id
577
+ })
578
+ return response.json()
@@ -0,0 +1,86 @@
1
+ from dagster import In, OpExecutionContext, op, Out
2
+
3
+ # noinspection PyProtectedMember
4
+ from dagster._annotations import experimental
5
+
6
+ from .app_client import DingTalkClient
7
+ from .resources import DingTalkWebhookResource
8
+
9
+ @experimental
10
+ @op(description="钉钉Webhook发送文本消息",
11
+ required_resource_keys={'dingtalk_webhook'},
12
+ ins={
13
+ "text": In(str),
14
+ "at": In(default_value=None, description="@列表,传List[str]解析为userId,传List[int]解析为phone,传ALL解析为全部。")
15
+ })
16
+ def op_send_simple_text(context: OpExecutionContext, text, at):
17
+ webhook:DingTalkWebhookResource = context.resources.dingtalk_webhook
18
+ if isinstance(at, str) and at == 'ALL':
19
+ webhook.send_text(text=text, at_all=True)
20
+ if isinstance(at, list) and isinstance(at[0], str):
21
+ webhook.send_text(text=text, at_user_ids=at)
22
+ if isinstance(at, list) and isinstance(at[0], int):
23
+ at = [str(mobile) for mobile in at]
24
+ webhook.send_text(text=text, at_mobiles=at)
25
+ if not at:
26
+ webhook.send_text(text=text)
27
+
28
+
29
+ @op(description="钉钉Webhook发送Markdown消息",
30
+ required_resource_keys={'dingtalk_webhook'},
31
+ ins={
32
+ "text": In(str),
33
+ "title": In(str, default_value=''),
34
+ "at": In(default_value=None, description="@列表,传List[str]解析为userId,传List[int]解析为phone,传ALL解析为全部。")
35
+ })
36
+ def op_send_markdown(context: OpExecutionContext, text, title, at):
37
+ webhook:DingTalkWebhookResource = context.resources.dingtalk_webhook
38
+ if isinstance(at, str) and at == 'ALL':
39
+ webhook.send_markdown(text=text, title=title, at_all=True)
40
+ if isinstance(at, list) and isinstance(at[0], str):
41
+ webhook.send_markdown(text=text, title=title, at_user_ids=at)
42
+ if isinstance(at, list) and isinstance(at[0], int):
43
+ at = [str(mobile) for mobile in at]
44
+ webhook.send_markdown(text=text, title=title, at_mobiles=at)
45
+ if not at:
46
+ webhook.send_markdown(text=text, title=title)
47
+
48
+
49
+ @op(description="更新钉钉互动卡片",
50
+ required_resource_keys={"dingtalk"},
51
+ ins={"card_param_map":In(), "out_track_id":In(str), "update_by_key":In(bool, default_value=True)},
52
+ out={"is_success":Out(bool, is_required=False)})
53
+ def renew_card(context:OpExecutionContext, card_param_map, out_track_id, update_by_key):
54
+ try:
55
+ dingtalk_yunxiao: DingTalkClient = context.resources.dingtalk_yunxiao
56
+ res = dingtalk_yunxiao.互动卡片.更新卡片(out_track_id=out_track_id, card_param_map=card_param_map, update_card_data_by_key=update_by_key)
57
+ context.log.info(res)
58
+ if res.get('success') and res.get('result'):
59
+ return True
60
+ else:
61
+ return False
62
+ except Exception as e:
63
+ context.log.error(e)
64
+ return False
65
+
66
+
67
+ @op(description="创建并发送钉钉互动卡片",
68
+ ins={"search_type_name":In(str), "alert_content":In(str), "card_template_id":In(str), "card_param_map":In(), "out_track_id":In(str), "open_space_id":In(str)},
69
+ out={"is_success":Out(bool, is_required=False)}, required_resource_keys={"dingtalk"})
70
+ def send_revenue_dt_card(context:OpExecutionContext, search_type_name, alert_content,card_template_id, card_param_map, out_track_id, open_space_id):
71
+ try:
72
+ dingtalk_yunxiao: DingTalkClient = context.resources.dingtalk_yunxiao
73
+ res = dingtalk_yunxiao.互动卡片.创建并投放卡片(
74
+ search_type_name=search_type_name,
75
+ search_desc=alert_content,
76
+ card_template_id=card_template_id,
77
+ card_param_map=card_param_map,
78
+ alert_content=alert_content,
79
+ out_track_id=out_track_id,
80
+ open_space_ids=[open_space_id]
81
+ )
82
+ context.log.info(res)
83
+ return res.get("success")
84
+ except Exception as e:
85
+ context.log.error(e)
86
+ return False
@@ -48,7 +48,7 @@ class DingTalkWebhookResource(ConfigurableResource):
48
48
  - **secret** (str, optional):
49
49
  如使用加签安全配置,则需传签名密钥。默认值为 None。
50
50
  - **alias** (str, optional):
51
- 如提供别名,可以在使用 `MultiDingTalkWebhookResource` 中使用别名进行 webhook 选择。默认值为 None。
51
+ 别名,仅用作标记。默认值为 None。
52
52
  - **base_url** (str, optional):
53
53
  通用地址,一般无需更改。默认值为 “https://oapi.dingtalk.com/robot/send”。
54
54
 
@@ -303,8 +303,6 @@ class DingTalkWebhookResource(ConfigurableResource):
303
303
 
304
304
  class DingTalkAppResource(ConfigurableResource):
305
305
  """
306
- 该 Dagster 资源允许定义一个钉钉的 API Client,更加便捷地调用钉钉服务端企业内部应用 API
307
-
308
306
  [钉钉服务端 API](https://open.dingtalk.com/document/orgapp/api-overview) 企业内部应用部分的第三方封装。
309
307
 
310
308
  通过此资源,可以调用部分钉钉服务端 API。具体封装的 API 可以在 IDE 中通过引入 `DingTalkAppClient` 类来查看 IDE 提示:
@@ -0,0 +1 @@
1
+ __version__ = "0.1.15"
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "dagster-dingtalk"
3
- version = "0.1.14"
3
+ version = "0.1.15"
4
4
  description = "A dagster plugin for the DingTalk"
5
5
  authors = ["YiZixuan <sqkkyzx@qq.com>"]
6
6
  readme = "README.md"
@@ -1,20 +0,0 @@
1
- from dagster import In, OpExecutionContext, op
2
-
3
- # noinspection PyProtectedMember
4
- from dagster._annotations import experimental
5
-
6
-
7
- @experimental
8
- @op(description="使用钉钉 Webhook 发送文本消息",
9
- required_resource_keys={'dingtalk_webhook'},
10
- ins={"text": In(str)})
11
- def op_send_simple_text(context: OpExecutionContext, text):
12
- webhook = context.resources.dingtalk_webhook
13
- webhook.send_text(text)
14
-
15
- @op(description="使用钉钉 Webhook 发送 Markdown 消息",
16
- required_resource_keys={'dingtalk_webhook'},
17
- ins={"text": In(str), "title": In(str, default_value='')})
18
- def op_simple_markdown(context: OpExecutionContext, text, title):
19
- webhook = context.resources.dingtalk_webhook
20
- webhook.send_text(text, title)
@@ -1 +0,0 @@
1
- __version__ = "0.1.14"