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.
@@ -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, BaseModel
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 _sign_webhook_url(self):
27
+ def webhook_url(self):
28
28
  if self.secret is None:
29
- return self.webhook_url
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
- return self.Webhooks[0]
139
- return self._webhooks[key]
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
- if access_token_cache.exists():
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
- else:
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(access_token_cache))
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._client = DingTalkClient(self._get_access_token(), self.AppID, self.AgentID, self.RobotCode or self.ClientId)
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
- return self.Apps[0]
271
- return self._apps[app_id]
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()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dagster-dingtalk
3
- Version: 0.1.5b2
3
+ Version: 0.1.8
4
4
  Summary: A dagster plugin for the DingTalk
5
5
  Author: YiZixuan
6
6
  Author-email: sqkkyzx@qq.com
@@ -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,,