workwx

package module
Version: v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 30, 2019 License: MIT Imports: 14 Imported by: 0

README

go-workwx

Travis Build Status Go Report Card GoDoc

import (
    "github.com/xen0n/go-workwx" // package workwx
)

A Work Weixin (a.k.a. Wechat Work) client SDK for Golang, that happens to be battle-tested and pretty serious about its types.

In production since late 2018, pushing all kinds of notifications and alerts in at least 2 of Qiniu's internal systems.

一个 Golang 企业微信客户端 SDK;碰巧在生产环境试炼过,还对类型很严肃。

自 2018 年末以来,在七牛至少 2 个内部系统运转至今,推送各种通知、告警。

English translation TODO for now, as the service covered here is not available outside of China (AFAIK).

Why another wheel?

工作中需要用 Go 实现一个简单的消息推送,想着找个开源库算了,然而现有唯一的开源企业微信 Golang SDK 代码质量不佳。只好自己写一个。

Update: 自从这个库写出来,已经过了很久;现在(2019.08)已经有三四个同类项目了。 不过看了看这些“竞品”,发现自己这个库的类型设计、公开接口、access token 处理等方面还不赖。 为什么人们总是喜欢写死请求 Host、用全局量、为拆包而拆包甚至不惜公开内部方法呢?

Features

  • 包名短
  • 支持覆盖 API Host,用于自己拦一层网关、临时调试等等奇葩需求
  • 支持使用自定义 http.Client
  • access token 处理靠谱
    • 你可以直接就做 API 调用,会自动请求 access token
    • 你也可以一行代码起一个后台 access token 刷新 goroutine
    • 自带指数退避重试
  • 严肃对待类型、公开接口
    • 公开暴露接口最小化,两步构造出 WorkwxApp 对象,然后直接用
    • 刻意不暴露企业微信原始接口请求、响应类型
    • 后续可能会做一个 lowlevel 包暴露裸的 API 接口,但很可能不做
    • 不为多态而多态,宁可 SDK 内部重复代码,也保证一个接口一类动作,下游用户 static dispatch
    • 个别数据模型做了调整甚至重做(如 UserInfoRecipient),以鼓励 idiomatic Go 风格
    • 几乎不会越俎代庖,一言不合 panic现存的少数一些情况都是要修掉的。
  • 自带一个 workwxctl 命令行小工具帮助调试
    • 用起来不爽提 issue 让我知道你在想啥

详情看 godoc 文档,还提供 Examples 小段代码可以参考。

Supported APIs

  • 通讯录管理 (部分支持,见下)
  • 外部联系人管理
  • 应用管理
  • 消息发送 (除接收消息、修改群聊会话外全部支持)
  • 素材管理 (支持上传, 见下)
通讯录管理 API
  • 成员管理
    • 创建成员
    • 读取成员 NOTE: 成员对外信息暂未实现
    • 更新成员
    • 删除成员
    • 批量删除成员
    • 获取部门成员
    • 获取部门成员详情
    • userid与openid互换
    • 二次验证
    • 邀请成员
  • 部门管理
    • 创建部门
    • 更新部门
    • 删除部门
    • 获取部门列表
  • 标签管理
    • 创建标签
    • 更新标签名字
    • 删除标签
    • 获取标签成员
    • 增加标签成员
    • 删除标签成员
    • 获取标签列表
  • 异步批量接口
    • 增量更新成员
    • 全量覆盖成员
    • 全量覆盖部门
    • 获取异步任务结果
  • 通讯录回调通知
    • 成员变更通知
    • 部门变更通知
    • 标签变更通知
    • 异步任务完成通知
外部联系人管理 API
  • 离职成员的外部联系人再分配
  • 成员对外信息
  • 获取外部联系人详情
应用管理 API
  • 获取应用
  • 设置应用
  • 自定义菜单
    • 创建菜单
    • 获取菜单
    • 删除菜单
消息发送 API
  • 发送应用消息
  • 接收消息
  • 发送消息到群聊会话
    • 创建群聊会话
    • 修改群聊会话
    • 获取群聊会话
    • 应用推送消息
消息类型
  • 文本消息
  • 图片消息
  • 语音消息
  • 视频消息
  • 文件消息
  • 文本卡片消息
  • 图文消息
  • 图文消息(mpnews)
  • markdown消息
素材管理 API
  • 上传临时素材
  • 上传永久图片
  • 获取临时素材
  • 获取高清语音素材

Notes

关于保密消息发送

Markdown 等类型消息目前不支持作为保密消息发送,强行发送会报错。 那么为何发送消息的方法还全部带着 isSafe 参数呢?

一方面,企业微信服务方完全可能在未来支持更多消息类型的保密发送,到时候不希望客户端代码重新编译; 另一方面,反正响应会报错,你也不会留着这种逻辑。因此不改了。

