当前位置: 首页 > news >正文

飞书应用机器人文件上传

背景:

  接上一篇 flask_apscheduler实现定时推送飞书消息,当检查出的异常结果比较多的时候,群里会有很多推送消息,一条条检查工作量会比较大,且容易出现遗漏。
  现在需要将定时任务执行的结果记录到文件,最好是飞书的云文件中,通过分享云文档的方式分析给响应的人员。

功能:

  飞书群机器人没有文件上传的的功能,满足这个功能需要使用飞书应用机器人。创建飞书应用后,需要完成机器人配置,以及上传文件的权限申请。
在这里插入图片描述在这里插入图片描述
待使用的接口功能:

  1. 实现文件上传,参考文档。通过该接口实现将定时任务执行结果保存上传至飞书云文档。
    在这里插入图片描述2. 更新云文档权限设置,参考文档。修改上传至云文档的文件权限,使组织内成员可阅读。
    在这里插入图片描述

实现:

  • 实现效果:
    在这里插入图片描述

  • 功能代码:

    # -*- coding:UTF-8 -*-"""@ProjectName  : HotelGo2DelonixPmx@FileName     : webhook@Description  : 飞书消息推送@Time         : 2023/9/17 13:36@Author       : Qredsun"""import os
    import requestsclass FeishuApplication():TENANT_ACCESS_TOKEN_URL = 'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal'GET_USER_ID_URL = 'https://open.feishu.cn/open-apis/contact/v3/users/batch_get_id'IM_MESSAGES_URL = 'https://open.feishu.cn/open-apis/im/v1/messages'FILES_UPLOAD_URL = 'https://open.feishu.cn/open-apis/drive/v1/files/upload_all'DRIVE_FILES_URL = 'https://open.feishu.cn/open-apis/drive/v1/files'FILE_PERMISSION = 'https://open.feishu.cn/open-apis/drive/v2/permissions/token/public'CREATE_FOLDER = 'https://open.feishu.cn/open-apis/drive/v1/files/create_folder'def __init__(self, app_id, app_secret):self.app_id = app_idself.app_secret = app_secretself.get_tenant_access_token()self._url_prefix = Noneself._file_url_prefix = Nonedef get_tenant_access_token(self):url = self.TENANT_ACCESS_TOKEN_URLdata = {"app_id"    : self.app_id,"app_secret": self.app_secret}response = requests.post(url, json=data)response.raise_for_status()res_data = response.json()if res_data:self._tenant_access_token = res_data['tenant_access_token']self.headers = {'Content-Type' : 'application/json','Authorization': f'Bearer {self._tenant_access_token}'}logger.debug(f'自建应用更新token成功')return self._tenant_access_tokenelse:logger.error(f'自建应用获取token失败:{response.text}')return Falsedef get_user_open_id(self, user_info):# 单用户id查询url = self.GET_USER_ID_URLparams = {"user_id_type": "open_id"}payload = {"emails" : [],"mobiles": []}if '@' in user_info:payload["emails"].append(user_info)response = requests.post(url, headers=self.headers, params=params, json=payload)elif user_info.isalnum():payload["mobiles"].append(user_info)response = requests.post(url, headers=self.headers, params=params, json=payload)response.raise_for_status()res_data = response.json()if res_data:self.open_id = res_data['data']["user_list"][0]["user_id"]return self.open_idelse:logger.error(f'获取用户{user_info} open_id 失败:{response.text}')return Nonedef send_single_message(self, msg = "single chat msg", open_id = ''):if not open_id:logger.error('缺少对话用户 open_id ')returnurl = self.IM_MESSAGES_URLparams = { "receive_id_type": "open_id" }msgContent = {"text": msg}req = {"receive_id": open_id,  # chat id"msg_type"  : "text","content"   : json.dumps(msgContent)}payload = json.dumps(req)response = requests.request("POST", url, params=params, headers=self.headers, data=payload)response.raise_for_status()res_data = response.json()if res_data:self.open_id = res_data['data']["chat_id"]return Trueelse:logger.error(f'给用户 {self.open_id} 发送消息失败:{response.text}')return Falsedef remove_file_or_folder(self, file_token, file_type='file'):url = self.DRIVE_FILES_URLurl += f'/{file_token}'payload = ''params = {'type':file_type}response = requests.request("DELETE", url, headers=self.headers, params=params, data=payload)response.raise_for_status()result = response.json()if result.get("code") and result.get("code") != 0:logger.error(f'移除文件失败:{response.text}')return Falseelse:logger.debug(f'移除文件成功:{response.text}')return Truedef update_permissions(self, folder_token = '', file_type='file'):url = self.FILE_PERMISSIONurl  = url.replace('token', folder_token)params = {'type': file_type}payload = json.dumps({"comment_entity"            : "anyone_can_view","copy_entity"               : "anyone_can_view","external_access_entity"    : "open","link_share_entity"         : "tenant_editable","manage_collaborator_entity": "collaborator_can_view","security_entity"           : "anyone_can_view","share_entity"              : "anyone"})response = requests.request("PATCH", url, headers=self.headers, data=payload, params=params)response.raise_for_status()result = response.json()if result.get("code") and result.get("code") != 0:logger.error(f'更新文件权限失败:{response.text}')return Falseelse:logger.debug(f'更新文件权限成功:{response.text}')return True"""上传文件"""def upload_file(self, file_path = "../data/result/23_09_25_订房检查任务.xlsx",parent_node = 'ErVlfbxP8lqZ1sdMIWkc11TQn8g'):if not os.path.isfile(file_path):logger.error(f'{file_path} 文件路径没有指定特定文件')returnurl = self.FILES_UPLOAD_URLfile_size = os.path.getsize(file_path)file_name = os.path.basename(file_path)payload = {'file_name'  : file_name,'parent_type': 'explorer','parent_node': parent_node,'size'       : f'{file_size}'}files = [('file', (file_name, open(os.path.abspath(file_path), 'rb'),'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'))]headers = {'Authorization': self.headers['Authorization']}resp = requests.request("POST", url, headers=headers, data=payload, files=files)resp.raise_for_status()result = resp.json()if result.get("code") and result.get("code") != 0:logger.error(f'文件上传失败:{resp.text}')return Falseelse:file_token = result['data']['file_token']logger.debug(f'文件上传成功:{resp.text}')return file_token"""获取文件夹下的清单"""def expoler(self, direction = 'DESC', order_by = 'EditedTime'):url = self.DRIVE_FILES_URLparams = {'direction': direction,'order_by' : order_by}resp = requests.request("GET", url, headers=self.headers, params=params)resp.raise_for_status()result = resp.json()if result.get("code") and result.get("code") != 0:logger.error(f'获取云空间列表失败:{resp.text}')return Noneelse:self.files = result['data']['files']self.update_url_prefix()logger.debug(f'获取云空间列表成功: {self.files}')return self.files"""新建文件夹"""def create_folder(self, folder_name = "", folder_token = ""):url = self.CREATE_FOLDERpayload = {"folder_token": folder_token,"name"        : folder_name}resp = requests.request("POST", url, headers=self.headers, json=payload)resp.raise_for_status()result = resp.json()if result.get("code") and result.get("code") != 0:logger.error(f'新建文件夹失败:{resp.text}')return Noneelse:self.folder_token = result['data']['token']logger.debug(f'新建文件夹成功: {self.folder_token}')folder_url = result['data']['url']start_index = folder_url.find('//') + 2r_index = folder_url.find('/', start_index) + 1self._url_prefix = folder_url[:r_index]logger.debug(f'更新应用地址前缀:{self._url_prefix}')self._file_url_prefix = self._url_prefix + 'file/'logger.debug(f'更新云文件前缀:{self._file_url_prefix}')return self.folder_tokendef update_url_prefix(self):for obj in self.files:if obj['type'] == 'folder':obj_url = obj['url']start_index = obj_url.find('//') + 2r_index = obj_url.find('/', start_index) + 1self._url_prefix = obj_url[:r_index]logger.debug(f'更新应用地址前缀:{self._url_prefix}')self._file_url_prefix = self._url_prefix + 'file/'logger.debug(f'更新云文件前缀:{self._file_url_prefix}')breakreturn self._url_prefixdef upload_schedule_result(upload_file, app_id, app_secret):robot = FeishuApplication(app_id, app_secret)default_folder = 'schedule_demo'file_path = upload_fileparent_node = ''robot.expoler()if not robot.files.__len__():# 创建文件夹result = robot.create_folder(default_folder)if result:parent_node = resultelse:for file in robot.files:if default_folder == file['name']:parent_node = file['parent_token']parent_node = file['token']break# 移除文件robot.remove_file_or_folder('O3MgbgYKgo7NgtxUNc4cqkQZnWe')upload_file_token = robot.upload_file(file_path=file_path, parent_node=parent_node)if upload_file_token:result = robot.update_permissions(upload_file_token)if result:file_url = f'{robot._file_url_prefix}{upload_file_token}'logger.debug(f'待分享的文件url: {file_url}')else:file_url = ''logger.debug('上传结果至飞书失败')return file_urlif __name__ == '__main__':upload_file = "../data/result/23_09_24_订房检查任务.xlsx"app_id = 'XXXX'app_secret = 'XXX'upload_schedule_result(upload_file, app_id, app_secret)
    

