Teambition企業內部應用開發指南

Teambition企業內部應用Python開發指南

注意:此文章並非搬運,一小部分僅為借鑒。

Teambition提供了API介面,我們可以註冊成為開發者,然後通過介面獲取Teambition的數據,按照需求的格式保存和分析.

一、準備階段

1.登錄Teambition企業帳號,要有管理員的許可權,點擊左上角的菜單按鈕,然後點擊進入企業的「全部應用」.最後點擊「應用商店」


2.點擊「開放平台」,此頁面有後期需用的API文檔,可以先收藏。點擊「立即創建」

3.創建企業內部應用:填寫名稱和描述
4.打開應用憑證和基本資訊,獲取ID和Secret(F12在程式碼中可以直接複製)

5.打開左側欄中的「應用開發」–「應用許可權」,根據需要勾選
6.打開「應用發布」,填寫資訊,發布。

二、Python腳本編寫

1.找到對應的jwt包,//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://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 = '//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 = '//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'//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查詢://open.teambition.com/docs/apis/6321c6d4912d20d3b5a4b0b0

四、一些問題

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 = '//www.teambition.com/organization/'
        self.company_id = 'XXXXXXXXXXXXXXXXXXX'
        self.callback_url = self.company_url + self.company_id
        self.user_code = ''
        self.auth_url = '//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 = '//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 = '//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 = '//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'//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但沒有任何參數,我覺得也用不上

更新任務欄位資訊(懷疑與任務中一介面重複)

沒有路徑參數,文檔中卻給了兩個