License

Documentation

Index

Examples

Constants

View Source
const DefaultQYAPIHost = "https://qyapi.weixin.qq.com"

DefaultQYAPIHost 默认企业微信 API Host

Variables

This section is empty.

Functions

This section is empty.

Types

type ChatInfo

type ChatInfo struct {
	// ChatID 群聊唯一标志
	ChatID string `json:"chatid"`
	// Name 群聊名
	Name string `json:"name"`
	// OwnerUserID 群主id
	OwnerUserID string `json:"owner"`
	// MemberUserIDs 群成员id列表
	MemberUserIDs []string `json:"userlist"`
}

ChatInfo 群聊信息

type CtorOption

type CtorOption interface {
	// contains filtered or unexported methods
}

CtorOption 客户端对象构造参数

func WithHTTPClient

func WithHTTPClient(client *http.Client) CtorOption

WithHTTPClient 使用给定的 http.Client 作为 HTTP 客户端

func WithQYAPIHost

func WithQYAPIHost(host string) CtorOption

WithQYAPIHost 覆盖默认企业微信 API 域名

type DeptInfo

type DeptInfo struct {
	// ID 部门 ID
	ID int64 `json:"id"`
	// Name 部门名称
	Name string `json:"name"`
	// ParentID 父亲部门id。根部门为1
	ParentID int64 `json:"parentid"`
	// Order 在父部门中的次序值。order值大的排序靠前。值范围是[0, 2^32)
	Order uint32 `json:"order"`
}

DeptInfo 部门信息

type Media

type Media struct {
	// contains filtered or unexported fields
}

Media 欲上传的素材

NOTE: 由于 Go `mime/multipart` 包的实现细节原因, 暂时不开放 Content-Type 定制,全部传 `application/octet-stream`。 如有需求,请去 GitHub 提 issue。

func NewMediaFromBuffer

func NewMediaFromBuffer(filename string, buf []byte) (*Media, error)

NewMediaFromBuffer 从内存创建一个欲上传的素材对象

func NewMediaFromFile

func NewMediaFromFile(f *os.File) (*Media, error)

NewMediaFromFile 从操作系统级文件创建一个欲上传的素材对象

type MediaUploadResult

type MediaUploadResult struct {
	// Type 媒体文件类型,分别有图片(image)、语音(voice)、视频(video),普通文件(file)
	Type string
	// MediaID 媒体文件上传后获取的唯一标识,3天内有效
	MediaID string
	// CreatedAt 媒体文件上传时间戳
	CreatedAt time.Time
}

MediaUploadResult 临时素材上传结果

type Recipient

type Recipient struct {
	// UserIDs 成员ID列表(消息接收者),最多支持1000个
	UserIDs []string
	// PartyIDs 部门ID列表,最多支持100个。
	PartyIDs []string
	// TagIDs 标签ID列表,最多支持100个
	TagIDs []string
	// ChatID 应用关联群聊ID,仅用于【发送消息到群聊会话】
	ChatID string
}

Recipient 消息收件人定义

type UserDeptInfo

type UserDeptInfo struct {
	// DeptID 部门 ID
	DeptID int64
	// Order 部门内的排序值,默认为0,数值越大排序越前面
	Order uint32
	// IsLeader 在所在的部门内是否为上级
	IsLeader bool
}

UserDeptInfo 用户部门信息

type UserGender

type UserGender int

UserGender 用户性别

const (
	// UserGenderUnspecified 性别未定义
	UserGenderUnspecified UserGender = 0
	// UserGenderMale 男性
	UserGenderMale UserGender = 1
	// UserGenderFemale 女性
	UserGenderFemale UserGender = 2
)

type UserInfo

type UserInfo struct {
	// UserID 成员UserID
	//
	// 对应管理端的账号,企业内必须唯一。不区分大小写,长度为1~64个字节
	UserID string
	// Name 成员名称
	Name string
	// Position 职务信息;第三方仅通讯录应用可获取
	Position string
	// Departments 成员所属部门信息
	Departments []UserDeptInfo
	// Mobile 手机号码;第三方仅通讯录应用可获取
	Mobile string
	// Gender 性别
	Gender UserGender
	// Email 邮箱;第三方仅通讯录应用可获取
	Email string
	// AvatarURL 头像 URL;第三方仅通讯录应用可获取
	//
	// NOTE:如果要获取小图将url最后的”/0”改成”/100”即可。
	AvatarURL string
	// Telephone 座机;第三方仅通讯录应用可获取
	Telephone string
	// IsEnabled 成员的启用状态
	IsEnabled bool
	// Alias 别名;第三方仅通讯录应用可获取
	Alias string
	// Status 成员激活状态
	Status UserStatus
	// QRCodeURL 员工个人二维码;第三方仅通讯录应用可获取
	//
	// 扫描可添加为外部联系人
	QRCodeURL string
}

