feishu.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. import json
  2. from app.infra.shared import AsyncHttpClient
  3. class Feishu:
  4. # 服务号分组群发监测机器人
  5. server_account_publish_monitor_bot = "https://open.feishu.cn/open-apis/bot/v2/hook/380fdecf-402e-4426-85b6-7d9dbd2a9f59"
  6. # 外部服务号投流监测机器人
  7. outside_gzh_monitor_bot = "https://open.feishu.cn/open-apis/bot/v2/hook/0899d43d-9f65-48ce-a419-f83ac935bf59"
  8. # 长文 daily 报警机器人
  9. long_articles_bot = "https://open.feishu.cn/open-apis/bot/v2/hook/b44333f2-16c0-4cb1-af01-d135f8704410"
  10. # 测试环境报警机器人
  11. long_articles_bot_dev = "https://open.feishu.cn/open-apis/bot/v2/hook/f32c0456-847f-41f3-97db-33fcc1616bcd"
  12. # 长文任务报警群
  13. long_articles_task_bot = "https://open.feishu.cn/open-apis/bot/v2/hook/223b3d72-f2e8-40e0-9b53-6956e0ae7158"
  14. # cookie 监测机器人
  15. cookie_monitor_bot = "https://open.feishu.cn/open-apis/bot/v2/hook/51b9c83a-f50d-44dd-939f-bcd10ac6c55a"
  16. # rank_bot
  17. rank_monitor_bot = "https://open.feishu.cn/open-apis/bot/v2/hook/f9dae7ba-decf-436b-b438-41994c35af1e"
  18. def __init__(self):
  19. self.token = None
  20. self.headers = {"Content-Type": "application/json"}
  21. self.mention_all = {
  22. "content": "<at id=all></at>\n",
  23. "tag": "lark_md",
  24. }
  25. self.not_mention = {}
  26. async def fetch_token(self):
  27. url = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal/"
  28. post_data = {
  29. "app_id": "cli_a51114cf8bf8d00c",
  30. "app_secret": "cNoTAqMpsAm7mPBcpCAXFfvOzCNL27fe",
  31. }
  32. async with AsyncHttpClient(default_headers=self.headers) as client:
  33. response = await client.post(url=url, json=post_data)
  34. tenant_access_token = response["tenant_access_token"]
  35. self.token = tenant_access_token
  36. class FeishuSheetApi(Feishu):
  37. async def prepend_value(self, sheet_token, sheet_id, ranges, values):
  38. insert_value_url = "https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{}/values_prepend".format(
  39. sheet_token
  40. )
  41. headers = {
  42. "Authorization": "Bearer " + self.token,
  43. "contentType": "application/json; charset=utf-8",
  44. }
  45. body = {
  46. "valueRange": {"range": "{}!{}".format(sheet_id, ranges), "values": values}
  47. }
  48. async with AsyncHttpClient() as client:
  49. response = await client.post(
  50. url=insert_value_url, json=body, headers=headers
  51. )
  52. print(response)
  53. async def insert_value(self, sheet_token, sheet_id, ranges, values):
  54. insert_value_url = (
  55. "https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/{}/values".format(
  56. sheet_token
  57. )
  58. )
  59. # self.token = 't-g104bpfHNZN45BVJWFSQEM6WD45AAI4FNRWXCZVK'
  60. headers = {
  61. "Authorization": "Bearer " + self.token,
  62. "contentType": "application/json; charset=utf-8",
  63. }
  64. body = {
  65. "valueRange": {"range": "{}!{}".format(sheet_id, ranges), "values": values}
  66. }
  67. async with AsyncHttpClient() as client:
  68. response = await client.put(
  69. url=insert_value_url, json=body, headers=headers
  70. )
  71. class FeishuBotApi(Feishu):
  72. @classmethod
  73. def create_feishu_columns_sheet(
  74. cls,
  75. sheet_type,
  76. sheet_name,
  77. display_name,
  78. width="auto",
  79. vertical_align="top",
  80. horizontal_align="left",
  81. number_format=None,
  82. ):
  83. match sheet_type:
  84. case "plain_text":
  85. return {
  86. "name": sheet_name,
  87. "display_name": display_name,
  88. "width": width,
  89. "data_type": "text",
  90. "vertical_align": vertical_align,
  91. "horizontal_align": horizontal_align,
  92. }
  93. case "lark_md":
  94. return {
  95. "name": sheet_name,
  96. "display_name": display_name,
  97. "data_type": "lark_md",
  98. }
  99. case "number":
  100. return {
  101. "name": sheet_name,
  102. "display_name": display_name,
  103. "data_type": "number",
  104. "format": number_format,
  105. "width": width,
  106. }
  107. case "date":
  108. return {
  109. "name": sheet_name,
  110. "display_name": display_name,
  111. "data_type": "date",
  112. "date_format": "YYYY/MM/DD",
  113. }
  114. case "options":
  115. return {
  116. "name": sheet_name,
  117. "display_name": display_name,
  118. "data_type": "options",
  119. }
  120. case _:
  121. return {
  122. "name": sheet_name,
  123. "display_name": display_name,
  124. "width": width,
  125. "data_type": "text",
  126. "vertical_align": vertical_align,
  127. "horizontal_align": horizontal_align,
  128. }
  129. # 表格形式
  130. def create_feishu_table(self, title, columns, rows, mention):
  131. table_base = {
  132. "header": {
  133. "template": "blue",
  134. "title": {"content": title, "tag": "plain_text"},
  135. },
  136. "elements": [
  137. self.mention_all if mention else self.not_mention,
  138. {
  139. "tag": "table",
  140. "page_size": len(rows) + 1,
  141. "row_height": "low",
  142. "header_style": {
  143. "text_align": "left",
  144. "text_size": "normal",
  145. "background_style": "grey",
  146. "text_color": "default",
  147. "bold": True,
  148. "lines": 1,
  149. },
  150. "columns": columns,
  151. "rows": rows,
  152. },
  153. ],
  154. }
  155. return table_base
  156. def create_feishu_bot_obj(self, title, mention, detail):
  157. """
  158. create feishu bot object
  159. """
  160. return {
  161. "elements": [
  162. {
  163. "tag": "div",
  164. "text": self.mention_all if mention else self.not_mention,
  165. },
  166. {
  167. "tag": "div",
  168. "text": {
  169. "content": json.dumps(detail, ensure_ascii=False, indent=4),
  170. "tag": "lark_md",
  171. },
  172. },
  173. ],
  174. "header": {"title": {"content": title, "tag": "plain_text"}},
  175. }
  176. # bot
  177. async def bot(
  178. self, title, detail, mention=True, table=False, env="long_articles_task"
  179. ):
  180. match env:
  181. case "dev":
  182. url = self.long_articles_bot_dev
  183. case "prod":
  184. url = self.long_articles_bot
  185. case "outside_gzh_monitor":
  186. url = self.outside_gzh_monitor_bot
  187. case "server_account_publish_monitor":
  188. url = self.server_account_publish_monitor_bot
  189. case "long_articles_task":
  190. url = self.long_articles_task_bot
  191. case "cookie_monitor":
  192. url = self.cookie_monitor_bot
  193. case "rank_bot":
  194. url = self.rank_monitor_bot
  195. case _:
  196. url = self.long_articles_bot_dev
  197. headers = {"Content-Type": "application/json"}
  198. if table:
  199. card = self.create_feishu_table(
  200. title=title,
  201. columns=detail["columns"],
  202. rows=detail["rows"],
  203. mention=mention,
  204. )
  205. else:
  206. card = self.create_feishu_bot_obj(
  207. title=title, mention=mention, detail=detail
  208. )
  209. data = {"msg_type": "interactive", "card": card}
  210. async with AsyncHttpClient() as client:
  211. res = await client.post(url=url, headers=headers, json=data)
  212. return res