相关文章:

飞书应用机器人文件上传

背景: 接上一篇 flask_apscheduler实现定时推送飞书消息,当检查出的异常结果比较多的时候,群里会有很多推送消息,一条条检查工作量会比较大,且容易出现遗漏。   现在需要将定时任务执行的结果记录到文件,…...

高版本Mac系统如何打开低版本的Xcode

这里写目录标题 前言解决方案 前言 大家偶尔也碰见过更新Mac系统后经常发现低版本的Xcode用不了的情况吧.基本每年大版本更新之后都可以在各个开发群里碰见问这个问题的. 解决方案 打开访达->应用程序->选中打不开的那个版本的Xcode并且右键显示包内容->Contents-…...

测试H5需要注意的交互测试用例点

H5(HTML5)是一种用于构建网页的标准,可以实现丰富的交互和功能。测试H5交互通常涉及到验证网页在各种情况下的行为,包括用户输入、按钮点击、页面加载等等。以下是一些可能的H5交互测试用例: 页面加载: 验…...

1014蓝桥算法双周赛,学习算法技巧,助力蓝桥杯

家人们,我来免费给大家送福利了!!! 【1014蓝桥算法双周赛 】 背景 蓝桥杯全国软件和信息技术专业人才大赛是由工业和信息化部人才交流中心举办的全国性IT学科赛事。参赛高校超过1200余所,累计参赛人数超过40万人。该…...