UserInfo 用户信息

type UserStatus

type UserStatus int

UserStatus 用户激活信息

已激活代表已激活企业微信或已关注微工作台(原企业号)。 未激活代表既未激活企业微信又未关注微工作台(原企业号)。

const (
	// UserStatusActivated 已激活
	UserStatusActivated UserStatus = 1
	// UserStatusDeactivated 已禁用
	UserStatusDeactivated UserStatus = 2
	// UserStatusUnactivated 未激活
	UserStatusUnactivated UserStatus = 4
)

type Workwx

type Workwx struct {

	// CorpID 企业 ID,必填
	CorpID string
	// contains filtered or unexported fields
}

Workwx 企业微信客户端

Example
corpID := "your_corpid"
corpSecret := "your_corpsecret"
agentID := int64(1234567)

client := workwx.New(corpID)

// there're advanced options
_ = workwx.New(
	corpID,
	workwx.WithQYAPIHost("http://localhost:8888"),
	workwx.WithHTTPClient(&http.Client{}),
)

// work with individual apps
app := client.WithApp(corpSecret, agentID)
app.SpawnAccessTokenRefresher()

// see other examples for more details
Output:

func New

func New(corpID string, opts ...CtorOption) *Workwx

New 构造一个 Workwx 客户端对象,需要提供企业 ID

func (*Workwx) WithApp

func (c *Workwx) WithApp(corpSecret string, agentID int64) *WorkwxApp

WithApp 构造本企业下某自建 app 的客户端

type WorkwxApp

type WorkwxApp struct {
	*Workwx

	// CorpSecret 应用的凭证密钥,必填
	CorpSecret string
	// AgentID 应用 ID,必填
	AgentID int64
	// contains filtered or unexported fields
}

WorkwxApp 企业微信客户端(分应用)

func (*WorkwxApp) CreateAppchat

func (c *WorkwxApp) CreateAppchat(chatInfo *ChatInfo) (chatid string, err error)

CreateAppchat 创建群聊会话

func (*WorkwxApp) GetAppchat

func (c *WorkwxApp) GetAppchat(chatid string) (*ChatInfo, error)

GetAppchat 获取群聊会话

func (*WorkwxApp) GetUser

func (c *WorkwxApp) GetUser(userid string) (*UserInfo, error)

GetUser 读取成员

func (*WorkwxApp) ListAllDepts

func (c *WorkwxApp) ListAllDepts() ([]*DeptInfo, error)

ListAllDepts 获取全量组织架构。

func (*WorkwxApp) ListDepts

func (c *WorkwxApp) ListDepts(id int64) ([]*DeptInfo, error)

ListDepts 获取指定部门及其下的子部门。

func (*WorkwxApp) ListUsersByDeptID

func (c *WorkwxApp) ListUsersByDeptID(deptID int64, fetchChild bool) ([]*UserInfo, error)

ListUsersByDeptID 获取部门成员详情

func (*WorkwxApp) SendFileMessage

func (c *WorkwxApp) SendFileMessage(
	recipient *Recipient,
	mediaID string,
	isSafe bool,
) error

SendFileMessage 发送文件消息

收件人参数如果仅设置了 `ChatID` 字段,则为【发送消息到群聊会话】接口调用; 否则为单纯的【发送应用消息】接口调用。

func (*WorkwxApp) SendImageMessage

func (c *WorkwxApp) SendImageMessage(
	recipient *Recipient,
	mediaID string,
	isSafe bool,
) error

SendImageMessage 发送图片消息

收件人参数如果仅设置了 `ChatID` 字段,则为【发送消息到群聊会话】接口调用; 否则为单纯的【发送应用消息】接口调用。

func (*WorkwxApp) SendMPNewsMessage

func (c *WorkwxApp) SendMPNewsMessage(
	recipient *Recipient,
	title string,
	thumbMediaID string,
	author string,
	sourceContentURL string,
	content string,
	digest string,
	isSafe bool,
) error

SendMPNewsMessage 发送 mpnews 类型的图文消息

收件人参数如果仅设置了 `ChatID` 字段,则为【发送消息到群聊会话】接口调用; 否则为单纯的【发送应用消息】接口调用。

func (*WorkwxApp) SendMarkdownMessage

func (c *WorkwxApp) SendMarkdownMessage(
	recipient *Recipient,
	content string,
	isSafe bool,
) error

SendMarkdownMessage 发送 Markdown 消息

