def check_drive_file_permission(self, user_access_token, file_token, file_type, perm): """判断协作者是否有某权限 :type self: OpenLark :param user_access_token: user_access_token :type user_access_token: str :param file_token: 文件的 token :type file_token: str :param file_type: 文件类型 :type file_type: DriveFileType :param perm: 权限 :type perm: DriveFilePermission 该接口用于根据 file_token 判断当前登录用户是否具有某权限 https://open.feishu.cn/document/ukTMukTMukTM/uYzN3UjL2czN14iN3cTN """ url = self._gen_request_url( '/open-apis/drive/permission/member/permitted') body = { 'token': file_token, 'type': converter_enum(file_type), 'perm': converter_enum(perm), } res = self._post(url, body=body, auth_token=user_access_token) return res['data']['is_permitted']
def delete_drive_file(self, user_access_token, file_token, file_type): """删除云空间文件 :type self: OpenLark :param user_access_token: user_access_token :type user_access_token: str :param file_token: 文件的 token :type file_token: str :param file_type: 文档类型,可选值为 doc 和 sheet :type file_type: DriveFileType :return: 文件夹元信息 :rtype: DriveDeleteFile 本文档包含两个接口,分别用于删除 Doc 和 Sheet,对应的文档类型请调用对应的接口 文档只能被文档所有者删除,文档被删除后将会放到回收站里 https://open.feishu.cn/document/ukTMukTMukTM/uATM2UjLwEjN14CMxYTN """ if converter_enum(file_type) == 'doc': url = self._gen_request_url( '/open-apis/drive/explorer/v2/file/docs/{}'.format(file_token)) elif converter_enum(file_type) == 'sheet': url = self._gen_request_url( '/open-apis/drive/explorer/v2/file/spreadsheets/{}'.format( file_token)) else: raise LarkInvalidArguments( msg='delete file type should be doc or sheet') res = self._delete(url, auth_token=user_access_token) return make_datatype(DriveDeleteFile, res['data'])
def add_drive_file_permission(self, user_access_token, file_token, file_type, members): """增加权限 :type self: OpenLark :param user_access_token: user_access_token :type user_access_token: str :param file_token: 文件的 token :type file_token: str :param file_type: 文件类型 :type file_type: DriveFileType :param members: 要添加的权限的人 :type members: list[DriveFileUserPermission] :rtype: list[DriveFileUserPermission] 该接口用于根据 file_token 给用户增加文档的权限 https://open.feishu.cn/document/ukTMukTMukTM/uMzNzUjLzczM14yM3MTN """ url = self._gen_request_url( '/open-apis/drive/permission/member/create') body = { 'token': file_token, 'type': converter_enum(file_type), 'members': [i.as_dict() for i in members] } res = self._post(url, body=body, auth_token=user_access_token) if res['data'].get('is_all_success', False): return [] return unmarshal_drive_user_permission( res['data']['fail_members']) # type: List[DriveFileUserPermission]
def get_drive_file_permissions(self, user_access_token, file_token, file_type): """获取协作者列表 :type self: OpenLark :param user_access_token: user_access_token :type user_access_token: str :param file_token: 文件的 token :type file_token: str :param file_type: 文件类型 :type file_type: DriveFileType :rtype list[DriveFileUserPermission] 该接口用于根据 file_token 查询协作者,目前包括人("user")和群("chat") 你能获取到协作者列表的前提是你对该文档有权限 https://open.feishu.cn/document/ukTMukTMukTM/uATN3UjLwUzN14CM1cTN """ url = self._gen_request_url('/open-apis/drive/permission/member/list') body = { 'type': converter_enum(file_type), 'token': file_token, } res = self._post(url, body=body, auth_token=user_access_token) return unmarshal_drive_user_permission( res['data']['members'], open_id_type='user', open_id_key='member_open_id', chat_id_type='chat', chat_id_key='member_open_id' ) # type: List[DriveFileUserPermission]
def upload_approval_file(self, name, filetype, content): """审批所需要的文件上传 :type self: OpenLark :param name: 文件名,需包含文件扩展名,如“文件.doc :type name: str :param filetype: 文件类型,只能是 image 和 attachment 之一 :type filetype: ApprovalUploadFileType :param content: 文件,支持路径、bytes、BytesIO :return: 返回的第一个是可以用于审批的 code,第二个是图片或者文件的 URL :rtype: Tuple[str, str] """ content = to_file_like(content) url = self._gen_request_url('/approval/openapi/v1/file/upload', app='approval') body = { 'name': name, 'type': converter_enum(filetype), } files = {'content': content} res = self._post(url=url, body=body, files=files, with_tenant_token=True) data = res['data'] code = data.get('code', '') # type: str url = data.get('url', '') # type: str return code, url
def merge_drive_sheet_cells(self, user_access_token, sheet_token, sheet_id, range, merge_type): """合并单元格 :type self: OpenLark :param user_access_token: user_access_token :type user_access_token: str :param sheet_token: 文件的 token 列表 :type sheet_token: str :param sheet_id: 作为表格唯一识别参数 :type sheet_id: str :param range: 范围,形如:'A1:D2' :type range: str :param merge_type: lock 信息 :type merge_type: DriveSheetMergeType :rtype: str 该接口用于根据 sheet_token 和维度信息合并单元格;单次操作不超过5000行,100列。 https://open.feishu.cn/document/ukTMukTMukTM/ukDNzUjL5QzM14SO0MTN """ url = self._gen_request_url('/open-apis/sheet/v2/spreadsheets/{}/merge_cells'.format(sheet_token)) body = { 'range': join_range(sheet_id, range), 'mergeType': converter_enum(merge_type), } self._post(url, body=body, auth_token=user_access_token)
def reply_meeting(self, room_id, uid, original_time, status): """回复会议室日程实例 :type self: OpenLark :param room_id: 会议室的 ID :type room_id: str :param uid: 会议室的日程 ID :type uid: str :param original_time: 日程实例原始时间,非重复日程必为0。重复日程若为0则表示回复其所有实例,否则表示回复单个实例。 :type original_time: int :param status: 回复状态,NOT_CHECK_IN 表示未签到,ENDED_BEFORE_DUE 表示提前结束 :type status: MeetingReplyStatus :return: 查询会议室忙闲的起始时间(与请求参数完全相同), 查询会议室忙闲的结束时间(与请求参数完全相同), Dict['会议室ID', List[忙碌时间]] :rtype: (datetime.datetime, datetime.datetime, dict[str, list[RoomFreeBusy]]) https://open.feishu.cn/document/ukTMukTMukTM/uIDOyUjLygjM14iM4ITN """ body = { 'room_id': room_id, 'uid': uid, 'original_time': original_time, 'status': converter_enum(status), } url = self._gen_request_url('/open-apis/meeting_room/instance/reply') self._post(url, body=body, with_tenant_token=True)
def create_drive_file(self, user_access_token, folder_token, title, file_type): """创建云空间文件 :type self: OpenLark :param user_access_token: user_access_token :type user_access_token: str :param folder_token: 文件夹的 token :type folder_token: str :param title: 文档标题 :type title: str :param file_type: 文档类型,可选值为 doc 和 sheet :type file_type: DriveFileType :return: 文件夹元信息 :rtype: DriveCreateFile 该接口用于根据 folder_token 创建 Docs或 Sheets 。 https://open.feishu.cn/document/ukTMukTMukTM/uQTNzUjL0UzM14CN1MTN """ url = self._gen_request_url( '/open-apis/drive/explorer/v2/file/{}'.format(folder_token)) body = { 'title': title, 'type': converter_enum(file_type, ranges=[DriveFileType.doc, DriveFileType.sheet]), } res = self._post(url, body=body, auth_token=user_access_token) return make_datatype(DriveCreateFile, res['data'])
def update_drive_file_permission(self, user_access_token, file_token, file_type, member, perm=DriveFilePermission.view, is_notify=None): """更新协作者权限 :type self: OpenLark :param user_access_token: user_access_token :type user_access_token: str :param file_token: 文件的 token :type file_token: str :param file_type: 文件类型 :type file_type: DriveFileType :param member: 成员 :type member: DriveFileUser :param perm: 权限 :type perm: DriveFilePermission :param is_notify: 是否通知 :type is_notify: bool 该接口用于根据 file_token 更新文档协作者的权限 https://open.feishu.cn/document/ukTMukTMukTM/ucTN3UjL3UzN14yN1cTN """ url = self._gen_request_url( '/open-apis/drive/permission/member/update') body = member.as_dict() body['token'] = file_token body['type'] = converter_enum(file_type) body['perm'] = converter_enum(perm) if is_notify is not None: body['notify_lark'] = is_notify self._post(url, body=body, auth_token=user_access_token)
def get_visible_apps(self, user_id=None, open_id=None, page_size=20, page_token='', lang=I18NType.zh_cn): """获取应用在企业内的可用范围 :type self: OpenLark :param user_id: 目标用户 user_id,与 open_id 至少给其中之一,user_id 优先于 open_id :type user_id: str :param open_id: 目标用户 open_id :type open_id: str :param page_size: 本次拉取用户列表最大个数(最大值 1000 ,0 自动最大个数 ) :type page_size: int :param page_token: 分页拉取用户列表起始位置标示,不填表示从头开始 :type page_token: str :param lang: 优先展示的应用信息的语言版本(zh_cn:中文,en_us:英文,ja_jp:日文) :type lang: I18NType :return: 是否还有更多, page_token, page_size, 总数, 语言, 应用列表 :rtype: (bool, str, int, int, I18NType, list[App]) 该接口用于查询应用在该企业内可以被使用的范围,只能被企业自建应用调用且需要“获取应用信息”权限。 https://open.feishu.cn/document/ukTMukTMukTM/uIjM3UjLyIzN14iMycTN """ url = self._gen_request_url('/open-apis/application/v1/user/visible_apps?') if user_id: url = '{}&user_id={}'.format(url, user_id) elif open_id: url = '{}&open_id={}'.format(url, open_id) else: raise LarkInvalidArguments(msg='empty user_id and open_id') if page_token: url = '{}&page_token={}'.format(url, page_token) if page_size: url = '{}&page_size={}'.format(url, page_size) if lang: url = '{}&lang={}'.format(url, converter_enum(lang)) res = self._get(url, with_tenant_token=True) data = res['data'] apps = [make_datatype(App, i) for i in data.get('app_list', [])] # type: List[App] has_more = bool(data.get('has_more', False)) # type: bool lang = I18NType(data.get('lang', 'zh_cn')) # type: I18NType page_size = data.get('page_size') # type: int page_token = data.get('page_token') # type: str total_count = data.get('total_count') # type: int return has_more, page_token, page_size, total_count, lang, apps
def copy_drive_file(self, user_access_token, file_token, file_type, dst_folder_token, dst_title, permission_needed=False, comment_needed=False): """复制云空间文件 :type self: OpenLark :param user_access_token: user_access_token :type user_access_token: str :param file_token: 文件的 token :type file_token: str :param file_type: 文档类型,可选值为 doc 和 sheet :type file_type: DriveFileType :param dst_folder_token:目标文件夹 token :type dst_folder_token: str :param dst_title: 目标文档标题 :type dst_title: str :param permission_needed: 同时复制权限 :type permission_needed: bool :param comment_needed: 同时复制评论 :type comment_needed: bool :return: 复制文件的返回值 :rtype: DriveCopyFile 该接口用于根据 file_token 复制 docs 或 sheets 。 https://open.feishu.cn/document/ukTMukTMukTM/uYTNzUjL2UzM14iN1MTN """ url = self._gen_request_url( '/open-apis/drive/explorer/v2/file/copy/files/{}'.format( file_token)) body = { 'type': converter_enum(file_type), 'dstFolderToken': dst_folder_token, 'dstName': dst_title, 'permissionNeeded': permission_needed, 'CommentNeeded': comment_needed } res = self._post(url, body=body, auth_token=user_access_token) return make_datatype(DriveCopyFile, res['data'])
def search_drive_file(self, user_access_token, key, owner_open_ids=None, chat_open_ids=None, docs_types=None, count=50, offset=0): """文档搜索 :type self: OpenLark :param user_access_token: user_access_token :type user_access_token: str :param key: 搜索的关键词 :type key: str :param owner_open_ids: 文档所有人 :type owner_open_ids: list[str] :param chat_open_ids: 文档所在群 :type chat_open_ids: list[str] :param docs_types: 文档类型,支持:"doc", "sheet", "slide", "bitable", "mindnote", "file", "wiki" :type docs_types: list[DriveFileType] :param count: 个数 :type count: int :param offset: 偏移 :type offset: int :return: 文件元信息 :rtype: (bool, int, list[DriveFileMeta]) 该接口用于根据搜索条件进行文档搜索 https://open.feishu.cn/document/ukTMukTMukTM/ugDM4UjL4ADO14COwgTN """ url = self._gen_request_url('/open-apis/suite/docs-api/search/object') body = { 'search_key': key, 'count': count, 'offset': offset, } if owner_open_ids: body['owner_ids'] = owner_open_ids if chat_open_ids: body['chat_ids'] = chat_open_ids if docs_types: body['docs_types'] = [converter_enum(i) for i in docs_types] res = self._post(url, body=body, auth_token=user_access_token) has_more = res['data']['has_more'] total = res['data']['total'] entities = [make_datatype(DriveFileMeta, i) for i in res['data']['docs_entities']] return has_more, total, entities
def get_installed_apps(self, page_size=20, page_token='', lang=I18NType.zh_cn, status=-1): """获取企业安装的应用 :type self: OpenLark :param page_size: 本次拉取用户列表最大个数(最大值 1000 ,0 自动最大个数 ) :type page_size: int :param page_token: 分页拉取用户列表起始位置标示,不填表示从头开始 :type page_token: str :param lang: 优先展示的应用信息的语言版本(zh_cn:中文,en_us:英文,ja_jp:日文) :type lang: I18NType :param status: 要返回的应用的状态,0:停用;1:启用;-1:全部 :type status: int :return: 是否还有更多, page_token, page_size, 总数, 语言, 应用列表 :rtype: (bool, str, int, int, I18NType, list[App]) 该接口用于查询企业安装的应用列表,只能被企业自建应用调用且需要“获取应用信息”权限。 https://open.feishu.cn/document/ukTMukTMukTM/uYDN3UjL2QzN14iN0cTN """ url = self._gen_request_url('/open-apis/application/v3/app/list?') if page_token: url = '{}&page_token={}'.format(url, page_token) if page_size: url = '{}&page_size={}'.format(url, page_size) if lang: url = '{}&lang={}'.format(url, converter_enum(lang)) if status in [0, 1, -1]: url = '{}&status={}'.format(url, status) res = self._get(url, with_tenant_token=True) data = res['data'] apps = [make_datatype(App, i) for i in data.get('app_list', [])] # type: List[App] has_more = bool(data.get('has_more', False)) # type: bool lang = I18NType(data.get('lang', 'zh_cn')) # type: I18NType page_size = data.get('page_size') # type: int page_token = data.get('page_token') # type: str total_count = data.get('total_count') # type: int return has_more, page_token, page_size, total_count, lang, apps
def transfer_drive_file_owner(self, user_access_token, file_token, file_type, owner, remove_old_owner=False, notify_old_owner=True): """转移拥有者 :type self: OpenLark :param user_access_token: user_access_token :type user_access_token: str :param file_token: 文件的 token :type file_token: str :param file_type: 文件类型 :type file_type: DriveFileType :param owner: 要转移的人 :type owner: DriveFileUser :param remove_old_owner: 转移后删除旧 owner 的权限,默认为 False :type remove_old_owner: bool :param notify_old_owner: 通知旧 owner,默认为 True :type notify_old_owner: bool 该接口用于根据文档信息和用户信息转移文档的所有者。 https://open.feishu.cn/document/ukTMukTMukTM/uQzNzUjL0czM14CN3MTN """ url = self._gen_request_url( '/open-apis/drive/permission/member/transfer') body = { 'type': converter_enum(file_type), 'token': file_token, 'owner': owner.as_dict(), 'remove_old_owner': remove_old_owner, 'cancel_notify': not notify_old_owner } self._post(url, body=body, auth_token=user_access_token)
def delete_drive_file_permission(self, user_access_token, file_token, file_type, member): """移除协作者权限 :type self: OpenLark :param user_access_token: user_access_token :type user_access_token: str :param file_token: 文件的 token :type file_token: str :param file_type: 文件类型 :type file_type: DriveFileType :param member: 成员 :type member: DriveFileUser 该接口用于根据 file_token 移除文档协作者的权限 https://open.feishu.cn/document/ukTMukTMukTM/uYTN3UjL2UzN14iN1cTN """ url = self._gen_request_url( '/open-apis/drive/permission/member/delete') body = member.as_dict() body['token'] = file_token body['type'] = converter_enum(file_type) self._post(url, body=body, auth_token=user_access_token)
def update_drive_file_public_permission(self, user_access_token, file_token, file_type, copy_print_export_status=None, comment=None, tenant_shareable=None, link_share_entity=None, external_access=None, invite_external=None): """更新文档公共设置 :type self: OpenLark :param user_access_token: user_access_token :type user_access_token: str :param file_token: 文件的 token :type file_token: str :param file_type: 文件类型 :type file_type: DriveFileType :param copy_print_export_status: 可创建副本/打印/导出/复制设置(不传则保持原值): true - 所有可访问此文档的用户 false - 有编辑权限的用户 :type copy_print_export_status: bool :param comment: 可评论设置(不传则保持原值): true - 所有可访问此文档的用户 false - 有编辑权限的用户 :type comment: bool :param tenant_shareable: 租户内用户是否有共享权限(不传则保持原值) :type tenant_shareable: bool :param link_share_entity: 链接共享(不传则保持原值): "tenant_readable" - 组织内获得链接的人可阅读 "tenant_editable" - 组织内获得链接的人可编辑 "anyone_readable" - 获得链接的任何人可阅读 "anyone_editable" - 获得链接的任何人可编辑 :type link_share_entity: DriveFilePublicLinkSharePermission :param external_access: 是否允许分享到租户外开关(不传则保持原值) :type external_access: bool :param invite_external: 非owner是否允许邀请外部人(不传则保持原值) :type invite_external: bool 该接口用于根据 file_token 更新文档的公共设置 https://open.feishu.cn/document/ukTMukTMukTM/ukTM3UjL5EzN14SOxcTN """ url = self._gen_request_url( '/open-apis/drive/permission/public/update') body = { 'token': file_token, 'type': converter_enum(file_type), } if copy_print_export_status is not None: body['copy_print_export_status'] = copy_print_export_status if comment is not None: body['comment'] = comment if tenant_shareable is not None: body['tenant_shareable'] = tenant_shareable if link_share_entity is not None: body['link_share_entity'] = link_share_entity.value if external_access is not None: body['external_access'] = external_access if invite_external is not None: body['invite_external'] = invite_external self._post(url, body=body, auth_token=user_access_token)