dagster-dingtalk 0.1.5b2__py3-none-any.whl → 0.1.8__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- dagster_dingtalk/resources.py +46 -36
- {dagster_dingtalk-0.1.5b2.dist-info → dagster_dingtalk-0.1.8.dist-info}/METADATA +1 -1
- dagster_dingtalk-0.1.8.dist-info/RECORD +7 -0
- dagster_dingtalk-0.1.5b2.dist-info/RECORD +0 -7
- {dagster_dingtalk-0.1.5b2.dist-info → dagster_dingtalk-0.1.8.dist-info}/WHEEL +0 -0
dagster_dingtalk/resources.py
CHANGED
@@ -15,7 +15,7 @@ from dagster import (
|
|
15
15
|
InitResourceContext, ResourceDependency,
|
16
16
|
)
|
17
17
|
from httpx import Client
|
18
|
-
from pydantic import Field, PrivateAttr
|
18
|
+
from pydantic import Field, PrivateAttr
|
19
19
|
|
20
20
|
|
21
21
|
class DingTalkWebhookResource(ConfigurableResource):
|
@@ -24,9 +24,9 @@ class DingTalkWebhookResource(ConfigurableResource):
|
|
24
24
|
alias: Optional[str] = Field(default=None, description="如提供别名,将来可以使用别名进行选择")
|
25
25
|
base_url: str = Field(default="https://oapi.dingtalk.com/robot/send", description="Webhook的通用地址,无需更改")
|
26
26
|
|
27
|
-
def
|
27
|
+
def webhook_url(self):
|
28
28
|
if self.secret is None:
|
29
|
-
return self.
|
29
|
+
return f"{self.base_url}?access_token={self.access_token}"
|
30
30
|
else:
|
31
31
|
timestamp = round(time.time() * 1000)
|
32
32
|
hmac_code = hmac.new(
|
@@ -46,12 +46,12 @@ class DingTalkWebhookResource(ConfigurableResource):
|
|
46
46
|
at["atUserIds"] = at_user_ids
|
47
47
|
if at_mobiles:
|
48
48
|
at["atMobiles"] = at_mobiles
|
49
|
-
httpx.post(url=self.webhook_url, json={"msgtype": "text", "text": {"content": text}, "at": at})
|
49
|
+
httpx.post(url=self.webhook_url(), json={"msgtype": "text", "text": {"content": text}, "at": at})
|
50
50
|
|
51
51
|
def send_link(self, text: str, message_url:str, title:str|None = None, pic_url:str = ""):
|
52
52
|
title = title or self._gen_title(text)
|
53
53
|
httpx.post(
|
54
|
-
url=self.webhook_url,
|
54
|
+
url=self.webhook_url(),
|
55
55
|
json={"msgtype": "link", "link": {"title": title, "text": text, "picUrl": pic_url, "messageUrl": message_url}}
|
56
56
|
)
|
57
57
|
|
@@ -64,7 +64,7 @@ class DingTalkWebhookResource(ConfigurableResource):
|
|
64
64
|
at["atUserIds"] = at_user_ids
|
65
65
|
if at_mobiles:
|
66
66
|
at["atMobiles"] = at_mobiles
|
67
|
-
httpx.post(url=self.webhook_url,json={"msgtype": "markdown", "markdown": {"title": title, "text": text}, "at": at})
|
67
|
+
httpx.post(url=self.webhook_url(),json={"msgtype": "markdown", "markdown": {"title": title, "text": text}, "at": at})
|
68
68
|
|
69
69
|
def send_action_card(self, text: List[str]|str, title:str|None = None, btn_orientation:Literal["0","1"] = "0",
|
70
70
|
single_jump:Tuple[str,str]|None = None, btns_jump:List[Tuple[str,str]]|None = None):
|
@@ -73,10 +73,10 @@ class DingTalkWebhookResource(ConfigurableResource):
|
|
73
73
|
action_card = {"title": title, "text": text, "btnOrientation": btn_orientation}
|
74
74
|
if btns_jump:
|
75
75
|
action_card["btns"] = [{"title": action_title, "actionURL": action_url} for action_title, action_url in btns_jump]
|
76
|
-
httpx.post(url=self.webhook_url, json={"msgtype": "actionCard", "actionCard": action_card})
|
76
|
+
httpx.post(url=self.webhook_url(), json={"msgtype": "actionCard", "actionCard": action_card})
|
77
77
|
elif single_jump:
|
78
78
|
action_card["singleTitle"], action_card["singleURL"] = single_jump
|
79
|
-
httpx.post(url=self.webhook_url, json={"msgtype": "actionCard", "actionCard": action_card})
|
79
|
+
httpx.post(url=self.webhook_url(), json={"msgtype": "actionCard", "actionCard": action_card})
|
80
80
|
else:
|
81
81
|
pass
|
82
82
|
|
@@ -85,7 +85,7 @@ class DingTalkWebhookResource(ConfigurableResource):
|
|
85
85
|
{"title": title, "messageURL": message_url, "picURL": pic_url}
|
86
86
|
for title, message_url, pic_url in links
|
87
87
|
]
|
88
|
-
httpx.post(url=self.webhook_url, json={"msgtype": "feedCard", "feedCard": {"links": links_data}})
|
88
|
+
httpx.post(url=self.webhook_url(), json={"msgtype": "feedCard", "feedCard": {"links": links_data}})
|
89
89
|
|
90
90
|
|
91
91
|
# noinspection NonAsciiCharacters
|
@@ -134,9 +134,12 @@ class MultiDingTalkWebhookResource(ConfigurableResource):
|
|
134
134
|
|
135
135
|
def select(self, key:str = "_FIRST_"):
|
136
136
|
try:
|
137
|
-
if key == "_FIRST_":
|
138
|
-
|
139
|
-
|
137
|
+
if key == "_FIRST_" or key is None:
|
138
|
+
webhook = self.Webhooks[0]
|
139
|
+
else:
|
140
|
+
webhook = self._webhooks[key]
|
141
|
+
webhook.init_webhook_url()
|
142
|
+
return webhook
|
140
143
|
except KeyError:
|
141
144
|
raise f"该 AccessToken 或 别名 <{key}> 不存在于提供的 Webhooks 中。请使用 DingTalkWebhookResource 定义单个 Webhook 后,将其加入 Webhooks 。"
|
142
145
|
|
@@ -176,13 +179,14 @@ class DingTalkResource(ConfigurableResource):
|
|
176
179
|
def _get_access_token(self) -> str:
|
177
180
|
access_token_cache = Path("/tmp/.dingtalk_cache")
|
178
181
|
|
179
|
-
|
182
|
+
try:
|
180
183
|
with open(access_token_cache, 'rb') as f:
|
181
184
|
all_access_token: Dict[str, Tuple[str, int]] = pickle.loads(f.read())
|
182
|
-
|
185
|
+
access_token, expire_in = all_access_token.get(self.AppID, ('', 0))
|
186
|
+
except Exception as e:
|
187
|
+
print(e)
|
183
188
|
all_access_token = {}
|
184
|
-
|
185
|
-
access_token, expire_in = all_access_token.get(self.AppID, ('', 0))
|
189
|
+
access_token, expire_in = all_access_token.get(self.AppID, ('', 0))
|
186
190
|
|
187
191
|
if access_token and expire_in < int(time.time()):
|
188
192
|
return access_token
|
@@ -196,29 +200,32 @@ class DingTalkResource(ConfigurableResource):
|
|
196
200
|
expire_in:int = response.json().get("expireIn") + int(time.time()) - 60
|
197
201
|
with open(access_token_cache, 'wb') as f:
|
198
202
|
all_access_token[self.AppID] = (access_token, expire_in)
|
199
|
-
f.write(pickle.dumps(
|
203
|
+
f.write(pickle.dumps(all_access_token))
|
200
204
|
return access_token
|
201
205
|
|
206
|
+
def init_client(self):
|
207
|
+
if not hasattr(self, '_client'):
|
208
|
+
self._client = DingTalkClient(
|
209
|
+
self._get_access_token(),
|
210
|
+
self.AppID,
|
211
|
+
self.AgentID,
|
212
|
+
self.RobotCode or self.ClientId
|
213
|
+
)
|
214
|
+
|
202
215
|
def setup_for_execution(self, context: InitResourceContext) -> None:
|
203
|
-
self.
|
216
|
+
self.init_client()
|
204
217
|
|
205
218
|
def teardown_after_execution(self, context: InitResourceContext) -> None:
|
206
219
|
self._client.api.close()
|
207
220
|
self._client.oapi.close()
|
208
221
|
|
209
222
|
def 智能人事(self):
|
210
|
-
if not hasattr(self, '_client'):
|
211
|
-
self._client = DingTalkClient(self._get_access_token(), self.AppID, self.AgentID, self.RobotCode or self.ClientId)
|
212
223
|
return API_智能人事(self._client)
|
213
224
|
|
214
225
|
def 通讯录管理(self):
|
215
|
-
if not hasattr(self, '_client'):
|
216
|
-
self._client = DingTalkClient(self._get_access_token(), self.AppID, self.AgentID, self.RobotCode or self.ClientId)
|
217
226
|
return API_通讯录管理(self._client)
|
218
227
|
|
219
228
|
def 文档文件(self):
|
220
|
-
if not hasattr(self, '_client'):
|
221
|
-
self._client = DingTalkClient(self._get_access_token(), self.AppID, self.AgentID, self.RobotCode or self.ClientId)
|
222
229
|
return API_文档文件(self._client)
|
223
230
|
|
224
231
|
|
@@ -266,9 +273,12 @@ class MultiDingTalkResource(ConfigurableResource):
|
|
266
273
|
|
267
274
|
def select(self, app_id:str = "_FIRST_"):
|
268
275
|
try:
|
269
|
-
if app_id == "_FIRST_":
|
270
|
-
|
271
|
-
|
276
|
+
if app_id == "_FIRST_" or app_id is None:
|
277
|
+
app = self.Apps[0]
|
278
|
+
else:
|
279
|
+
app = self._apps[app_id]
|
280
|
+
app.init_client()
|
281
|
+
return app
|
272
282
|
except KeyError:
|
273
283
|
raise f"该 AppID <{app_id}> 不存在于提供的 AppLists 中。请使用 DingTalkResource 定义单个 App 后,将其加入 AppLists 。"
|
274
284
|
|
@@ -278,14 +288,14 @@ class API_智能人事:
|
|
278
288
|
def __init__(self, _client:DingTalkClient):
|
279
289
|
self._client = _client
|
280
290
|
|
281
|
-
def 花名册_获取花名册元数据(self):
|
291
|
+
def 花名册_获取花名册元数据(self) -> dict:
|
282
292
|
response = self._client.oapi.post(
|
283
293
|
url="/topapi/smartwork/hrm/roster/meta/get",
|
284
294
|
json={"agentid": self._client.agent_id},
|
285
295
|
)
|
286
296
|
return response.json()
|
287
297
|
|
288
|
-
def 花名册_获取员工花名册字段信息(self, user_id_list:List[str], field_filter_list:List[str]|None = None, text_to_select_convert:bool|None = None):
|
298
|
+
def 花名册_获取员工花名册字段信息(self, user_id_list:List[str], field_filter_list:List[str]|None = None, text_to_select_convert:bool|None = None) -> dict:
|
289
299
|
body_dict = {"userIdList": user_id_list, "appAgentId": self._client.agent_id}
|
290
300
|
if field_filter_list is not None:
|
291
301
|
body_dict["fieldFilterList"] = field_filter_list
|
@@ -302,28 +312,28 @@ class API_智能人事:
|
|
302
312
|
待离职: '5'
|
303
313
|
无状态: '-1'
|
304
314
|
|
305
|
-
def 员工管理_获取待入职员工列表(self, offset:int, size:int):
|
315
|
+
def 员工管理_获取待入职员工列表(self, offset:int, size:int) -> dict:
|
306
316
|
response = self._client.oapi.post(
|
307
317
|
"/topapi/smartwork/hrm/employee/querypreentry",
|
308
318
|
json={"offset": offset, "size": size},
|
309
319
|
)
|
310
320
|
return response.json()
|
311
321
|
|
312
|
-
def 员工管理_获取在职员工列表(self, status_list:List[在职员工状态], offset:int, size:int):
|
322
|
+
def 员工管理_获取在职员工列表(self, status_list:List[在职员工状态], offset:int, size:int) -> dict:
|
313
323
|
response = self._client.oapi.post(
|
314
324
|
"/topapi/smartwork/hrm/employee/querypreentry",
|
315
325
|
json={"status_list": status_list, "offset": offset, "size": size},
|
316
326
|
)
|
317
327
|
return response.json()
|
318
328
|
|
319
|
-
def 员工管理_获取离职员工列表(self, next_token:int, max_results:int):
|
329
|
+
def 员工管理_获取离职员工列表(self, next_token:int, max_results:int) -> dict:
|
320
330
|
response = self._client.api.get(
|
321
331
|
"/v1.0/hrm/employees/dismissions",
|
322
332
|
params={"nextToken": next_token, "maxResults": max_results},
|
323
333
|
)
|
324
334
|
return response.json()
|
325
335
|
|
326
|
-
def 员工管理_批量获取员工离职信息(self, user_id_list:List[str]):
|
336
|
+
def 员工管理_批量获取员工离职信息(self, user_id_list:List[str]) -> dict:
|
327
337
|
response = self._client.api.get(
|
328
338
|
"/v1.0/hrm/employees/dimissionInfo",
|
329
339
|
params={"userIdList": user_id_list},
|
@@ -336,11 +346,11 @@ class API_通讯录管理:
|
|
336
346
|
def __init__(self, _client:DingTalkClient):
|
337
347
|
self._client = _client
|
338
348
|
|
339
|
-
def 查询用户详情(self, user_id:str, language:str = "zh_CN"):
|
349
|
+
def 查询用户详情(self, user_id:str, language:str = "zh_CN") -> dict:
|
340
350
|
response = self._client.oapi.post(url="/topapi/v2/user/get", json={"language": language, "userid": user_id})
|
341
351
|
return response.json()
|
342
352
|
|
343
|
-
def 查询离职记录列表(self, start_time:datetime, end_time:datetime|None, next_token:str, max_results:int):
|
353
|
+
def 查询离职记录列表(self, start_time:datetime, end_time:datetime|None, next_token:str, max_results:int) -> dict:
|
344
354
|
params = {"startTime": start_time.strftime("%Y-%m-%dT%H:%M:%SZ"), "nextToken": next_token, "maxResults": max_results}
|
345
355
|
if end_time is not None:
|
346
356
|
params["endTime"] = end_time.strftime("%Y-%m-%dT%H:%M:%SZ")
|
@@ -353,7 +363,7 @@ class API_文档文件:
|
|
353
363
|
def __init__(self, _client:DingTalkClient):
|
354
364
|
self._client = _client
|
355
365
|
|
356
|
-
def 媒体文件_上传媒体文件(self, file_path:Path|str, media_type:Literal['image', 'voice', 'video', 'file']):
|
366
|
+
def 媒体文件_上传媒体文件(self, file_path:Path|str, media_type:Literal['image', 'voice', 'video', 'file']) -> dict:
|
357
367
|
with open(file_path, 'rb') as f:
|
358
368
|
response = self._client.oapi.post(url=f"/media/upload?type={media_type}", files={'media': f})
|
359
369
|
return response.json()
|
@@ -0,0 +1,7 @@
|
|
1
|
+
dagster_dingtalk/__init__.py,sha256=ktvoURpkJwIzcyQfUvnel1KA4DukRgavAgLl7f0Cy_0,440
|
2
|
+
dagster_dingtalk/operations.py,sha256=xJJlOVmFjpaDTMkHZXxj5LbXqRtIQwREl9ZJdXIMOyE,788
|
3
|
+
dagster_dingtalk/resources.py,sha256=iWhVHtct5DDKk3-ejlT1t_N0pFtfD_nb1h6xr4rVSSQ,15231
|
4
|
+
dagster_dingtalk/version.py,sha256=sXLh7g3KC4QCFxcZGBTpG2scR7hmmBsMjq6LqRptkRg,22
|
5
|
+
dagster_dingtalk-0.1.8.dist-info/METADATA,sha256=KlhB2moaofe0iHmVOFCgxtJ5AqEItCkbqFVkjaQKS2A,1659
|
6
|
+
dagster_dingtalk-0.1.8.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
7
|
+
dagster_dingtalk-0.1.8.dist-info/RECORD,,
|
@@ -1,7 +0,0 @@
|
|
1
|
-
dagster_dingtalk/__init__.py,sha256=ktvoURpkJwIzcyQfUvnel1KA4DukRgavAgLl7f0Cy_0,440
|
2
|
-
dagster_dingtalk/operations.py,sha256=xJJlOVmFjpaDTMkHZXxj5LbXqRtIQwREl9ZJdXIMOyE,788
|
3
|
-
dagster_dingtalk/resources.py,sha256=zZkrrSff8lW59D6FEw1_01GyhcMAgL6TN3hOD21p9AE,15159
|
4
|
-
dagster_dingtalk/version.py,sha256=sXLh7g3KC4QCFxcZGBTpG2scR7hmmBsMjq6LqRptkRg,22
|
5
|
-
dagster_dingtalk-0.1.5b2.dist-info/METADATA,sha256=xeX9IPCeb_vufDg7NvaATUO5PKfLFeFgx_lb_7NdVh4,1661
|
6
|
-
dagster_dingtalk-0.1.5b2.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
7
|
-
dagster_dingtalk-0.1.5b2.dist-info/RECORD,,
|
File without changes
|