• Teambition企业内部应用开发指南


    Teambition企业内部应用Python开发指南

    注意:此文章并非搬运,一小部分仅为借鉴。发表自博客园,转载请注明。

    Teambition提供了API接口,我们可以注册成为开发者,然后通过接口获取Teambition的数据,按照需求的格式保存和分析.

    一、准备阶段

    1.登录Teambition企业账号,要有管理员的权限,点击左上角的菜单按钮,然后点击进入企业的“全部应用”.最后点击“应用商店”


    2.点击“开放平台”,此页面有后期需用的API文档,可以先收藏。点击“立即创建”

    3.创建企业内部应用:填写名称和描述
    4.打开应用凭证和基本信息,获取ID和Secret(F12在代码中可以直接复制)

    5.打开左侧栏中的“应用开发”--“应用权限”,根据需要勾选
    6.打开“应用发布”,填写信息,发布。
    7.在应用商店中找到刚发布的应用,安装。

    二、Python脚本编写

    1.找到对应的jwt包,https://jwt.io/libraries,下载安装(推荐PyJWT:至少我用没有问题)
    2.appAccessToken的获取(最重要的一步)

    • 因为文档中没有Python实现的任何描述,这里只提供个人写法
    from datetime import datetime, timedelta
    import jwt
    import requests
    import time
    from Config import getConfig
     
     class GetTeamBitionEvents(object):
         def __init__(self):
     	self.app_id = getConfig('config', 'Get_TB_Data', 'app_id')
            self.app_secret = getConfig('config', 'Get_TB_Data', 'app_secret')
        def get_aptoken(self):
            now_time = int(time.time())
            expire_time = now_time + 36000  # 1 小时后超时
            token_dict = {'iat': now_time,
                          '_appId': '%s' % self.app_id,
                          'exp': expire_time,
                          }
            headers = {
                'typ': 'jwt',
                'alg': 'HS256'
                # 声明所使用的算法
            }
            encoded = jwt.encode(payload=token_dict, key=self.app_secret, headers=headers,
                                 algorithm='HS256')  # .decode('ascii')
            return encoded
    
    • 个人习惯将固定的重要数据存放在config文件中,你也可以直接写入字符串

    3.获取Token后就可以开始调用API了,我这里将“创建项目任务类型”作为示例

    • 文档链接:开放平台文档中心 (teambition.com)
    • 主要看六点
      • URL:https://open.teambition.com/api/v3/sfc/create
      • Method:POST
      • 权限:tb-core:sfc:create
      • 请求头
      • 查询参数
      • 请求体
    • 有了这些信息,就可以直接上代码了
    from __future__ import absolute_import, unicode_literals
    import requests, time, jwt
    
    
    class GetTeamBitionEvents(object):
    
        def __init__(self):
            self.app_id = ''			# 必填
            self.app_secret = ''		# 必填
            self.company_url = 'https://www.teambition.com/organization/'	# 固定
            self.company_id = ''  # 一些API会用到公司ID
            self.callback_url = self.company_url + self.company_id		# 固定
            self.user_id=''		# 一些API会用到个人ID
            self.auth_url = 'https://account.teambition.com/oauth2/authorize?client_id=' + self.app_id + '&redirect_uri=' + self.callback_url		# 固定
    
        def get_aptoken(self):
            now_time = int(time.time())
            expire_time = now_time + 36000  # 1 小时后超时
            token_dict = {'iat': now_time,
                          '_appId': '%s' % self.app_id,
                          'exp': expire_time,
                          }
            headers = {
                'typ': 'jwt',
                'alg': 'HS256'
                # 声明所使用的算法
            }
            encoded = jwt.encode(payload=token_dict, key=self.app_secret, headers=headers,
                                 algorithm='HS256')  # .decode('ascii')
            return encoded
    
        def post_proj_type(self,params,object):
            url = f'https://open.teambition.com/api/v3/sfc/create'
            app_token = (self.get_aptoken()).replace("\n", "").replace('\r', '')
            headers = {
                'Authorization': 'Bearer %s' % app_token,
                'X-Tenant-Id': '%s' % self.company_id,
                'X-Tenant-Type': 'organization',
                'X-Operator-Id': self.user_id
            }
    
            return requests.post(url,json=object,params=params, headers=headers)
    
    
    if __name__ == '__main__':
        tb = GetTeamBitionEvents()
        projectId=tb.company_id       #测试企业-项目管理副本
        roleId=tb.user_id           # 测试角色
        object={
            'name':'测试类型'
        }
        params={
            'projectId':projectId
        }
        result = tb.post_proj_type(params,object)
        print(result.json()["result"])
    
    
    • 其中params为查询参数,json为请求体。根据具体API要求
      • 'params'和'object'中参数用,分隔
      • requests的方法有get/post/del/put根据需要使用
      • 参数后有勾选必填的,必须要有,不然会报错
    • 记得打开相应权限

    三、一些辅助脚本

    Config.py

    import configparser
    import os
    
    
    # 读取配置文件
    def getConfig(filename, section, option):
        """
        :param filename 文件名称
        :param section: 服务
        :param option: 配置参数
        :return:返回配置信息
        """# 获取当前目录路径
        proDir = os.path.split(os.path.realpath(__file__))[0]
        # print(proDir)
    
        # 拼接路径获取完整路径
        configPath = os.path.join(proDir, filename)
        # print(configPath)
    
        # 创建ConfigParser对象
        conf = configparser.ConfigParser()
    
        # 读取文件内容
        conf.read(configPath)
        config = conf.get(section, option)
        return config
    

    config文件格式

    [Get_TB_Data]
    app_id=XXXXXXXX
    app_secret=XXXXXXXX
    
    • 中括号内为Section,条目为option

    其他

    这方面可以自己拓展
    我个人是写了专门的:数据筛选脚本(根据条件),数据处理脚本(生成json,txt,csv,将国际时间转为北京时间),邮件发送脚本
    主要是我自己懒得把代码搬上来了,因为逻辑全是连在一起的,不太好动。如果有需求,可以发送评论,如果方便,我会找机会放上来。
    如果追求搜索任务时的自由度的话,可以尝试在历史版本中的TQL查询:https://open.teambition.com/docs/apis/6321c6d4912d20d3b5a4b0b0

    四、一些问题


    12-13
    今天去开放文档看了一下,多了很多新东西。很可能之前的问题已经被解决了,这几天会再研究一下。

    11-13
    Teambition的维护并不好,文档和API中有许多错漏,我已经在10月13向阿里的相关开发者提交了一下报告,不知道何时能修好。这报告也不全面,是后面才想起来写的。仅供参考。

    服务器问题(大概)

    企业

    获取企业信息(X)
    from __future__ import absolute_import, unicode_literals
    import requests, time, jwt
    
    
    class GetTeamBitionEvents(object):
    
        def __init__(self):
            self.app_id = 'XXXXXXXXXXXXXXXXXXX'
            self.app_secret = 'XXXXXXXXXXXXXXXXXXX'
            self.company_url = 'https://www.teambition.com/organization/'
            self.company_id = 'XXXXXXXXXXXXXXXXXXX'
            self.callback_url = self.company_url + self.company_id
            self.user_code = ''
            self.auth_url = 'https://account.teambition.com/oauth2/authorize?client_id=' + self.app_id + '&redirect_uri=' + self.callback_url
    
        def get_aptoken(self):
            now_time = int(time.time())
            expire_time = now_time + 36000  # 1 小时后超时
            token_dict = {'iat': now_time,
                          '_appId': '%s' % self.app_id,
                          'exp': expire_time,
                          }
            headers = {
                'typ': 'jwt',
                'alg': 'HS256'
                # 声明所使用的算法
            }
            encoded = jwt.encode(payload=token_dict, key=self.app_secret, headers=headers,
                                 algorithm='HS256')  # .decode('ascii')
            return encoded
    
        def post_userapp_visible(self):
            url = 'https://open.teambition.com/api/org/info'
            app_token = (self.get_aptoken()).replace("\n", "").replace('\r', '')
            headers = {
                "Authorization": 'Bearer %s' % app_token,
            }
            params = {
                "orgId": '%s' % self.company_id
            }
    
            return requests.get(url, params=params, headers=headers)
    
    
    if __name__ == '__main__':
        tb = GetTeamBitionEvents()
        result = tb.post_userapp_visible()
        print(result.json())
        print(result.json()["result"])
    
    

    有问题

    {'code': 403, 'errorMessage': 'Forbidden: authbase.Verify failed: Forbidden: no permission to access resource, appID(6332aa802cd25c2c2880e56b) serviceID(5d4ce50b900cea004806c15a) tenant() resource(organization) action(1)', 'result': None}
    None
    

    任务

    更新自由任务标题(X)
    from __future__ import absolute_import, unicode_literals
    import requests, time, jwt
    
    
    class GetTeamBitionEvents(object):
    
        def __init__(self):
            self.app_id = 'XXXXXXXXXXXXXXXXXXX'
            self.app_secret = 'XXXXXXXXXXXXXXXXXXX'
            self.company_url = 'https://www.teambition.com/organization/'
            self.company_id = 'XXXXXXXXXXXXXXXXXXX'  # 测试用公司
            self.callback_url = self.company_url + self.company_id
            self.user_id='XXXXXXXXXXXXXXXXXXX'
            self.user_code = ''
            self.auth_url = 'https://account.teambition.com/oauth2/authorize?client_id=' + self.app_id + '&redirect_uri=' + self.callback_url
    
        def get_aptoken(self):
            now_time = int(time.time())
            expire_time = now_time + 36000  # 1 小时后超时
            token_dict = {'iat': now_time,
                          '_appId': '%s' % self.app_id,
                          'exp': expire_time,
                          }
            headers = {
                'typ': 'jwt',
                'alg': 'HS256'
                # 声明所使用的算法
            }
            encoded = jwt.encode(payload=token_dict, key=self.app_secret, headers=headers,
                                 algorithm='HS256')  # .decode('ascii')
            return encoded
    
        def post_create_freetask(self,xoperatorid,content):
            url = f'https://open.teambition.com/api/organization-task/create'
            app_token = (self.get_aptoken()).replace("\n", "").replace('\r', '')
            headers = {
                'x-operator-id': xoperatorid,
                'Authorization': 'Bearer %s' % app_token,
                'X-Tenant-Id': '%s' % self.company_id,
                'X-Tenant-Type': 'organization',
    
            }
            params={
                'content':content
            }
    
            return requests.post(url,json=params, headers=headers)
    
    
    if __name__ == '__main__':
        tb = GetTeamBitionEvents()
        xoperatorid='63310bc0b2b7b2cf2ca8a3b2'
        content='all right'
        result = tb.post_create_freetask(xoperatorid,content)
        print(result.json())
        print(result.json()["result"])
    
    

    有问题

    {'code': 403, 'errorMessage': '系统错误', 'result': None}
    
    创建自由任务(X)

    同上报错

    查询自由任务详情(X)

    同上

    更新自由任务截止时间(X)

    同上

    更新自由任务执行者(?)
    更新自由任务参与者(?)
    更新自由任务完成态(?)
    更新自由任务备注(?)

    这几个都没测了,感觉会是一样的结果

    获取任务关联信息(X)
    {'code': 403, 'errorMessage': '应用的接口访问权限受限', 'result': None}
    
    创建任务关联(?)
    删除任务关联(?)
    更新自由任务优先级(?)

    这几个也都没测了

    更新任务自定义字段值(弃用?)
    {'code': 404, 'errorMessage': '访问的资源不存在', 'result': None}
    

    我估计这是被弃用的,因为后面有一条简介一模一样的接口

    而且object中的参数缺失

    项目

    查询企业优先级(X)
    {'code': 403, 'errorMessage': '系统错误', 'result': None}
    
    修改项目角色的权限项(X)
    {'code': 500, 'errorMessage': 'internal server error', 'result': None}
    
    恢复归档项目(功能问题)
    {'updated': '2022-10-13T06:56:39.469Z'}
    

    运行完毕后,并未让已归档项目回复

    查询项目分组(怀疑是被弃用的)

    项目中有一个搜索项目分组,不会报错

    {'code': 403, 'errorMessage': '系统错误', 'result': None}
    

    文档问题

    文档部分,只记录了在项目条目下的错误

    项目

    查询企业优先级(X)

    查询参数organizationId是必填字段

    安装项目应用

    请求体object缺少参数说明,或者说可能不需要

    删除项目应用

    文档请求头描述中缺少X-Operator-Id

    复制项目

    请求体object中name是必填项

    从模版创建项目

    请求体object中name、templateId是必填项

    创建项目

    请求体object中name是必填项

    创建项目分组关联关系(没有在网页端找到相应信息)(X)
    {'code': 400, 'errorMessage': '参数有误:  应当有必需属性 projectRoleIds', 'result': None}
    

    在文档里找不到projectRoleIds

    创建项目成员

    文档缺少:X-Operator-Id必填

    修改项目成员的角色

    userIds、roleIds为必填参数

    更新项目的项目分组(X)

    x-operator-id必填

    {'code': 400, 'errorMessage': '参数有误: required: $add or $del', 'result': None}
    

    文档内没有$add or $del相关解释

    创建项目角色

    x-operator-id必填

    移除项目角色

    x-operator-id必填

    创建项目任务类型

    x-operator-id必填

    修改项目任务类型

    其实应该放在任务一栏下面

    x-operator-id必填,projectId 也是必须的

    删除项目任务类型

    x-operator-id必填,projectId 是必须的,文档里写了object但没有任何参数,我觉得也用不上

    更新任务字段信息(怀疑与任务中一接口重复)

    没有路径参数,文档中却给了两个

  • 相关阅读:
    基于springboot实现智能停车场管理平台
    前端最新2022面试题(JS)
    ffmpeg封装和解封装介绍-(8)解封装和封装重构
    深度理解 RGMII (包含Linux和realtek)
    23、Mybatis查询功能4(查询结果为一个map集合(多条数据))
    信贷风控NCL净损失率的指标实现与应用
    java计算机毕业设计小型医院药品及门诊管理源码+数据库+系统+lw文档+mybatis+运行部署
    Go-命令行参数解析
    元宇宙广告 模式与机遇
    Unity引擎更新收费模式:从收入分成转向游戏安装量,将会有哪些影响呢
  • 原文地址:https://www.cnblogs.com/yanyh-robot/p/16810845.html