lark_api_utils.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  1. import json
  2. from typing import Any, Optional, cast
  3. import httpx
  4. from core.tools.errors import ToolProviderCredentialValidationError
  5. from extensions.ext_redis import redis_client
  6. def lark_auth(credentials):
  7. app_id = credentials.get("app_id")
  8. app_secret = credentials.get("app_secret")
  9. if not app_id or not app_secret:
  10. raise ToolProviderCredentialValidationError("app_id and app_secret is required")
  11. try:
  12. assert LarkRequest(app_id, app_secret).tenant_access_token is not None
  13. except Exception as e:
  14. raise ToolProviderCredentialValidationError(str(e))
  15. class LarkRequest:
  16. API_BASE_URL = "https://lark-plugin-api.solutionsuite.ai/lark-plugin"
  17. def __init__(self, app_id: str, app_secret: str):
  18. self.app_id = app_id
  19. self.app_secret = app_secret
  20. def convert_add_records(self, json_str):
  21. try:
  22. data = json.loads(json_str)
  23. if not isinstance(data, list):
  24. raise ValueError("Parsed data must be a list")
  25. converted_data = [{"fields": json.dumps(item, ensure_ascii=False)} for item in data]
  26. return converted_data
  27. except json.JSONDecodeError:
  28. raise ValueError("The input string is not valid JSON")
  29. except Exception as e:
  30. raise ValueError(f"An error occurred while processing the data: {e}")
  31. def convert_update_records(self, json_str):
  32. try:
  33. data = json.loads(json_str)
  34. if not isinstance(data, list):
  35. raise ValueError("Parsed data must be a list")
  36. converted_data = [
  37. {"fields": json.dumps(record["fields"], ensure_ascii=False), "record_id": record["record_id"]}
  38. for record in data
  39. if "fields" in record and "record_id" in record
  40. ]
  41. if len(converted_data) != len(data):
  42. raise ValueError("Each record must contain 'fields' and 'record_id'")
  43. return converted_data
  44. except json.JSONDecodeError:
  45. raise ValueError("The input string is not valid JSON")
  46. except Exception as e:
  47. raise ValueError(f"An error occurred while processing the data: {e}")
  48. @property
  49. def tenant_access_token(self) -> str:
  50. feishu_tenant_access_token = f"tools:{self.app_id}:feishu_tenant_access_token"
  51. if redis_client.exists(feishu_tenant_access_token):
  52. return str(redis_client.get(feishu_tenant_access_token).decode())
  53. res: dict[str, str] = self.get_tenant_access_token(self.app_id, self.app_secret)
  54. redis_client.setex(feishu_tenant_access_token, res.get("expire"), res.get("tenant_access_token"))
  55. return res.get("tenant_access_token", "")
  56. def _send_request(
  57. self,
  58. url: str,
  59. method: str = "post",
  60. require_token: bool = True,
  61. payload: Optional[dict] = None,
  62. params: Optional[dict] = None,
  63. ):
  64. headers = {
  65. "Content-Type": "application/json",
  66. "user-agent": "Dify",
  67. }
  68. if require_token:
  69. headers["tenant-access-token"] = f"{self.tenant_access_token}"
  70. res = httpx.request(method=method, url=url, headers=headers, json=payload, params=params, timeout=30).json()
  71. if res.get("code") != 0:
  72. raise Exception(res)
  73. return res
  74. def get_tenant_access_token(self, app_id: str, app_secret: str) -> dict:
  75. url = f"{self.API_BASE_URL}/access_token/get_tenant_access_token"
  76. payload = {"app_id": app_id, "app_secret": app_secret}
  77. res: dict = self._send_request(url, require_token=False, payload=payload)
  78. return res
  79. def create_document(self, title: str, content: str, folder_token: str) -> dict:
  80. url = f"{self.API_BASE_URL}/document/create_document"
  81. payload = {
  82. "title": title,
  83. "content": content,
  84. "folder_token": folder_token,
  85. }
  86. res: dict = self._send_request(url, payload=payload)
  87. if "data" in res:
  88. data: dict = res.get("data", {})
  89. return data
  90. return res
  91. def write_document(self, document_id: str, content: str, position: str = "end") -> dict:
  92. url = f"{self.API_BASE_URL}/document/write_document"
  93. payload = {"document_id": document_id, "content": content, "position": position}
  94. res: dict = self._send_request(url, payload=payload)
  95. return res
  96. def get_document_content(self, document_id: str, mode: str = "markdown", lang: str = "0") -> str | dict:
  97. params = {
  98. "document_id": document_id,
  99. "mode": mode,
  100. "lang": lang,
  101. }
  102. url = f"{self.API_BASE_URL}/document/get_document_content"
  103. res: dict = self._send_request(url, method="GET", params=params)
  104. if "data" in res:
  105. return cast(dict, res.get("data", {}).get("content"))
  106. return ""
  107. def list_document_blocks(
  108. self, document_id: str, page_token: str, user_id_type: str = "open_id", page_size: int = 500
  109. ) -> dict:
  110. params = {
  111. "user_id_type": user_id_type,
  112. "document_id": document_id,
  113. "page_size": page_size,
  114. "page_token": page_token,
  115. }
  116. url = f"{self.API_BASE_URL}/document/list_document_blocks"
  117. res: dict = self._send_request(url, method="GET", params=params)
  118. if "data" in res:
  119. data: dict = res.get("data", {})
  120. return data
  121. return res
  122. def send_bot_message(self, receive_id_type: str, receive_id: str, msg_type: str, content: str) -> dict:
  123. url = f"{self.API_BASE_URL}/message/send_bot_message"
  124. params = {
  125. "receive_id_type": receive_id_type,
  126. }
  127. payload = {
  128. "receive_id": receive_id,
  129. "msg_type": msg_type,
  130. "content": content.strip('"').replace(r"\"", '"').replace(r"\\", "\\"),
  131. }
  132. res: dict = self._send_request(url, params=params, payload=payload)
  133. if "data" in res:
  134. data: dict = res.get("data", {})
  135. return data
  136. return res
  137. def send_webhook_message(self, webhook: str, msg_type: str, content: str) -> dict:
  138. url = f"{self.API_BASE_URL}/message/send_webhook_message"
  139. payload = {
  140. "webhook": webhook,
  141. "msg_type": msg_type,
  142. "content": content.strip('"').replace(r"\"", '"').replace(r"\\", "\\"),
  143. }
  144. res: dict = self._send_request(url, require_token=False, payload=payload)
  145. return res
  146. def get_chat_messages(
  147. self,
  148. container_id: str,
  149. start_time: str,
  150. end_time: str,
  151. page_token: str,
  152. sort_type: str = "ByCreateTimeAsc",
  153. page_size: int = 20,
  154. ) -> dict:
  155. url = f"{self.API_BASE_URL}/message/get_chat_messages"
  156. params = {
  157. "container_id": container_id,
  158. "start_time": start_time,
  159. "end_time": end_time,
  160. "sort_type": sort_type,
  161. "page_token": page_token,
  162. "page_size": page_size,
  163. }
  164. res: dict = self._send_request(url, method="GET", params=params)
  165. if "data" in res:
  166. data: dict = res.get("data", {})
  167. return data
  168. return res
  169. def get_thread_messages(
  170. self, container_id: str, page_token: str, sort_type: str = "ByCreateTimeAsc", page_size: int = 20
  171. ) -> dict:
  172. url = f"{self.API_BASE_URL}/message/get_thread_messages"
  173. params = {
  174. "container_id": container_id,
  175. "sort_type": sort_type,
  176. "page_token": page_token,
  177. "page_size": page_size,
  178. }
  179. res: dict = self._send_request(url, method="GET", params=params)
  180. if "data" in res:
  181. data: dict = res.get("data", {})
  182. return data
  183. return res
  184. def create_task(self, summary: str, start_time: str, end_time: str, completed_time: str, description: str) -> dict:
  185. url = f"{self.API_BASE_URL}/task/create_task"
  186. payload = {
  187. "summary": summary,
  188. "start_time": start_time,
  189. "end_time": end_time,
  190. "completed_at": completed_time,
  191. "description": description,
  192. }
  193. res: dict = self._send_request(url, payload=payload)
  194. if "data" in res:
  195. data: dict = res.get("data", {})
  196. return data
  197. return res
  198. def update_task(
  199. self, task_guid: str, summary: str, start_time: str, end_time: str, completed_time: str, description: str
  200. ) -> dict:
  201. url = f"{self.API_BASE_URL}/task/update_task"
  202. payload = {
  203. "task_guid": task_guid,
  204. "summary": summary,
  205. "start_time": start_time,
  206. "end_time": end_time,
  207. "completed_time": completed_time,
  208. "description": description,
  209. }
  210. res: dict = self._send_request(url, method="PATCH", payload=payload)
  211. if "data" in res:
  212. data: dict = res.get("data", {})
  213. return data
  214. return res
  215. def delete_task(self, task_guid: str) -> dict:
  216. url = f"{self.API_BASE_URL}/task/delete_task"
  217. payload = {
  218. "task_guid": task_guid,
  219. }
  220. res: dict = self._send_request(url, method="DELETE", payload=payload)
  221. if "data" in res:
  222. data: dict = res.get("data", {})
  223. return data
  224. return res
  225. def add_members(self, task_guid: str, member_phone_or_email: str, member_role: str) -> dict:
  226. url = f"{self.API_BASE_URL}/task/add_members"
  227. payload = {
  228. "task_guid": task_guid,
  229. "member_phone_or_email": member_phone_or_email,
  230. "member_role": member_role,
  231. }
  232. res: dict = self._send_request(url, payload=payload)
  233. if "data" in res:
  234. data: dict = res.get("data", {})
  235. return data
  236. return res
  237. def get_wiki_nodes(self, space_id: str, parent_node_token: str, page_token: str, page_size: int = 20) -> dict:
  238. url = f"{self.API_BASE_URL}/wiki/get_wiki_nodes"
  239. payload = {
  240. "space_id": space_id,
  241. "parent_node_token": parent_node_token,
  242. "page_token": page_token,
  243. "page_size": page_size,
  244. }
  245. res: dict = self._send_request(url, payload=payload)
  246. if "data" in res:
  247. data: dict = res.get("data", {})
  248. return data
  249. return res
  250. def get_primary_calendar(self, user_id_type: str = "open_id") -> dict:
  251. url = f"{self.API_BASE_URL}/calendar/get_primary_calendar"
  252. params = {
  253. "user_id_type": user_id_type,
  254. }
  255. res: dict = self._send_request(url, method="GET", params=params)
  256. if "data" in res:
  257. data: dict = res.get("data", {})
  258. return data
  259. return res
  260. def create_event(
  261. self,
  262. summary: str,
  263. description: str,
  264. start_time: str,
  265. end_time: str,
  266. attendee_ability: str,
  267. need_notification: bool = True,
  268. auto_record: bool = False,
  269. ) -> dict:
  270. url = f"{self.API_BASE_URL}/calendar/create_event"
  271. payload = {
  272. "summary": summary,
  273. "description": description,
  274. "need_notification": need_notification,
  275. "start_time": start_time,
  276. "end_time": end_time,
  277. "auto_record": auto_record,
  278. "attendee_ability": attendee_ability,
  279. }
  280. res: dict = self._send_request(url, payload=payload)
  281. if "data" in res:
  282. data: dict = res.get("data", {})
  283. return data
  284. return res
  285. def update_event(
  286. self,
  287. event_id: str,
  288. summary: str,
  289. description: str,
  290. need_notification: bool,
  291. start_time: str,
  292. end_time: str,
  293. auto_record: bool,
  294. ) -> dict:
  295. url = f"{self.API_BASE_URL}/calendar/update_event/{event_id}"
  296. payload: dict[str, Any] = {}
  297. if summary:
  298. payload["summary"] = summary
  299. if description:
  300. payload["description"] = description
  301. if start_time:
  302. payload["start_time"] = start_time
  303. if end_time:
  304. payload["end_time"] = end_time
  305. if need_notification:
  306. payload["need_notification"] = need_notification
  307. if auto_record:
  308. payload["auto_record"] = auto_record
  309. res: dict = self._send_request(url, method="PATCH", payload=payload)
  310. return res
  311. def delete_event(self, event_id: str, need_notification: bool = True) -> dict:
  312. url = f"{self.API_BASE_URL}/calendar/delete_event/{event_id}"
  313. params = {
  314. "need_notification": need_notification,
  315. }
  316. res: dict = self._send_request(url, method="DELETE", params=params)
  317. return res
  318. def list_events(self, start_time: str, end_time: str, page_token: str, page_size: int = 50) -> dict:
  319. url = f"{self.API_BASE_URL}/calendar/list_events"
  320. params = {
  321. "start_time": start_time,
  322. "end_time": end_time,
  323. "page_token": page_token,
  324. "page_size": page_size,
  325. }
  326. res: dict = self._send_request(url, method="GET", params=params)
  327. if "data" in res:
  328. data: dict = res.get("data", {})
  329. return data
  330. return res
  331. def search_events(
  332. self,
  333. query: str,
  334. start_time: str,
  335. end_time: str,
  336. page_token: str,
  337. user_id_type: str = "open_id",
  338. page_size: int = 20,
  339. ) -> dict:
  340. url = f"{self.API_BASE_URL}/calendar/search_events"
  341. payload = {
  342. "query": query,
  343. "start_time": start_time,
  344. "end_time": end_time,
  345. "page_token": page_token,
  346. "user_id_type": user_id_type,
  347. "page_size": page_size,
  348. }
  349. res: dict = self._send_request(url, payload=payload)
  350. if "data" in res:
  351. data: dict = res.get("data", {})
  352. return data
  353. return res
  354. def add_event_attendees(self, event_id: str, attendee_phone_or_email: str, need_notification: bool = True) -> dict:
  355. url = f"{self.API_BASE_URL}/calendar/add_event_attendees"
  356. payload = {
  357. "event_id": event_id,
  358. "attendee_phone_or_email": attendee_phone_or_email,
  359. "need_notification": need_notification,
  360. }
  361. res: dict = self._send_request(url, payload=payload)
  362. if "data" in res:
  363. data: dict = res.get("data", {})
  364. return data
  365. return res
  366. def create_spreadsheet(
  367. self,
  368. title: str,
  369. folder_token: str,
  370. ) -> dict:
  371. url = f"{self.API_BASE_URL}/spreadsheet/create_spreadsheet"
  372. payload = {
  373. "title": title,
  374. "folder_token": folder_token,
  375. }
  376. res: dict = self._send_request(url, payload=payload)
  377. if "data" in res:
  378. data: dict = res.get("data", {})
  379. return data
  380. return res
  381. def get_spreadsheet(
  382. self,
  383. spreadsheet_token: str,
  384. user_id_type: str = "open_id",
  385. ) -> dict:
  386. url = f"{self.API_BASE_URL}/spreadsheet/get_spreadsheet"
  387. params = {
  388. "spreadsheet_token": spreadsheet_token,
  389. "user_id_type": user_id_type,
  390. }
  391. res: dict = self._send_request(url, method="GET", params=params)
  392. if "data" in res:
  393. data: dict = res.get("data", {})
  394. return data
  395. return res
  396. def list_spreadsheet_sheets(
  397. self,
  398. spreadsheet_token: str,
  399. ) -> dict:
  400. url = f"{self.API_BASE_URL}/spreadsheet/list_spreadsheet_sheets"
  401. params = {
  402. "spreadsheet_token": spreadsheet_token,
  403. }
  404. res: dict = self._send_request(url, method="GET", params=params)
  405. if "data" in res:
  406. data: dict = res.get("data", {})
  407. return data
  408. return res
  409. def add_rows(
  410. self,
  411. spreadsheet_token: str,
  412. sheet_id: str,
  413. sheet_name: str,
  414. length: int,
  415. values: str,
  416. ) -> dict:
  417. url = f"{self.API_BASE_URL}/spreadsheet/add_rows"
  418. payload = {
  419. "spreadsheet_token": spreadsheet_token,
  420. "sheet_id": sheet_id,
  421. "sheet_name": sheet_name,
  422. "length": length,
  423. "values": values,
  424. }
  425. res: dict = self._send_request(url, payload=payload)
  426. if "data" in res:
  427. data: dict = res.get("data", {})
  428. return data
  429. return res
  430. def add_cols(
  431. self,
  432. spreadsheet_token: str,
  433. sheet_id: str,
  434. sheet_name: str,
  435. length: int,
  436. values: str,
  437. ) -> dict:
  438. url = f"{self.API_BASE_URL}/spreadsheet/add_cols"
  439. payload = {
  440. "spreadsheet_token": spreadsheet_token,
  441. "sheet_id": sheet_id,
  442. "sheet_name": sheet_name,
  443. "length": length,
  444. "values": values,
  445. }
  446. res: dict = self._send_request(url, payload=payload)
  447. if "data" in res:
  448. data: dict = res.get("data", {})
  449. return data
  450. return res
  451. def read_rows(
  452. self,
  453. spreadsheet_token: str,
  454. sheet_id: str,
  455. sheet_name: str,
  456. start_row: int,
  457. num_rows: int,
  458. user_id_type: str = "open_id",
  459. ) -> dict:
  460. url = f"{self.API_BASE_URL}/spreadsheet/read_rows"
  461. params = {
  462. "spreadsheet_token": spreadsheet_token,
  463. "sheet_id": sheet_id,
  464. "sheet_name": sheet_name,
  465. "start_row": start_row,
  466. "num_rows": num_rows,
  467. "user_id_type": user_id_type,
  468. }
  469. res: dict = self._send_request(url, method="GET", params=params)
  470. if "data" in res:
  471. data: dict = res.get("data", {})
  472. return data
  473. return res
  474. def read_cols(
  475. self,
  476. spreadsheet_token: str,
  477. sheet_id: str,
  478. sheet_name: str,
  479. start_col: int,
  480. num_cols: int,
  481. user_id_type: str = "open_id",
  482. ) -> dict:
  483. url = f"{self.API_BASE_URL}/spreadsheet/read_cols"
  484. params = {
  485. "spreadsheet_token": spreadsheet_token,
  486. "sheet_id": sheet_id,
  487. "sheet_name": sheet_name,
  488. "start_col": start_col,
  489. "num_cols": num_cols,
  490. "user_id_type": user_id_type,
  491. }
  492. res: dict = self._send_request(url, method="GET", params=params)
  493. if "data" in res:
  494. data: dict = res.get("data", {})
  495. return data
  496. return res
  497. def read_table(
  498. self,
  499. spreadsheet_token: str,
  500. sheet_id: str,
  501. sheet_name: str,
  502. num_range: str,
  503. query: str,
  504. user_id_type: str = "open_id",
  505. ) -> dict:
  506. url = f"{self.API_BASE_URL}/spreadsheet/read_table"
  507. params = {
  508. "spreadsheet_token": spreadsheet_token,
  509. "sheet_id": sheet_id,
  510. "sheet_name": sheet_name,
  511. "range": num_range,
  512. "query": query,
  513. "user_id_type": user_id_type,
  514. }
  515. res: dict = self._send_request(url, method="GET", params=params)
  516. if "data" in res:
  517. data: dict = res.get("data", {})
  518. return data
  519. return res
  520. def create_base(
  521. self,
  522. name: str,
  523. folder_token: str,
  524. ) -> dict:
  525. url = f"{self.API_BASE_URL}/base/create_base"
  526. payload = {
  527. "name": name,
  528. "folder_token": folder_token,
  529. }
  530. res: dict = self._send_request(url, payload=payload)
  531. if "data" in res:
  532. data: dict = res.get("data", {})
  533. return data
  534. return res
  535. def add_records(
  536. self,
  537. app_token: str,
  538. table_id: str,
  539. table_name: str,
  540. records: str,
  541. user_id_type: str = "open_id",
  542. ) -> dict:
  543. url = f"{self.API_BASE_URL}/base/add_records"
  544. params = {
  545. "app_token": app_token,
  546. "table_id": table_id,
  547. "table_name": table_name,
  548. "user_id_type": user_id_type,
  549. }
  550. payload = {
  551. "records": self.convert_add_records(records),
  552. }
  553. res: dict = self._send_request(url, params=params, payload=payload)
  554. if "data" in res:
  555. data: dict = res.get("data", {})
  556. return data
  557. return res
  558. def update_records(
  559. self,
  560. app_token: str,
  561. table_id: str,
  562. table_name: str,
  563. records: str,
  564. user_id_type: str,
  565. ) -> dict:
  566. url = f"{self.API_BASE_URL}/base/update_records"
  567. params = {
  568. "app_token": app_token,
  569. "table_id": table_id,
  570. "table_name": table_name,
  571. "user_id_type": user_id_type,
  572. }
  573. payload = {
  574. "records": self.convert_update_records(records),
  575. }
  576. res: dict = self._send_request(url, params=params, payload=payload)
  577. if "data" in res:
  578. data: dict = res.get("data", {})
  579. return data
  580. return res
  581. def delete_records(
  582. self,
  583. app_token: str,
  584. table_id: str,
  585. table_name: str,
  586. record_ids: str,
  587. ) -> dict:
  588. url = f"{self.API_BASE_URL}/base/delete_records"
  589. params = {
  590. "app_token": app_token,
  591. "table_id": table_id,
  592. "table_name": table_name,
  593. }
  594. if not record_ids:
  595. record_id_list = []
  596. else:
  597. try:
  598. record_id_list = json.loads(record_ids)
  599. except json.JSONDecodeError:
  600. raise ValueError("The input string is not valid JSON")
  601. payload = {
  602. "records": record_id_list,
  603. }
  604. res: dict = self._send_request(url, params=params, payload=payload)
  605. if "data" in res:
  606. data: dict = res.get("data", {})
  607. return data
  608. return res
  609. def search_record(
  610. self,
  611. app_token: str,
  612. table_id: str,
  613. table_name: str,
  614. view_id: str,
  615. field_names: str,
  616. sort: str,
  617. filters: str,
  618. page_token: str,
  619. automatic_fields: bool = False,
  620. user_id_type: str = "open_id",
  621. page_size: int = 20,
  622. ) -> dict:
  623. url = f"{self.API_BASE_URL}/base/search_record"
  624. params = {
  625. "app_token": app_token,
  626. "table_id": table_id,
  627. "table_name": table_name,
  628. "user_id_type": user_id_type,
  629. "page_token": page_token,
  630. "page_size": page_size,
  631. }
  632. if not field_names:
  633. field_name_list = []
  634. else:
  635. try:
  636. field_name_list = json.loads(field_names)
  637. except json.JSONDecodeError:
  638. raise ValueError("The input string is not valid JSON")
  639. if not sort:
  640. sort_list = []
  641. else:
  642. try:
  643. sort_list = json.loads(sort)
  644. except json.JSONDecodeError:
  645. raise ValueError("The input string is not valid JSON")
  646. if not filters:
  647. filter_dict = {}
  648. else:
  649. try:
  650. filter_dict = json.loads(filters)
  651. except json.JSONDecodeError:
  652. raise ValueError("The input string is not valid JSON")
  653. payload: dict[str, Any] = {}
  654. if view_id:
  655. payload["view_id"] = view_id
  656. if field_names:
  657. payload["field_names"] = field_name_list
  658. if sort:
  659. payload["sort"] = sort_list
  660. if filters:
  661. payload["filter"] = filter_dict
  662. if automatic_fields:
  663. payload["automatic_fields"] = automatic_fields
  664. res: dict = self._send_request(url, params=params, payload=payload)
  665. if "data" in res:
  666. data: dict = res.get("data", {})
  667. return data
  668. return res
  669. def get_base_info(
  670. self,
  671. app_token: str,
  672. ) -> dict:
  673. url = f"{self.API_BASE_URL}/base/get_base_info"
  674. params = {
  675. "app_token": app_token,
  676. }
  677. res: dict = self._send_request(url, method="GET", params=params)
  678. if "data" in res:
  679. data: dict = res.get("data", {})
  680. return data
  681. return res
  682. def create_table(
  683. self,
  684. app_token: str,
  685. table_name: str,
  686. default_view_name: str,
  687. fields: str,
  688. ) -> dict:
  689. url = f"{self.API_BASE_URL}/base/create_table"
  690. params = {
  691. "app_token": app_token,
  692. }
  693. if not fields:
  694. fields_list = []
  695. else:
  696. try:
  697. fields_list = json.loads(fields)
  698. except json.JSONDecodeError:
  699. raise ValueError("The input string is not valid JSON")
  700. payload = {
  701. "name": table_name,
  702. "fields": fields_list,
  703. }
  704. if default_view_name:
  705. payload["default_view_name"] = default_view_name
  706. res: dict = self._send_request(url, params=params, payload=payload)
  707. if "data" in res:
  708. data: dict = res.get("data", {})
  709. return data
  710. return res
  711. def delete_tables(
  712. self,
  713. app_token: str,
  714. table_ids: str,
  715. table_names: str,
  716. ) -> dict:
  717. url = f"{self.API_BASE_URL}/base/delete_tables"
  718. params = {
  719. "app_token": app_token,
  720. }
  721. if not table_ids:
  722. table_id_list = []
  723. else:
  724. try:
  725. table_id_list = json.loads(table_ids)
  726. except json.JSONDecodeError:
  727. raise ValueError("The input string is not valid JSON")
  728. if not table_names:
  729. table_name_list = []
  730. else:
  731. try:
  732. table_name_list = json.loads(table_names)
  733. except json.JSONDecodeError:
  734. raise ValueError("The input string is not valid JSON")
  735. payload = {
  736. "table_ids": table_id_list,
  737. "table_names": table_name_list,
  738. }
  739. res: dict = self._send_request(url, params=params, payload=payload)
  740. if "data" in res:
  741. data: dict = res.get("data", {})
  742. return data
  743. return res
  744. def list_tables(
  745. self,
  746. app_token: str,
  747. page_token: str,
  748. page_size: int = 20,
  749. ) -> dict:
  750. url = f"{self.API_BASE_URL}/base/list_tables"
  751. params = {
  752. "app_token": app_token,
  753. "page_token": page_token,
  754. "page_size": page_size,
  755. }
  756. res: dict = self._send_request(url, method="GET", params=params)
  757. if "data" in res:
  758. data: dict = res.get("data", {})
  759. return data
  760. return res
  761. def read_records(
  762. self,
  763. app_token: str,
  764. table_id: str,
  765. table_name: str,
  766. record_ids: str,
  767. user_id_type: str = "open_id",
  768. ) -> dict:
  769. url = f"{self.API_BASE_URL}/base/read_records"
  770. params = {
  771. "app_token": app_token,
  772. "table_id": table_id,
  773. "table_name": table_name,
  774. }
  775. if not record_ids:
  776. record_id_list = []
  777. else:
  778. try:
  779. record_id_list = json.loads(record_ids)
  780. except json.JSONDecodeError:
  781. raise ValueError("The input string is not valid JSON")
  782. payload = {
  783. "record_ids": record_id_list,
  784. "user_id_type": user_id_type,
  785. }
  786. res: dict = self._send_request(url, method="POST", params=params, payload=payload)
  787. if "data" in res:
  788. data: dict = res.get("data", {})
  789. return data
  790. return res