Пример #1
0
    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
Пример #2
0
    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
Пример #3
0
    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 {})
Пример #4
0
    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 {})
Пример #5
0
    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']]
Пример #6
0
    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
Пример #7
0
    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
Пример #8
0
    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
Пример #9
0
    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
Пример #10
0
    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('<', '&lt;'). \
            replace('>', '&gt;'). \
            replace('&', '&amp;'). \
            replace('\'', '&#x27;'). \
            replace('"', '&quot;')

        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'])
Пример #11
0
    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
Пример #12
0
    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)
Пример #13
0
    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
Пример #14
0
    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
Пример #15
0
    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
Пример #16
0
    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'])
Пример #17
0
    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'])
Пример #18
0
    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
Пример #19
0
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
Пример #20
0
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
Пример #21
0
    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
Пример #22
0
    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'])
Пример #23
0
    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)
Пример #24
0
    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'])
Пример #25
0
    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 [])
                             ])
Пример #26
0
    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)
Пример #27
0
    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
Пример #28
0
    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
Пример #29
0
    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
Пример #30
0
    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)