Code Monkey home page Code Monkey logo

dingtalk-python's Introduction

DingTalk-Python SDK

钉钉第三方SDK,Python版本,用于企业自研微应用。

[TOC]

环境

Python3

Redis(或Memcached,或自定义会话管理对象)

QuickStart

安装依赖包

pycrypto==2.6.1
requests==2.18.4
redis==2.10.6
# 或
python3-memcached==1.51
# 或
pymysql==0.8.0

在python的环境中执行:

pip install -r requirements.txt

钉钉回调消息的加密解密需要依赖pycrypto。

这个包在Windows下安装比较繁琐,建议在Mac OS或Linux下进行调试。

如果不需要使用钉钉回调消息,则可以不安装pycrypto,不影响其他功能的正常工作。

复制模块

将项目的dingtalk模块复制到需要使用的项目根目录下。

暂不考虑将其打包成python的包,主要原因是目前只实现钉钉接口文档的部分功能,如果打包成python包不便于在使用时新增或调整功能。

管理钉钉会话

Dingtalk-Python需要依赖缓存服务器对access token、jsapi ticket进行会话过期时间管理,所以需要传入缓存服务器的客户端对象,这里可以选用Redis(推荐)或Memcached。

需要特别注意的是,对于一个企业多个微应用,或一个企业多种环境:如生产环境、测试环境这种情况,务必保证缓存数据的一致,避免频繁调用钉钉jsapi ticket的接口,导致不同缓存服务器的jsapi ticket互相覆盖。

创建Redis对象

import redis
# 使用redis管理钉钉会话
session_manager = redis.Redis(host='127.0.0.1', port='6379', db=0)

创建Memcached对象

from memcache import Client
# 使用memcached管理钉钉会话
session_manager = Client(['127.0.0.1:11211'])

自定义会话管理对象

除了使用redis和memcached管理钉钉会话外,还支持自定义管理对象,实现对钉钉会话的管理。

通过自定义会话管理对象的方式,可以将钉钉的access token、jsapi ticket存储到MySQL或其它数据库,不仅仅局限于只能使用redis或memcached。

自定义缓存对象需要实现以下类的抽象方法,最后将这个对象实例化后赋值给DingTalkApp的session_manager属性。

class SessionManager:
    """
    钉钉会话管理
    除了支持redis和memcached以外
    也可以通过实现此类的抽象方法支持mysql等数据库
    """

    def set(self, key, value, expires):
        """
        存储会话数据
        :param key: 
        :param value:
        :param expires: 超时时间,单位秒
        :return:
        """
        raise NotImplementedError

    def get(self, key):
        """
        获取会话数据,获取时需要判断会话是否过期
        如已经会话数据已经过期,需要返回None
        :param key:
        :return:
        """
        raise NotImplementedError

    def delete(self, key):
        """
        删除会话数据
        :param key:
        :return:
        """
        raise NotImplementedError

实例化DingTalk App

from dingtalk import DingTalkApp
# name传入企业名称
# session_manager传入钉钉会话管理对象,如果用缓存服务器进行管理,可以是redis或memcached
# 也可以自行实现一个会话管理的对象
# 用于加解密的aes_key,必须是43位字符串,由大小写字母和数字组成,不能有标点符号
# 如果同个企业需要创建多个app实例时,请保持除agent_id外的参数完全一致
# 以下实例化参数都是模拟数据
app = DingTalkApp(name='test', session_manager=session_manager,
                  agent_id='152919534',
                  corp_id='ding19cdf2s221ef83f635c2e4523eb3418f',
                  corp_secret='3ab8Uk7Wef4ytgf7YZF2EziCAlx6AufdF3dFvfjtu3532FG3AUgWNEJys',
                  aes_key='4g5j64qlyl3zvetqxz5jiocdr586fn2zvjpa8zls3ij')

调用接口示例

不同的功能分布在app实例不同的子模块中,目前支持以下子模块的部分接口:

模块名 说明
auth 钉钉鉴权模块,所有子模块的基础
smartwork 智能办公模块,含有考勤和流程等接口
contact 企业内部通讯录子模块
message 企业通知及消息子模块
file 文件相关子模块,目前主要用于钉盘
customer 外部联系人子模块
callback 回调接口子模块,另外还含有加密解密部分的功能

直接在app实例中,通过不同的子模块,调用对应的方法即可,不需要传入公共参数部分,公共参数部分会自动补充。

# 获取钉钉后台定义的外部联系人标签
label_groups = app.customer.get_label_groups()
# 获取审批实例
start_time = datetime(year=2017, month=6, day=1, hour=1, minute=1, second=1, microsecond=1)
# 以下皆是模拟数据
data = app.smartwork.get_bpms_instance_list(process_code='PROC-FF6Y4BE1N2-B3OQZGC9RLR4SY1MTNLQ1-91IFWS3', 
                                  start_time=start_time)

比较特别是鉴权子模块,既可以通过子模块调用,也可以通过app实例直接调用。

# 获取access token
app.auth.get_access_token()
# 以下的方法也是等价的
app.get_access_token()

同时,提供可以通过钉钉的接口方法名直接调用方法的途径,便于和钉钉的接口文档对应。

# 通过run()方法,传入钉钉的接口方法名,及业务参数(不含公共参数部分)
data = app.run('dingtalk.corp.ext.listlabelgroups', size=20, offset=0)
# 上面的方法等同于
data = app.customer.get_label_groups(size=20, offset=0)

这种方式仅限于钉钉本身提供了方法名,一些钉钉本身未提供方法名的情况下,不适用此方法。

如果一定要使用run的形式调用,可以在每个模块的类对象中,以装饰器的形式,给对应的方法加上一个方法名。

@method('dingtalk.corp.ext.all')
def get_all_ext_list(self):
    """
    获取全部的外部联系人,方法实现省略
    """
    pass

例如上面的“dingtalk.corp.ext.all”方法,钉钉本身是没有这个方法名的,通过method装饰器,给函数加上一个方法名后,就可以通过app.run('dingtalk.corp.ext.all')的方式调用。

已实现的接口

  • 获取AccessToken
  • 获取部门列表
  • 获取部门详情
  • 创建部门
  • 更新部门
  • 删除部门
  • 获取成员详情
  • 创建成员
  • 更新成员
  • 删除成员
  • 获取部门成员
  • 获取角色列表
  • 获取角色组信息
  • 企业会话消息异步发送
  • 获取异步发送企业会话消息的发送进度
  • 获取异步向企业会话发送消息的结果
  • 注册事件回调接口
  • 查询事件回调接口
  • 更新事件回调接口
  • 获取回调失败的结果
  • 获取企业下的自定义空间
  • 标签列表
  • 外部联系人列表
  • 添加企业外部联系人
  • 修改企业外部联系人
  • 删除企业外部联系人
  • 通过CODE换取用户身份
  • 考勤排班接口
  • 考勤组详情接口
  • 发起审批实例
  • 获取审批实例列表
  • 获取jsapi_ticket

计划完成的接口

  • 删除事件回调接口
  • 获取部门id列表

常见问题

添加外部联系人失败

如果遇到添加外部联系人失败的情况,请检查在钉钉设置中,外部联系人是否存在某些必填自定义字段。存在必填自定义字段的情况下,通过接口添加外部联系人会失败,而且钉钉只会返回"系统错误"四个字。

dingtalk-python's People

Contributors

blackmatrix7 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dingtalk-python's Issues

特定的ciphertext和aes_key会导致解密失败

aes_key: ZC5MWOE8inNkJRbUw3ay9OXl27bnd0SLqXTwfAIqgir
ciphertext: JVjyp8Sgojp6I1oLHA96uc8i/sXsvpmvyVjkxh6jwbP20m2IeoJCkAt/60k80IrqhiPi2ZEobPL+VZa14lj0mw==

调用crypto.py里的decrypt会出错:
File "。。。。/callback/crypto.py", line 111, in
ciphertext='JVjyp8Sgojp6I1oLHA96uc8i/sXsvpmvyVjkxh6jwbP20m2IeoJCkAt/60k80IrqhiPi2ZEobPL+VZa14lj0mw=='))
File "。。。/callback/crypto.py", line 85, in decrypt
length = struct.unpack('!i', raw[16:20])[0]
struct.error: unpack requires a buffer of 4 bytes

调试了一下,发现应该是pkcs7_unpad把信息搞丢了:
pkcs7_unpad之前信息为:
b'AfkpTLMLSlYN7Iuz\x00\x00\x00\x0cheollo worldding02323e3f1d13ae10\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c'

之后为:
AfkpTLMLSlYN7Iuz\x00\x00\x00

注意到\x0c第一次出现在msg前,即位置19处,所以pkcs7_unpad把后面的消息都截取掉了。

我没有研究过具体加密和解密的算法,我这边为了保证信息不会被截取,把pkcs7_unpad方法改了一下:

return text[: text.index(text[-1], 20)]

有懂算法的可以看看这样是否合适。

file 这个模块的操作

file 这个模块,你是说主要针对于钉盘,
能再多介绍一下,我想要实现一个自动下载的功能。

钉钉回调失败失败 返回文本非success

1、env
python 3.5.2

2、现象
回调接口返回数据:
{"msg_signature": "f2b351fe2f0635b80b2f4c8b4bac2b34ff6c294c", "nonce": "12345", "timeStamp": "1551773340805", "encrypt": "h4FvNBrDtsJf8FoOjWB/v9OcpwFtXqFfVLVmfCb/nVer50qXdjFnwOVflT9+rUSp11a+hcyW7zI49IjfgMVEFA=="}

返回结果

{'errcode': 71009, 'errmsg': '返回文本非success'}

ImportError: cannot import name 'JSONDecodeError'

放在web.py 里面,运行时出现异常 ImportError: cannot import name 'JSONDecodeError'
请问这是什么问题呢?

File "E:\HardPython\projects\DingAppServer\webapi.py", line 118, in GET
from dingtalk import DingTalkApp
File "E:\HardPython\projects\DingAppServer\dingtalk_init_.py", line 13, in
from .message import Message
File "E:\HardPython\projects\DingAppServer\dingtalk\message_init_.py", line 8, in
from .conversation import *
File "E:\HardPython\projects\DingAppServer\dingtalk\message\conversation.py", line 11, in
from json import JSONDecodeError
ImportError: cannot import name 'JSONDecodeError'

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.