仅支持 Markdown 的子集,详见[官方文档](https://work.weixin.qq.com/api/doc#90002/90151/90854/%E6%94%AF%E6%8C%81%E7%9A%84markdown%E8%AF%AD%E6%B3%95)。

收件人参数如果仅设置了 `ChatID` 字段,则为【发送消息到群聊会话】接口调用; 否则为单纯的【发送应用消息】接口调用。

func (*WorkwxApp) SendNewsMessage

func (c *WorkwxApp) SendNewsMessage(
	recipient *Recipient,
	title string,
	description string,
	url string,
	picURL string,
	isSafe bool,
) error

SendNewsMessage 发送图文消息

收件人参数如果仅设置了 `ChatID` 字段,则为【发送消息到群聊会话】接口调用; 否则为单纯的【发送应用消息】接口调用。

func (*WorkwxApp) SendTextCardMessage

func (c *WorkwxApp) SendTextCardMessage(
	recipient *Recipient,
	title string,
	description string,
	url string,
	buttonText string,
	isSafe bool,
) error

SendTextCardMessage 发送文本卡片消息

收件人参数如果仅设置了 `ChatID` 字段,则为【发送消息到群聊会话】接口调用; 否则为单纯的【发送应用消息】接口调用。

func (*WorkwxApp) SendTextMessage

func (c *WorkwxApp) SendTextMessage(
	recipient *Recipient,
	content string,
	isSafe bool,
) error

SendTextMessage 发送文本消息

收件人参数如果仅设置了 `ChatID` 字段,则为【发送消息到群聊会话】接口调用; 否则为单纯的【发送应用消息】接口调用。

Example
corpID := "your_corpid"
corpSecret := "your_corpsecret"
agentID := int64(1234567)

client := workwx.New(corpID)

app := client.WithApp(corpSecret, agentID)
// preferably do this at app initialization
app.SpawnAccessTokenRefresher()

// send to user(s)
to1 := workwx.Recipient{
	UserIDs: []string{"testuser"},
}
_ = app.SendTextMessage(&to1, "send to user(s)", false)

// "safe" message
to2 := workwx.Recipient{
	UserIDs: []string{"testuser"},
}
_ = app.SendTextMessage(&to2, "safe message", true)

// send to party(parties)
to3 := workwx.Recipient{
	PartyIDs: []string{"testdept"},
}
_ = app.SendTextMessage(&to3, "send to party(parties)", false)

// send to tag(s)
to4 := workwx.Recipient{
	TagIDs: []string{"testtag"},
}
_ = app.SendTextMessage(&to4, "send to tag(s)", false)

// send to chatid
to5 := workwx.Recipient{
	ChatID: "testchat",
}
_ = app.SendTextMessage(&to5, "send to chatid", false)
Output:

func (*WorkwxApp) SendVideoMessage

func (c *WorkwxApp) SendVideoMessage(
	recipient *Recipient,
	mediaID string,
	description string,
	title string,
	isSafe bool,
) error

SendVideoMessage 发送视频消息

收件人参数如果仅设置了 `ChatID` 字段,则为【发送消息到群聊会话】接口调用; 否则为单纯的【发送应用消息】接口调用。

func (*WorkwxApp) SendVoiceMessage

func (c *WorkwxApp) SendVoiceMessage(
	recipient *Recipient,
	mediaID string,
	isSafe bool,
) error

SendVoiceMessage 发送语音消息

收件人参数如果仅设置了 `ChatID` 字段,则为【发送消息到群聊会话】接口调用; 否则为单纯的【发送应用消息】接口调用。

func (*WorkwxApp) SpawnAccessTokenRefresher

func (c *WorkwxApp) SpawnAccessTokenRefresher()

SpawnAccessTokenRefresher 启动该 app 的 access token 刷新 goroutine

NOTE: 该 goroutine 本身没有 keep-alive 逻辑,需要自助保活

func (*WorkwxApp) UploadPermanentImageMedia

func (c *WorkwxApp) UploadPermanentImageMedia(media *Media) (url string, err error)

UploadPermanentImageMedia 上传永久图片素材

func (*WorkwxApp) UploadTempFileMedia

func (c *WorkwxApp) UploadTempFileMedia(media *Media) (*MediaUploadResult, error)

UploadTempFileMedia 上传临时文件素材

func (*WorkwxApp) UploadTempImageMedia

func (c *WorkwxApp) UploadTempImageMedia(media *Media) (*MediaUploadResult, error)

UploadTempImageMedia 上传临时图片素材

func (*WorkwxApp) UploadTempVideoMedia

func (c *WorkwxApp) UploadTempVideoMedia(media *Media) (*MediaUploadResult, error)

UploadTempVideoMedia 上传临时视频素材

func (*WorkwxApp) UploadTempVoiceMedia

func (c *WorkwxApp) UploadTempVoiceMedia(media *Media) (*MediaUploadResult, error)

UploadTempVoiceMedia 上传临时语音素材

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL