def get_approval_definition(self, definition_code, locale='zh'): """查看审批定义 :type self: OpenLark :param definition_code: 审批定义Code,需要有管理员权限,然后在 https://www.feishu.cn/approval/admin/approvalList 创建 :type definition_code: str :param locale: zh or en :type locale: str :return: 审批定义对象 ApprovalDefinition :rtype: ApprovalDefinition 根据 definition_code 获取某个审批定义的详情,用于构造创建审批实例的请求。 https://open.feishu.cn/document/ukTMukTMukTM/uADNyUjLwQjM14CM0ITN """ url = self._gen_request_url('/approval/openapi/v2/approval/get', app='approval') locale = {'zh': 'zh-CN', 'en': 'en-US'}.get(str(locale).lower()) body = {'approval_code': definition_code, 'locale': locale} res = self._post(url, body, with_tenant_token=True) data = res['data'] approval_name = data['approval_name'] form = json.loads(data['form']) nodes = data['node_list'] definition = ApprovalDefinition( approval_name=approval_name, forms=[make_datatype(ApprovalForm, i) for i in form], nodes=[make_datatype(ApprovalNode, i) for i in nodes], ) return definition
def batch_update_drive_sheet(self, user_access_token, sheet_token, adds=None, copys=None, deletes=None): """操作子表 :type self: OpenLark :param user_access_token: user_access_token :type user_access_token: str :param sheet_token: 文件的 token 列表 :type sheet_token: str :param adds: 参数 :type adds: List[BatchUpdateDriveSheetRequestAdd] :param copys: 参数 :type copys: List[BatchUpdateDriveSheetRequestCopy] :param deletes: 参数 :type deletes: List[BatchUpdateDriveSheetRequestDelete] :rtype (list[UpdateDriveSheetResponse], list[UpdateDriveSheetResponse], list[UpdateDriveSheetResponse]) 该接口用于根据 sheet_token 操作表格,如增加sheet,复制sheet、删除sheet。 https://open.feishu.cn/document/ukTMukTMukTM/uYTMzUjL2EzM14iNxMTN """ url = self._gen_request_url( '/open-apis/sheet/v2/spreadsheets/{}/sheets_batch_update'.format( sheet_token)) requests = [] if adds: for i in adds: requests.append(i.as_dict()) if copys: for i in copys: requests.append(i.as_dict()) if deletes: for i in deletes: requests.append(i.as_dict()) res = self._post(url, body={'requests': requests}, auth_token=user_access_token) adds_resp = [] # type: List[UpdateDriveSheetResponse] copys_resp = [] # type: List[UpdateDriveSheetResponse] deletes_resp = [] # type: List[UpdateDriveSheetResponse] for i in res.get('data', {}).get('replies', []): if 'addSheet' in i: adds_resp.append( make_datatype(UpdateDriveSheetResponse, i['addSheet']['properties'])) elif 'copySheet' in i: copys_resp.append( make_datatype(UpdateDriveSheetResponse, i['copySheet']['properties'])) elif 'deleteSheet' in i: deletes_resp.append( make_datatype(UpdateDriveSheetResponse, i['deleteSheet'])) return adds_resp, copys_resp, deletes_resp
def refresh_user_session(self, refresh_token): """刷新用户扫码登录后获取的 access_token :type self: OpenLark :param refresh_token: 扫码登录后会拿到这个值 :type refresh_token: str :return: OAuthCodeToSessionResp :rtype: OAuthCodeToSessionResp 刷新用户 token 特别需要注意的是:老 api 获取的 expire_in 是时间戳,新 api 获取的 expire_in 是秒数 https://open.feishu.cn/document/ukTMukTMukTM/uQDO4UjL0gDO14CN4gTN """ url = self._gen_request_url( '/open-apis/authen/v1/refresh_access_token') body = { "app_access_token": self.app_access_token, "grant_type": "refresh_token", "refresh_token": refresh_token } res = self._post(url, body) return make_datatype(OAuthCodeToSessionResp, res.get('data') or {})
def oauth_code_2_session(self, code): """获取登录用户身份 :type self: OpenLark :param code: 扫码登录后会自动 302 到 redirect_uri 并带上此参数 :type code: str :return: OAuthCodeToSessionResp :rtype: OAuthCodeToSessionResp Web 扫码后拿到的 code 换取用户信息,通过此接口获取登录用户身份。 特别需要注意的是:老 api 获取的 expire_in 是时间戳,新 api 获取的 expire_in 是秒数 https://open.feishu.cn/document/ukTMukTMukTM/uEDO4UjLxgDO14SM4gTN """ url = self._gen_request_url('/open-apis/authen/v1/access_token') body = { 'app_access_token': self.app_access_token, 'grant_type': 'authorization_code', 'code': code, } res = self._post(url, body) return make_datatype(OAuthCodeToSessionResp, res.get('data') or {})
def get_drive_file_meta(self, user_access_token, files): """获取各类文件的元数据 :type self: OpenLark :param user_access_token: user_access_token :type user_access_token: str :param files: 文件的 token 列表 :type files: list[DriveFileToken] :return: 文件元信息 :rtype: list[DriveFileMeta] 该接口用于根据 token 获取各类文件的元数据 https://open.feishu.cn/document/ukTMukTMukTM/uMjN3UjLzYzN14yM2cTN """ url = self._gen_request_url('/open-apis/suite/docs-api/meta') body = { 'request_docs': [ { 'docs_token': i.token, 'docs_type': i.type, } for i in files ] } res = self._post(url, body=body, auth_token=user_access_token) return [make_datatype(DriveFileMeta, i) for i in res['data']['docs_metas']]
def get_app_visibility(self, app_id, user_page_token='', user_page_size=20): """获取应用在企业内的可用范围 :type self: OpenLark :param app_id: 目标应用的 ID :type app_id: str :param user_page_token: 分页拉取用户列表起始位置标示,不填表示从头开始 :type user_page_token: str :param user_page_size: 本次拉取用户列表最大个数(最大值 1000 ,0 自动最大个数 ) :type user_page_size: int :return: (部门列表, 可见的用户列表,是否全员可见,是否还有更多用户,用户翻页token, 所有可见用户数量(仅包含单独设置的用户,可用部门中的用户不计算在内) :rtype: (list[str], list[SimpleUser], bool, bool, str, int) 该接口用于查询应用在该企业内可以被使用的范围,只能被企业自建应用调用且需要“获取应用信息”权限。 https://open.feishu.cn/document/ukTMukTMukTM/uIjM3UjLyIzN14iMycTN """ url = self._gen_request_url('/open-apis/application/v1/app/visibility?app_id={}'.format(app_id)) if user_page_token: url = '{}&user_page_token={}'.format(url, user_page_token) if user_page_size: url = '{}&user_page_size={}'.format(url, user_page_size) res = self._get(url, with_tenant_token=True) data = res['data'] department_ids = [i.get('id') for i in data.get('departments', [])] # type: List[str] users = [make_datatype(SimpleUser, i) for i in data.get('users', [])] # type: List[SimpleUser] is_visible_to_all = bool(data.get('is_visible_to_all', False)) # type: bool has_more_users = bool(data.get('has_more_users', False)) # type: bool user_page_token = data.get('user_page_token') # type: str total_user_count = data.get('total_user_count') # type: int return department_ids, users, is_visible_to_all, has_more_users, user_page_token, total_user_count
def get_approval_instance(self, instance_code, locale='zh'): """获取单个审批实例详情 :type self: OpenLark :param instance_code: 审批实例 code,需要有管理员权限,然后在 https://www.feishu.cn/approval/admin/approvalList 创建 :type instance_code: str :param locale zh 中文,en 英文 :type locale: str :return: 审批实例的对象 ApprovalInstance :rtype: ApprovalInstance 根据 instance_code 获取某个审批实例的详情,instance_code 由【批量获取审批实例】接口获取。 一般情况下,当实例状态为1,需定期重新拉取,以确保获取到最新的实例详情。 https://open.feishu.cn/document/ukTMukTMukTM/uEDNyUjLxQjM14SM0ITN """ url = self._gen_request_url('/approval/openapi/v2/instance/get', app='approval') body = { 'instance_code': instance_code, 'locale': _transfer_locale(locale) } res = self._post(url, body=body, with_tenant_token=True) data = res['data'] instance = make_datatype(ApprovalInstance, data) return instance
def batch_get_building(self, building_ids, fields=None): """查询建筑物详情 :type self: OpenLark :param building_ids: 必须参数,用于查询指定建筑物的ID列表 :type building_ids: list[str] :param fields: 可选参数,用于指定返回的字段名,可选字段有:"id,name,description,floors",默认返回所有字段 :return: 建筑物列表 :rtype: list[Building] https://open.feishu.cn/document/ukTMukTMukTM/ukzNyUjL5cjM14SO3ITN """ params = { 'building_ids': building_ids, } if fields: params['fields'] = ','.join(fields) url = self._gen_request_url( '/open-apis/meeting_room/building/batch_get?{}'.format(urlencode(params, doseq=True))) res = self._get(url, with_tenant_token=True) data = res.get('data', {}) buildings = data.get('buildings', []) building_list = [make_datatype(Building, i) for i in buildings] return building_list
def batch_get_department_detail(self, department_ids): """批量获取部门详情,只返回权限范围内的部门。 :type self: OpenLark :param department_ids: 部门 ID 列表 :type department_ids: list[str] :return: departments, errors :rtype: (dict[str, Department], dict[str, OpenLarkException]) 批量获取部门详情,只返回权限范围内的部门。 https://open.feishu.cn/document/ukTMukTMukTM/uczN3QjL3czN04yN3cDN https://bytedance.feishu.cn/docs/doccnOcR1fnxBACchoY9tlg7Amg# """ if isinstance(department_ids, str): department_ids = [department_ids] qs = '&'.join(['ids={}'.format(i) for i in department_ids]) url = self._gen_request_url( '/open-apis/contact/v2/department/detail/batch_get?' + qs) res = self._get(url, with_tenant_token=True) data = res['data'] departments = {} # type: Dict[str, Department] for i in data.get('departments', []): dept = make_datatype(Department, i) # type: Department departments[dept.id] = dept errors = {} # type: Dict[str, OpenLarkException] for i in data.get('errors', []): e = gen_exception(code=i.get('code'), url='', msg=i.get('msg')) errors[i.get('id', '')] = e return departments, errors
def add_drive_comment(self, user_access_token, file_token, content): """添加全文评论 :type self: OpenLark :param user_access_token: user_access_token :type user_access_token: str :param file_token: 文件的 token :type file_token: str :param content: 评论内容 :type content: str :return: 评论对象 :rtype: DriveComment 该接口用于根据 file_token 给文档添加全文评论 https://open.feishu.cn/document/ukTMukTMukTM/ucDN4UjL3QDO14yN0gTN """ if not content or not isinstance(content, string_types): raise LarkInvalidArguments(msg='content empty') content = content. \ replace('<', '<'). \ replace('>', '>'). \ replace('&', '&'). \ replace('\'', '''). \ replace('"', '"') url = self._gen_request_url('/open-apis/comment/add_whole') body = {'type': 'doc', 'token': file_token, 'content': content} res = self._post(url, body=body, auth_token=user_access_token) return make_datatype(DriveComment, res['data'])
def batch_get_room_list(self, room_ids, fields=None): """查询会议室详情 :type self: OpenLark :param room_ids: 用于查询指定会议室的ID列表 :type room_ids: List[str] :param fields: 可选字段有:"id,name,description,capacity,building_id,building_name,floor_name,is_disabled, display_id",默认返回所有字段 :return: 会议室列表 :rtype: list[Room] https://open.feishu.cn/document/ukTMukTMukTM/uEDOyUjLxgjM14SM4ITN """ params = { 'room_ids': room_ids, } if fields: params['fields'] = ','.join(fields) url = self._gen_request_url('/open-apis/meeting_room/room/batch_get?{}'.format(urlencode(params, doseq=True))) res = self._get(url, with_tenant_token=True) data = res.get('data', {}) rooms = data.get('rooms', []) room_list = [make_datatype(Room, i) for i in rooms] return room_list
def get_user(self, open_id='', user_id=''): """获取用户信息 :type self: OpenLark :param open_id: 用户的 open_id :type open_id: str :param user_id: 用户的 user_id :type user_id: str :return: User 对象 :rtype: User https://open.feishu.cn/document/ukTMukTMukTM/ukjMwUjL5IDM14SOyATN """ if open_id: url = self._gen_request_url( '/open-apis/user/v3/info?open_id={}'.format(open_id)) elif user_id: url = self._gen_request_url( '/open-apis/user/v3/info?employee_id={}'.format(user_id)) else: raise LarkInvalidArguments( msg='[get_user] empty open_id and user_id') res = self._get(url, with_tenant_token=True) res['user_id'] = pop_or_none(res, 'employee_id') return make_datatype(User, res)
def get_role_user_list(self, role_id, page_size=20, page_token=''): """获取角色成员列表 :type self: OpenLark :param role_id: 角色 id :type role_id: str :param page_size: 分页大小,最大支持 200;默认为 20 :type page_size: int :param page_token: 分页标记,分页查询还有更多群时会同时返回新的 page_token, 下次遍历可采用该 page_token 获取更多 :type page_token: str :return: (has_more, page_token, user_list) :rtype: (bool, str, list[SimpleUser]) 该接口用于获取角色下的用户列表,调用该接口需要有该企业的通讯录读权限或写权限。返回结果为该应用通讯录权限范围内的角色成员列表。 https://open.feishu.cn/document/ukTMukTMukTM/uczMwUjL3MDM14yNzATN """ base = self._gen_request_url('/open-apis/contact/v2/role/members') url = join_url(base, [ ('role_id', role_id), ('page_size', page_size), ('page_token', page_token), ]) res = self._get(url, with_tenant_token=True) data = res['data'] has_more = data.get('has_more', False) page_token = data.get('page_token', '') user_list = [ make_datatype(SimpleUser, i) for i in data.get('user_list', []) ] # type: List[SimpleUser] return has_more, page_token, user_list
def get_contact_scope(self): """获取通讯录授权范围 :type self: OpenLark :return: is_visible_to_all, department_ids, users :rtype: (bool, list[str], list[SimpleUser]) 该接口用于获取应用被授权可访问的通讯录范围,包括可访问的部门列表及用户列表。 授权范围为全员时,返回的部门列表为该企业所有的一级部门; 否则返回的部门为管理员在设置授权范围时勾选的部门(不包含勾选部门的子部门)。 https://open.feishu.cn/document/ukTMukTMukTM/ugjNz4CO2MjL4YzM https://bytedance.feishu.cn/docs/doccnOcR1fnxBACchoY9tlg7Amg# """ url = self._gen_request_url('/open-apis/contact/v2/scope/get') res = self._get(url, with_tenant_token=True) data = res['data'] department_ids = data.get('authed_departments', []) # type: List[str] users = [ make_datatype(SimpleUser, i) for i in data.get('authed_users', []) ] # type: List[SimpleUser] is_visible_to_all = '0' in department_ids return is_visible_to_all, department_ids, users
def get_pay_order_detail(self, order_id): """查询订单详情 :type self: OpenLark :param order_id: 获取用户购买套餐信息设置的过滤条件,normal为正常状态,refund为已退款,为空或者all表示所有,未支付的订单无法查到 :type order_id: str 该接口用于查询某个订单的具体信息 https://open.feishu.cn/document/ukTMukTMukTM/uITNwUjLyUDM14iM1ATN """ url = self._gen_request_url( '/open-apis/pay/v1/order/get?order_id={}'.format(order_id)) res = self._get(url, with_app_token=True) data = res['data'] total = data.get('total') has_more = data.get('has_more') page_token = data.get('page_token') orders = [ make_datatype(PayOrder, i) for i in data.get('order_list', []) ] return has_more, page_token, total, orders
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 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 get_calendar_list(self, max_results=500, page_token='', sync_token=''): """获取日历列表 :type self: OpenLark :param max_results: 一次请求要求返回最大数,该参数不能大于 1000,默认 500 :type max_results: int :param page_token: 用于标志当次请求从哪页开始,90 天有效期 :type page_token: str :param sync_token: 表示从上次返回的截止页起,返回结果,90 天有效期 :type sync_token: str :return: 两个分页参数,和日历对象 Calendar 的列表 :rtype: Tuple[str, str, List[Calendar]] 该接口用于获取应用在企业内的日历列表。 https://open.feishu.cn/document/ukTMukTMukTM/uMTM14yMxUjLzETN """ if max_results > 1000: max_results = 1000 url = self._gen_request_url( '/open-apis/calendar/v3/calendar_list?max_results={}'.format( max_results)) if page_token: url = '{}&page_token={}'.format(url, page_token) if sync_token: url = '{}&sync_token={}'.format(url, sync_token) res = self._get(url, with_tenant_token=True, success_code=200000) data = res.get('data', []) page_token = res.get('page_token', '') sync_token = res.get('sync_token', '') calendar_list = [make_datatype(Calendar, i) for i in data] return page_token, sync_token, calendar_list
def _make_v1_department_info(res): """ :rtype: Department """ department_info = res['data'].get('department_info') or {} open_id = department_info.get('leader_open_id') user_id = department_info.get('leader_employee_id') department_info['leader'] = { 'open_id': open_id, 'user_id': user_id, } return make_datatype(Department, department_info) # type: Department
def _get_conf(): with open('./tests/conf.json', 'r') as f: v = json.load(f) conf = make_datatype(TestConfig, v) # type: TestConfig logging.info('[test] local json conf is %s', conf) conf.lark_app_id = os.getenv('APP_ID_1') conf.lark_app_secret = os.getenv('APP_SECRET_1') conf.bot.open_lark.app_secret = os.getenv(conf.bot.open_lark.app_secret) return conf
def get_users_by_mobile_email(self, emails=None, mobiles=None): """获取用户信息 :type self: OpenLark :param emails: 邮箱列表 :type emails: list[str] :param mobiles: 手机列表 :type mobiles: list[str] :return: 邮箱的用户字典,邮箱不存在的列表,手机的用户字典,手机不存在的列表 :rtype: (dict[str, list[SimpleUser]], list[str], dict[str, list[SimpleUser]], list[str]) 根据用户邮箱或手机号查询用户 open_id 和 user_id,支持批量查询。 只能查询到应用可用性范围内的用户 ID。 调用该接口需要具有 “获取用户 ID” 权限。 https://open.feishu.cn/document/ukTMukTMukTM/uUzMyUjL1MjM14SNzITN """ qs = '&'.join(['mobiles=' + i for i in (mobiles or [])] + ['emails=' + i for i in (emails or [])]) url = self._gen_request_url('/open-apis/user/v1/batch_get_id?' + qs) res = self._get(url, with_tenant_token=True) data = res['data'] email_users = data.get('email_users', {}) email_users = { k: [make_datatype(SimpleUser, vv) for vv in v] for k, v in email_users.items() } # type: dict[str, List[SimpleUser]] emails_not_exist = data.get('emails_not_exist', []) # type: List[str] mobile_users = data.get('mobile_users', {}) mobile_users = { k: [make_datatype(SimpleUser, vv) for vv in v] for k, v in mobile_users.items() } # type: dict[str, List[SimpleUser]] mobiles_not_exist = data.get('mobiles_not_exist', []) # type: List[str] return email_users, emails_not_exist, mobile_users, mobiles_not_exist
def get_bot_info(self): """获取机器人信息 :type self: OpenLark :return: 机器人的对象 Bot :rtype: Bot https://open.feishu.cn/document/ukTMukTMukTM/uAjMxEjLwITMx4CMyETM """ url = self._gen_request_url('/open-apis/bot/v3/info/') body = {} # type: Dict[str, Any] res = self._post(url, body, with_tenant_token=True) return make_datatype(Bot, res['bot'])
def update_calendar_by_id(self, calendar_id, summary=None, description=None, is_private=None, default_access_role=None): """更新日历 :type self: OpenLark :param calendar_id: 日历 ID :type calendar_id: str :param summary: 日历标题,最大长度为 256 :type summary: str :param description: 日历描述,最大长度为 256 :type description: str :param is_private: 是否为私有日历,私有日历不可被搜索,默认为false :type is_private: bool :param default_access_role: 表示用户的默认访问权限。取值如下: reader: 订阅者,可查看日程详情 free_busy_reader: 游客,只能看到"忙碌/空闲" :type default_access_role: CalendarRole :return: Calendar 对象 :rtype: Calendar 该接口用于修改指定日历的信息。 https://open.feishu.cn/document/ukTMukTMukTM/uYTM14iNxUjL2ETN """ url = self._gen_request_url( '/open-apis/calendar/v3/calendars/{}'.format(calendar_id)) body = {} for k, v in { 'summary': summary, 'description': description, 'is_private': is_private, 'default_access_role': default_access_role.value if default_access_role else None, }.items(): if v is not None: body[k] = v res = self._patch(url, body, with_tenant_token=True, success_code=200000) data = res['data'] return make_datatype(Calendar, data)
def get_drive_sheet_import_result(self, user_access_token, ticket) -> DriveSheetImportResult: """ 获取导入表格的结果 Args: user_access_token: user_access_token 或者 tenant_access_token ticket: 导入表格获取的ticket Returns: DriveSheetImportResult """ url = self._gen_request_url( '/open-apis/sheets/v2/import/result?ticket={}'.format(ticket)) res = self._get(url, auth_token=user_access_token) return make_datatype(DriveSheetImportResult, res['data'])
def _gen_calendar_event(self, data): """生成 CalendarEvent :rtype CalendarEvent """ return CalendarEvent(id=data.get('id', ''), summary=data.get('summary', ''), description=data.get('description', ''), start=data.get('start', {}).get('time_stamp', 0), end=data.get('end', {}).get('time_stamp', 0), visibility=CalendarEventVisibility( data.get('visibility', 'default')), attendees=[ make_datatype(CalendarAttendee, i) for i in (data.get('attendees') or []) ])
def get_chat_info(self, chat_id): """获取会话信息,包括和机器人的私聊 + 群聊 :type self: OpenLark :param chat_id: 会话的 ID :type chat_id str :return: 会话信息 :rtype: DetailChat 获取群名称、群主 ID、成员列表 ID 等群基本信息。 https://open.feishu.cn/document/ukTMukTMukTM/uMTO5QjLzkTO04yM5kDN """ url = self._gen_request_url('/open-apis/chat/v4/info/?chat_id=' + chat_id) res = self._get(url, with_tenant_token=True) chat = res['data'] return make_datatype(DetailChat, chat)
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 get_room_list(self, building_id, page_size=100, page_token='', order_by='', fields=None): """获取会议室列表 :type self: OpenLark :param building_id: 被查询的建筑物ID :type building_id: str :param page_size: 请求期望返回的会议室数量,不足则返回全部,该值默认为 100,最大为 1000 :type page_size: int :param page_token: 用于标记当前请求的页数,将返回以当前页开始,往后 page_size 个元素 :type page_token: str :param order_by: 提供用于对名称/楼层进行升序/降序排序的方式查询,可选项有:"name-asc,name-desc,floor_name-asc, floor_name-desc",传入其他字符串不做处理,默认无序 :type order_by: str :param fields: 可选字段有:"id,name,description,capacity,building_id,building_name,floor_name,is_disabled, display_id",默认返回所有字段 :type fields: list[str] :return: has_more, page_token, 会议室列表 :rtype: (bool, str, list[Room]) https://open.feishu.cn/document/ukTMukTMukTM/uADOyUjLwgjM14CM4ITN """ if page_size > 1000: page_size = 1000 elif page_size <= 0: page_size = 100 params = { 'building_id': building_id, 'page_size': page_size } if page_token: params['page_token'] = page_token if order_by: params['order_by'] = order_by if fields: params['fields'] = ','.join(fields) url = self._gen_request_url('/open-apis/meeting_room/room/list?{}'.format(urlencode(params))) res = self._get(url, with_tenant_token=True) data = res.get('data', {}) rooms = data.get('rooms', []) has_more = data.get('has_more', False) page_token = data.get('page_token', '') room_list = [make_datatype(Room, i) for i in rooms] return has_more, page_token, room_list
def batch_get_department_detail_user(self, user_ids=None, open_ids=None): """批量获取用户详细信息 :type self: OpenLark :param user_ids: 用户 UserID 列表 :type user_ids: list[str] :param open_ids: 用户 OpenID 列表 :type open_ids: list[str] :return: has_more, page_token, departments :rtype: (Dict[str, DepartmentUser], Dict[str, OpenLarkException]) 批量获取用户信息详情,需具有用户所在部门或者用户的通讯录权限。 https://open.feishu.cn/document/ukTMukTMukTM/ugjNz4CO2MjL4YzM https://bytedance.feishu.cn/docs/doccnOcR1fnxBACchoY9tlg7Amg# """ if user_ids and open_ids: raise LarkInvalidArguments(msg='only need user_ids or open_ids') elif not user_ids and not open_ids: raise LarkInvalidArguments(msg='need user_ids or open_ids') qs = '' user_key = '' if user_ids: qs = '&'.join(['user_ids={}'.format(i) for i in user_ids]) user_key = 'user_id' elif open_ids: qs = '&'.join(['open_ids={}'.format(i) for i in open_ids]) user_key = 'open_id' url = self._gen_request_url('/open-apis/contact/v2/user/batch_get') url = url + '?' + qs res = self._get(url, with_tenant_token=True) data = res['data'] users = {} # type: Dict[str, DepartmentUser] for i in data.get('users', []): user = make_datatype(DepartmentUser, i) users[getattr(user, user_key)] = user errors = {} # type: Dict[str, OpenLarkException] for i in data.get('errors', []): e = gen_exception(code=i.get('code'), url='', msg=i.get('msg')) errors[i.get('id', '')] = e return users, errors
def oauth_get_user(self, user_access_token): """获取用户信息 :type self: OpenLark :param user_access_token: 此接口仅用于获取登录用户的信息。 调用此接口需要在 Header 中带上 user_access_token。 https://open.feishu.cn/document/ukTMukTMukTM/uIDO4UjLygDO14iM4gTN """ url = self._gen_request_url('/open-apis/authen/v1/user_info') res = self._get(url, auth_token=user_access_token) data = res['data'] data['avatar_url'] = data.get('avatar') or data.get('avatar_url') data['user_id'] = data.get('user_id') or data.get('employee_id') return make_datatype(User, data)