dagster-dingtalk 0.1.5b2__py3-none-any.whl → 0.1.8__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/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
|