C语言之通讯录的实现篇

目录 test.c 主菜单menu 创建通讯录con 初始化通讯录InitContact 增加个人信息AddContact 展示个人信息ShowContact 删除个人信息DelContact 查找个人信息SearchContact 修改个人信息ModifyContact test.c总代码 contact.h 头文件包含 PeoInfo_个人信息的设置声…...

如何降低海康、大华等网络摄像头调用的高延迟问题(二)

目录 1.RTSP介绍 2.解决办法1 3.解决办法2 1.RTSP介绍 RTSP(Real-time Streaming Protocol)是一种用于实时流媒体传输的网络协议。它被设计用于在服务器和客户端之间传输音频、视频以及其他流媒体数据。 RTSP协议允许客户端通过与服务器建立RTSP会话…...

centos清理日志和缓存

今天使用redmine修改密码,修改报错,再去试试创建用户,创建用户的页面直接报错显示不出来。然后看了一下服务器,发现服务器磁盘空间全部占满了。 CentOS系统也会在使用很长一段时间后出现硬盘空间开始不够的情况,而这并…...

排序算法的稳定性

什么是排序算法的稳定性? 排序算法的稳定性: 假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i] r[j],且 r[i…...

kafka属性说明

kafka中关于一些字段说明 groupId :标识消费者分组id,如果多个消费者id相同,就表示这几个消费者是一组,当一组多个消费者消费同一个topic时,一组中只会有一个成功消费 代码如下 这时只会有一条消息被消费...

STM32F4使用ucosii时操作浮点数卡死的问题

STM32F4使用ucosii时操作浮点数卡死的问题_stm32 fpu float 程序跑不起来_shou撕代码的博客-CSDN博客...

python练习:赋值运算 => 输入身高,体重,求BMI = 体重(kg)/身高(m)的平方。

赋值运算 > 输入身高,体重,求BMI 体重(kg)/身高(m)的平方。 代码: height float(input(‘请输入您的身高(m):’)) weight float(input(‘请输入您的体重(kg):’))…...

PCL ICP精配准(点到点)

文章目录 一、简介二、实现过程三、实现效果参考资料一、简介 迭代最近点(ICP)算法作为是目前最常用的刚性点集配准方法,它有着简单、计算复杂度低等优点,该算法的具体计算过程如下: (1)在目标点云P中取点集 p i ∈ P p_i∈P p...

Redis数据缓存(Redis的缓存击穿和穿透的区别)

Redis是一个高性能的内存中数据存储系统,可以使用它作为数据缓存。使用Redis作为数据缓存可以提高应用程序的性能和可伸缩性,因为Redis运行在内存中,读写速度非常快。 Redis支持许多数据结构,如字符串、哈希表、列表、集合和有序…...

八大排序算法(含时间复杂度、空间复杂度、算法稳定性)

文章目录 八大排序算法(含时间复杂度、空间复杂度、算法稳定性)1、(直接)插入排序1.1、算法思想1.2、排序过程图解1.3、排序代码 2、希尔排序3、冒泡排序3.1、算法思想3.2、排序过程图解3.3、排序代码 4、(简单)选择排序4.1、算法…...

【C++】:引用的概念/引用的特性/常引用/引用的使用场景/传值与传引用的效率比较/引用和指针的区别/内联函数的概念/内联函数的特性

引用的概念 引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间 比如:李逵,在家称为"铁牛",江湖上人称"黑旋风&…...

Python点云处理(十七)点云地面点提取——基于格网算法

目录 0 简述1 算法流程2 优缺点3 实现4 效果5 结语0 简述 提取地面点是点云数据分析和处理中的重要任务,而点云格网法是一种常用的地面点提取方法。点云格网法(Grid-based Method),通过将点云数据划分为网格单元,根据高程值分析来实现地面点的提取。 1 算法流程 步骤1:…...

Flink 中kafka broker缩容导致Task一直重启

背景 Flink版本 1.12.2 Kafka 客户端 2.4.1 在公司的Flink平台运行了一个读Kafka计算DAU的流程序,由于公司Kafka的缩容,直接导致了该程序一直在重启,重启了一个小时都还没恢复(具体的所容操作是下掉了四台kafka broker&#xff0…...

纯前端js中使用sheetjs导出excel,并且合并标题

先定义变量----用的是Vue2 ,以下在vue的data:{}中定义--------------//空格占位符 headerTopTitle: [患者信息, , , , , , , , , 入出院信息, , , , , , , 病案首页中的出院主要诊断, ,出院其他诊断(病案首页中原始信息), , , , ,…...

猫眼 校园招聘_1面

(1)打包和构建工具 vite 和 webpack 功能 1. 构建原理: Webpack 是一个静态模块打包器,通过对项目中的JavaScript、css、Image 等文件进行分析,生成对应的静态资源,并且通过一些插件和加载器来实现各种功…...

博弈论——博弈信息结构

博弈信息结构 0 引言 在一个博弈构成中,博弈信息结构是不可或缺要素。博弈信息,顾名思义,就是在博弈中,博弈方对于信息的了解。知己知彼,百战不殆。和短兵相接的战争一样,只有充分了解自己的优劣势&#x…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器

一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

剑指offer20_链表中环的入口节点

链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

从零实现STL哈希容器:unordered_map/unordered_set封装详解

本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP

编辑-虚拟网络编辑器-更改设置 选择桥接模式&#xff0c;然后找到相应的网卡&#xff08;可以查看自己本机的网络连接&#xff09; windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置&#xff0c;选择刚才配置的桥接模式 静态ip设置&#xff1a; 我用的ubuntu24桌…...

20个超级好用的 CSS 动画库

分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码&#xff0c;而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库&#xff0c;可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画&#xff0c;可以包含在你的网页或应用项目中。 3.An…...

Netty从入门到进阶(二)

二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架&#xff0c;用于…...

云原生安全实战:API网关Kong的鉴权与限流详解

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关&#xff08;API Gateway&#xff09; API网关是微服务架构中的核心组件&#xff0c;负责统一管理所有API的流量入口。它像一座…...

【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看

文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...

Python 实现 Web 静态服务器(HTTP 协议)

目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1&#xff09;下载安装包2&#xff09;配置环境变量3&#xff09;安装镜像4&#xff09;node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1&#xff09;使用 http-server2&#xff09;详解 …...

探索Selenium:自动化测试的神奇钥匙

目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...