dagster-dingtalk 0.1.14__py3-none-any.whl → 0.1.16__py3-none-any.whl
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.
- dagster_dingtalk/__init__.py +3 -4
- dagster_dingtalk/app_client.py +251 -0
- dagster_dingtalk/operations.py +77 -15
- dagster_dingtalk/resources.py +1 -3
- dagster_dingtalk/version.py +1 -1
- {dagster_dingtalk-0.1.14.dist-info → dagster_dingtalk-0.1.16.dist-info}/METADATA +55 -38
- dagster_dingtalk-0.1.16.dist-info/RECORD +8 -0
- dagster_dingtalk-0.1.14.dist-info/RECORD +0 -8
- {dagster_dingtalk-0.1.14.dist-info → dagster_dingtalk-0.1.16.dist-info}/WHEEL +0 -0
dagster_dingtalk/__init__.py
CHANGED
@@ -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
|
-
|
8
|
-
from dagster_dingtalk.version import __version__
|
7
|
+
import dagster_dingtalk.operations as dingtalk_op
|
9
8
|
|
10
9
|
DagsterLibraryRegistry.register("dagster-dingtalk", __version__)
|
dagster_dingtalk/app_client.py
CHANGED
@@ -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()
|
dagster_dingtalk/operations.py
CHANGED
@@ -1,20 +1,82 @@
|
|
1
|
-
from dagster import In, OpExecutionContext, op
|
1
|
+
from dagster import In, OpExecutionContext, op, Out
|
2
|
+
from .app_client import DingTalkClient
|
3
|
+
from .resources import DingTalkWebhookResource
|
2
4
|
|
3
|
-
# noinspection PyProtectedMember
|
4
|
-
from dagster._annotations import experimental
|
5
5
|
|
6
|
-
|
7
|
-
@experimental
|
8
|
-
@op(description="使用钉钉 Webhook 发送文本消息",
|
6
|
+
@op(description="钉钉Webhook发送文本消息",
|
9
7
|
required_resource_keys={'dingtalk_webhook'},
|
10
|
-
ins={
|
11
|
-
|
12
|
-
|
13
|
-
|
8
|
+
ins={
|
9
|
+
"text": In(str),
|
10
|
+
"at": In(default_value=None, description="@列表,传List[str]解析为userId,传List[int]解析为phone,传ALL解析为全部。")
|
11
|
+
})
|
12
|
+
def op_send_text(context: OpExecutionContext, text, at):
|
13
|
+
webhook:DingTalkWebhookResource = context.resources.dingtalk_webhook
|
14
|
+
if isinstance(at, str) and at == 'ALL':
|
15
|
+
webhook.send_text(text=text, at_all=True)
|
16
|
+
if isinstance(at, list) and isinstance(at[0], str):
|
17
|
+
webhook.send_text(text=text, at_user_ids=at)
|
18
|
+
if isinstance(at, list) and isinstance(at[0], int):
|
19
|
+
at = [str(mobile) for mobile in at]
|
20
|
+
webhook.send_text(text=text, at_mobiles=at)
|
21
|
+
if not at:
|
22
|
+
webhook.send_text(text=text)
|
23
|
+
|
14
24
|
|
15
|
-
@op(description="
|
25
|
+
@op(description="钉钉Webhook发送Markdown消息",
|
16
26
|
required_resource_keys={'dingtalk_webhook'},
|
17
|
-
ins={
|
18
|
-
|
19
|
-
|
20
|
-
|
27
|
+
ins={
|
28
|
+
"text": In(str, description="Markdown 内容"),
|
29
|
+
"title": In(str, default_value='', description="标题"),
|
30
|
+
"at": In(default_value=None, description="传 List[str] @userIds ,传 List[int] @mobiles ,传 \"ALL\" @所有人。")
|
31
|
+
})
|
32
|
+
def op_send_markdown(context: OpExecutionContext, text, title, at):
|
33
|
+
webhook:DingTalkWebhookResource = context.resources.dingtalk_webhook
|
34
|
+
if isinstance(at, str) and at == 'ALL':
|
35
|
+
webhook.send_markdown(text=text, title=title, at_all=True)
|
36
|
+
if isinstance(at, list) and isinstance(at[0], str):
|
37
|
+
webhook.send_markdown(text=text, title=title, at_user_ids=at)
|
38
|
+
if isinstance(at, list) and isinstance(at[0], int):
|
39
|
+
at = [str(mobile) for mobile in at]
|
40
|
+
webhook.send_markdown(text=text, title=title, at_mobiles=at)
|
41
|
+
if not at:
|
42
|
+
webhook.send_markdown(text=text, title=title)
|
43
|
+
|
44
|
+
|
45
|
+
@op(description="更新钉钉互动卡片",
|
46
|
+
required_resource_keys={"dingtalk"},
|
47
|
+
ins={"card_param_map":In(), "out_track_id":In(str), "update_by_key":In(bool, default_value=True)},
|
48
|
+
out={"is_success":Out(bool, is_required=False)})
|
49
|
+
def renew_card(context:OpExecutionContext, card_param_map, out_track_id, update_by_key):
|
50
|
+
try:
|
51
|
+
dingtalk_yunxiao: DingTalkClient = context.resources.dingtalk_yunxiao
|
52
|
+
res = dingtalk_yunxiao.互动卡片.更新卡片(out_track_id=out_track_id, card_param_map=card_param_map, update_card_data_by_key=update_by_key)
|
53
|
+
context.log.info(res)
|
54
|
+
if res.get('success') and res.get('result'):
|
55
|
+
return True
|
56
|
+
else:
|
57
|
+
return False
|
58
|
+
except Exception as e:
|
59
|
+
context.log.error(e)
|
60
|
+
return False
|
61
|
+
|
62
|
+
|
63
|
+
@op(description="创建并发送钉钉互动卡片",
|
64
|
+
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)},
|
65
|
+
out={"is_success":Out(bool, is_required=False)}, required_resource_keys={"dingtalk"})
|
66
|
+
def send_revenue_dt_card(context:OpExecutionContext, search_type_name, alert_content,card_template_id, card_param_map, out_track_id, open_space_id):
|
67
|
+
try:
|
68
|
+
dingtalk_yunxiao: DingTalkClient = context.resources.dingtalk_yunxiao
|
69
|
+
res = dingtalk_yunxiao.互动卡片.创建并投放卡片(
|
70
|
+
search_type_name=search_type_name,
|
71
|
+
search_desc=alert_content,
|
72
|
+
card_template_id=card_template_id,
|
73
|
+
card_param_map=card_param_map,
|
74
|
+
alert_content=alert_content,
|
75
|
+
out_track_id=out_track_id,
|
76
|
+
open_space_ids=[open_space_id]
|
77
|
+
)
|
78
|
+
context.log.info(res)
|
79
|
+
return res.get("success")
|
80
|
+
except Exception as e:
|
81
|
+
context.log.error(e)
|
82
|
+
return False
|
dagster_dingtalk/resources.py
CHANGED
@@ -48,7 +48,7 @@ class DingTalkWebhookResource(ConfigurableResource):
|
|
48
48
|
- **secret** (str, optional):
|
49
49
|
如使用加签安全配置,则需传签名密钥。默认值为 None。
|
50
50
|
- **alias** (str, optional):
|
51
|
-
|
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 提示:
|
dagster_dingtalk/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "0.1.
|
1
|
+
__version__ = "0.1.16"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: dagster-dingtalk
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.16
|
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
|
-
|
24
|
+
```bash
|
25
|
+
pip install dagster-dingtalk
|
26
|
+
```
|
27
|
+
|
28
|
+
## 资源
|
24
29
|
|
30
|
+
### DingTalkWebhookResource
|
25
31
|
|
26
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
106
|
+
### DingTalkAppResource
|
117
107
|
|
118
|
-
|
108
|
+
---
|
119
109
|
|
120
|
-
|
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
|
-
|
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
|
-
|
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
|
|
@@ -0,0 +1,8 @@
|
|
1
|
+
dagster_dingtalk/__init__.py,sha256=CqR5mJA2IrgCFi90KhgTvVLucIn5p978cF7VhXj84u4,418
|
2
|
+
dagster_dingtalk/app_client.py,sha256=VNCZhZZ3IntleW5zcUeevtnvtfTnaaRDh3nMJow4btg,23814
|
3
|
+
dagster_dingtalk/operations.py,sha256=C1wwXCW7mpKhLC1-Y7TCP_72L9e93a9ceVHRWhNda-Q,3891
|
4
|
+
dagster_dingtalk/resources.py,sha256=1u8-oXRa7H_e0CAYkTJDxbjEmt3ZcD_ntBNvrS_rwr8,17430
|
5
|
+
dagster_dingtalk/version.py,sha256=yF88-8vL8keLe6gCTumymw0UoMkWkSrJnzLru4zBCLQ,23
|
6
|
+
dagster_dingtalk-0.1.16.dist-info/METADATA,sha256=zfr64W7ct1gXJAcQP9sqFVJbrnmQd1j98jnmGyzZ90I,8011
|
7
|
+
dagster_dingtalk-0.1.16.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
8
|
+
dagster_dingtalk-0.1.16.dist-info/RECORD,,
|
@@ -1,8 +0,0 @@
|
|
1
|
-
dagster_dingtalk/__init__.py,sha256=X7r8JoydXOsT9Sis4rBpVSKQeKJnnZ_t_qFae-ASF7E,466
|
2
|
-
dagster_dingtalk/app_client.py,sha256=STTBxNzs2rhyHX7gsDuTpftJcctbTPKRAFIZV7zsF08,13800
|
3
|
-
dagster_dingtalk/operations.py,sha256=3cCZCxh-dAdzzb75WCTKVdzeMV8yu_JJpIeULS7XaNg,761
|
4
|
-
dagster_dingtalk/resources.py,sha256=HUZX9PSZqyLxiHfsWC-CKsccQC4K0XtBy_LK3af7VTk,17626
|
5
|
-
dagster_dingtalk/version.py,sha256=PIBqEOI-nqKFL9oJAWQQwlHuujG9Cd7EmdxDrThNQto,23
|
6
|
-
dagster_dingtalk-0.1.14.dist-info/METADATA,sha256=4gXJVegi44soyMyQevPsiumcjiIqWWkxbj1TssT1XH0,7608
|
7
|
-
dagster_dingtalk-0.1.14.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
8
|
-
dagster_dingtalk-0.1.14.dist-info/RECORD,,
|
File without changes
|