user.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. package addresslist
  2. import (
  3. "fmt"
  4. "strings"
  5. "github.com/silenceper/wechat/v2/util"
  6. )
  7. const (
  8. // userSimpleListURL 获取部门成员
  9. userSimpleListURL = "https://qyapi.weixin.qq.com/cgi-bin/user/simplelist"
  10. // userCreateURL 创建成员
  11. userCreateURL = "https://qyapi.weixin.qq.com/cgi-bin/user/create?access_token=%s"
  12. // userGetURL 读取成员
  13. userGetURL = "https://qyapi.weixin.qq.com/cgi-bin/user/get"
  14. // userDeleteURL 删除成员
  15. userDeleteURL = "https://qyapi.weixin.qq.com/cgi-bin/user/delete"
  16. // userListIDURL 获取成员 ID 列表
  17. userListIDURL = "https://qyapi.weixin.qq.com/cgi-bin/user/list_id"
  18. // convertToOpenIDURL userID 转 openID
  19. convertToOpenIDURL = "https://qyapi.weixin.qq.com/cgi-bin/user/convert_to_openid"
  20. // convertToUserIDURL openID 转 userID
  21. convertToUserIDURL = "https://qyapi.weixin.qq.com/cgi-bin/user/convert_to_userid"
  22. )
  23. type (
  24. // UserSimpleListResponse 获取部门成员响应
  25. UserSimpleListResponse struct {
  26. util.CommonError
  27. UserList []*UserList
  28. }
  29. // UserList 部门成员
  30. UserList struct {
  31. UserID string `json:"userid"`
  32. Name string `json:"name"`
  33. Department []int `json:"department"`
  34. OpenUserID string `json:"open_userid"`
  35. }
  36. )
  37. // UserSimpleList 获取部门成员
  38. // @see https://developer.work.weixin.qq.com/document/path/90200
  39. func (r *Client) UserSimpleList(departmentID int) ([]*UserList, error) {
  40. var (
  41. accessToken string
  42. err error
  43. )
  44. if accessToken, err = r.GetAccessToken(); err != nil {
  45. return nil, err
  46. }
  47. var response []byte
  48. if response, err = util.HTTPGet(strings.Join([]string{
  49. userSimpleListURL,
  50. util.Query(map[string]interface{}{
  51. "access_token": accessToken,
  52. "department_id": departmentID,
  53. }),
  54. }, "?")); err != nil {
  55. return nil, err
  56. }
  57. result := &UserSimpleListResponse{}
  58. err = util.DecodeWithError(response, result, "UserSimpleList")
  59. return result.UserList, err
  60. }
  61. type (
  62. // UserCreateRequest 创建成员数据请求
  63. UserCreateRequest struct {
  64. UserID string `json:"userid"`
  65. Name string `json:"name"`
  66. Alias string `json:"alias"`
  67. Mobile string `json:"mobile"`
  68. Department []int `json:"department"`
  69. Order []int `json:"order"`
  70. Position string `json:"position"`
  71. Gender int `json:"gender"`
  72. Email string `json:"email"`
  73. BizMail string `json:"biz_mail"`
  74. IsLeaderInDept []int `json:"is_leader_in_dept"`
  75. DirectLeader []string `json:"direct_leader"`
  76. Enable int `json:"enable"`
  77. AvatarMediaid string `json:"avatar_mediaid"`
  78. Telephone string `json:"telephone"`
  79. Address string `json:"address"`
  80. MainDepartment int `json:"main_department"`
  81. Extattr struct {
  82. Attrs []ExtraAttr `json:"attrs"`
  83. } `json:"extattr"`
  84. ToInvite bool `json:"to_invite"`
  85. ExternalPosition string `json:"external_position"`
  86. ExternalProfile ExternalProfile `json:"external_profile"`
  87. }
  88. // ExtraAttr 扩展属性
  89. ExtraAttr struct {
  90. Type int `json:"type"`
  91. Name string `json:"name"`
  92. Text struct {
  93. Value string `json:"value"`
  94. } `json:"text,omitempty"`
  95. Web struct {
  96. URL string `json:"url"`
  97. Title string `json:"title"`
  98. } `json:"web,omitempty"`
  99. }
  100. // ExternalProfile 成员对外信息
  101. ExternalProfile struct {
  102. ExternalCorpName string `json:"external_corp_name"`
  103. WechatChannels struct {
  104. Nickname string `json:"nickname"`
  105. Status int `json:"status"`
  106. } `json:"wechat_channels"`
  107. ExternalAttr []ExternalProfileAttr `json:"external_attr"`
  108. }
  109. // ExternalProfileAttr 成员对外信息属性
  110. ExternalProfileAttr struct {
  111. Type int `json:"type"`
  112. Name string `json:"name"`
  113. Text struct {
  114. Value string `json:"value"`
  115. } `json:"text,omitempty"`
  116. Web struct {
  117. URL string `json:"url"`
  118. Title string `json:"title"`
  119. } `json:"web,omitempty"`
  120. Miniprogram struct {
  121. Appid string `json:"appid"`
  122. Pagepath string `json:"pagepath"`
  123. Title string `json:"title"`
  124. } `json:"miniprogram,omitempty"`
  125. }
  126. // UserCreateResponse 创建成员数据响应
  127. UserCreateResponse struct {
  128. util.CommonError
  129. }
  130. )
  131. // UserCreate 创建成员
  132. // @see https://developer.work.weixin.qq.com/document/path/90195
  133. func (r *Client) UserCreate(req *UserCreateRequest) (*UserCreateResponse, error) {
  134. var (
  135. accessToken string
  136. err error
  137. )
  138. if accessToken, err = r.GetAccessToken(); err != nil {
  139. return nil, err
  140. }
  141. var response []byte
  142. if response, err = util.PostJSON(fmt.Sprintf(userCreateURL, accessToken), req); err != nil {
  143. return nil, err
  144. }
  145. result := &UserCreateResponse{}
  146. err = util.DecodeWithError(response, result, "UserCreate")
  147. return result, err
  148. }
  149. // UserGetResponse 获取部门成员响应
  150. type UserGetResponse struct {
  151. util.CommonError
  152. UserID string `json:"userid"` // 成员 UserID。对应管理端的帐号,企业内必须唯一。不区分大小写,长度为 1~64 个字节;第三方应用返回的值为 open_userid
  153. Name string `json:"name"` // 成员名称;第三方不可获取,调用时返回 userid 以代替 name;代开发自建应用需要管理员授权才返回;对于非第三方创建的成员,第三方通讯录应用也不可获取;未返回 name 的情况需要通过通讯录展示组件来展示名字
  154. Department []int `json:"department"` // 成员所属部门 id 列表,仅返回该应用有查看权限的部门 id;成员授权模式下,固定返回根部门 id,即固定为 1。对授权了“组织架构信息”权限的第三方应用,返回成员所属的全部部门 id
  155. Order []int `json:"order"` // 部门内的排序值,默认为 0。数量必须和 department 一致,数值越大排序越前面。值范围是 [0, 2^32)。成员授权模式下不返回该字段
  156. Position string `json:"position"` // 职务信息;代开发自建应用需要管理员授权才返回;第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段
  157. Mobile string `json:"mobile"` // 手机号码,代开发自建应用需要管理员授权且成员 oauth2 授权获取;第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段
  158. Gender string `json:"gender"` // 性别。0 表示未定义,1 表示男性,2 表示女性。代开发自建应用需要管理员授权且成员 oauth2 授权获取;第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段。注:不可获取指返回值 0
  159. Email string `json:"email"` // 邮箱,代开发自建应用需要管理员授权且成员 oauth2 授权获取;第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段
  160. BizMail string `json:"biz_mail"` // 企业邮箱,代开发自建应用需要管理员授权且成员 oauth2 授权获取;第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段
  161. IsLeaderInDept []int `json:"is_leader_in_dept"` // 表示在所在的部门内是否为部门负责人,数量与 department 一致;第三方通讯录应用或者授权了“组织架构信息 - 应用可获取企业的部门组织架构信息 - 部门负责人”权限的第三方应用可获取;对于非第三方创建的成员,第三方通讯录应用不可获取;上游企业不可获取下游企业成员该字段
  162. DirectLeader []string `json:"direct_leader"` // 直属上级 UserID,返回在应用可见范围内的直属上级列表,最多有五个直属上级;第三方通讯录应用或者授权了“组织架构信息 - 应用可获取可见范围内成员组织架构信息 - 直属上级”权限的第三方应用可获取;对于非第三方创建的成员,第三方通讯录应用不可获取;上游企业不可获取下游企业成员该字段;代开发自建应用不可获取该字段
  163. Avatar string `json:"avatar"` // 头像 url。代开发自建应用需要管理员授权且成员 oauth2 授权获取;第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段
  164. ThumbAvatar string `json:"thumb_avatar"` // 头像缩略图 url。第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段
  165. Telephone string `json:"telephone"` // 座机。代开发自建应用需要管理员授权才返回;第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段
  166. Alias string `json:"alias"` // 别名;第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段
  167. Address string `json:"address"` // 地址。代开发自建应用需要管理员授权且成员 oauth2 授权获取;第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段
  168. OpenUserid string `json:"open_userid"` // 全局唯一。对于同一个服务商,不同应用获取到企业内同一个成员的 open_userid 是相同的,最多 64 个字节。仅第三方应用可获取
  169. MainDepartment int `json:"main_department"` // 主部门,仅当应用对主部门有查看权限时返回。
  170. Extattr struct {
  171. Attrs []struct {
  172. Type int `json:"type"`
  173. Name string `json:"name"`
  174. Text struct {
  175. Value string `json:"value"`
  176. } `json:"text,omitempty"`
  177. Web struct {
  178. URL string `json:"url"`
  179. Title string `json:"title"`
  180. } `json:"web,omitempty"`
  181. } `json:"attrs"`
  182. } `json:"extattr"` // 扩展属性,代开发自建应用需要管理员授权才返回;第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段
  183. Status int `json:"status"` // 激活状态:1=已激活,2=已禁用,4=未激活,5=退出企业。已激活代表已激活企业微信或已关注微信插件(原企业号)。未激活代表既未激活企业微信又未关注微信插件(原企业号)。
  184. QrCode string `json:"qr_code"` // 员工个人二维码,扫描可添加为外部联系人 (注意返回的是一个 url,可在浏览器上打开该 url 以展示二维码);代开发自建应用需要管理员授权且成员 oauth2 授权获取;第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段
  185. ExternalPosition string `json:"external_position"` // 对外职务,如果设置了该值,则以此作为对外展示的职务,否则以 position 来展示。代开发自建应用需要管理员授权才返回;第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段
  186. ExternalProfile struct {
  187. ExternalCorpName string `json:"external_corp_name"`
  188. WechatChannels struct {
  189. Nickname string `json:"nickname"`
  190. Status int `json:"status"`
  191. } `json:"wechat_channels"`
  192. ExternalAttr []struct {
  193. Type int `json:"type"`
  194. Name string `json:"name"`
  195. Text struct {
  196. Value string `json:"value"`
  197. } `json:"text,omitempty"`
  198. Web struct {
  199. URL string `json:"url"`
  200. Title string `json:"title"`
  201. } `json:"web,omitempty"`
  202. Miniprogram struct {
  203. Appid string `json:"appid"`
  204. Pagepath string `json:"pagepath"`
  205. Title string `json:"title"`
  206. } `json:"miniprogram,omitempty"`
  207. } `json:"external_attr"`
  208. } `json:"external_profile"` // 成员对外属性,字段详情见对外属性;代开发自建应用需要管理员授权才返回;第三方仅通讯录应用可获取;对于非第三方创建的成员,第三方通讯录应用也不可获取;上游企业不可获取下游企业成员该字段
  209. }
  210. // UserGet 读取成员
  211. // @see https://developer.work.weixin.qq.com/document/path/90196
  212. func (r *Client) UserGet(UserID string) (*UserGetResponse, error) {
  213. var (
  214. accessToken string
  215. err error
  216. )
  217. if accessToken, err = r.GetAccessToken(); err != nil {
  218. return nil, err
  219. }
  220. var response []byte
  221. if response, err = util.HTTPGet(
  222. strings.Join([]string{
  223. userGetURL,
  224. util.Query(map[string]interface{}{
  225. "access_token": accessToken,
  226. "userid": UserID,
  227. }),
  228. }, "?")); err != nil {
  229. return nil, err
  230. }
  231. result := &UserGetResponse{}
  232. err = util.DecodeWithError(response, result, "UserGet")
  233. return result, err
  234. }
  235. type (
  236. // UserDeleteResponse 删除成员数据响应
  237. UserDeleteResponse struct {
  238. util.CommonError
  239. }
  240. )
  241. // UserDelete 删除成员
  242. // @see https://developer.work.weixin.qq.com/document/path/90334
  243. func (r *Client) UserDelete(userID string) (*UserDeleteResponse, error) {
  244. var (
  245. accessToken string
  246. err error
  247. )
  248. if accessToken, err = r.GetAccessToken(); err != nil {
  249. return nil, err
  250. }
  251. var response []byte
  252. if response, err = util.HTTPGet(strings.Join([]string{
  253. userDeleteURL,
  254. util.Query(map[string]interface{}{
  255. "access_token": accessToken,
  256. "userid": userID,
  257. }),
  258. }, "?")); err != nil {
  259. return nil, err
  260. }
  261. result := &UserDeleteResponse{}
  262. err = util.DecodeWithError(response, result, "UserDelete")
  263. return result, err
  264. }
  265. // UserListIDRequest 获取成员 ID 列表请求
  266. type UserListIDRequest struct {
  267. Cursor string `json:"cursor"`
  268. Limit int `json:"limit"`
  269. }
  270. // UserListIDResponse 获取成员 ID 列表响应
  271. type UserListIDResponse struct {
  272. util.CommonError
  273. NextCursor string `json:"next_cursor"`
  274. DeptUser []*DeptUser `json:"dept_user"`
  275. }
  276. // DeptUser 用户 - 部门关系
  277. type DeptUser struct {
  278. UserID string `json:"userid"`
  279. Department int `json:"department"`
  280. }
  281. // UserListID 获取成员 ID 列表
  282. // see https://developer.work.weixin.qq.com/document/path/96067
  283. func (r *Client) UserListID(req *UserListIDRequest) (*UserListIDResponse, error) {
  284. var (
  285. accessToken string
  286. err error
  287. )
  288. if accessToken, err = r.GetAccessToken(); err != nil {
  289. return nil, err
  290. }
  291. var response []byte
  292. if response, err = util.PostJSON(strings.Join([]string{
  293. userListIDURL,
  294. util.Query(map[string]interface{}{
  295. "access_token": accessToken,
  296. }),
  297. }, "?"), req); err != nil {
  298. return nil, err
  299. }
  300. result := &UserListIDResponse{}
  301. err = util.DecodeWithError(response, result, "UserListID")
  302. return result, err
  303. }
  304. type (
  305. // convertToOpenIDRequest userID 转 openID 请求
  306. convertToOpenIDRequest struct {
  307. UserID string `json:"userid"`
  308. }
  309. // convertToOpenIDResponse userID 转 openID 响应
  310. convertToOpenIDResponse struct {
  311. util.CommonError
  312. OpenID string `json:"openid"`
  313. }
  314. )
  315. // ConvertToOpenID userID 转 openID
  316. // see https://developer.work.weixin.qq.com/document/path/90202
  317. func (r *Client) ConvertToOpenID(userID string) (string, error) {
  318. var (
  319. accessToken string
  320. err error
  321. )
  322. if accessToken, err = r.GetAccessToken(); err != nil {
  323. return "", err
  324. }
  325. var response []byte
  326. if response, err = util.PostJSON(strings.Join([]string{
  327. convertToOpenIDURL,
  328. util.Query(map[string]interface{}{
  329. "access_token": accessToken,
  330. }),
  331. }, "?"), &convertToOpenIDRequest{
  332. UserID: userID,
  333. }); err != nil {
  334. return "", err
  335. }
  336. result := &convertToOpenIDResponse{}
  337. err = util.DecodeWithError(response, result, "ConvertToOpenID")
  338. return result.OpenID, err
  339. }
  340. type (
  341. // convertToUserIDRequest openID 转 userID 请求
  342. convertToUserIDRequest struct {
  343. OpenID string `json:"openid"`
  344. }
  345. // convertToUserIDResponse openID 转 userID 响应
  346. convertToUserIDResponse struct {
  347. util.CommonError
  348. UserID string `json:"userid"`
  349. }
  350. )
  351. // ConvertToUserID openID 转 userID
  352. // see https://developer.work.weixin.qq.com/document/path/90202
  353. func (r *Client) ConvertToUserID(openID string) (string, error) {
  354. var (
  355. accessToken string
  356. err error
  357. )
  358. if accessToken, err = r.GetAccessToken(); err != nil {
  359. return "", err
  360. }
  361. var response []byte
  362. if response, err = util.PostJSON(strings.Join([]string{
  363. convertToUserIDURL,
  364. util.Query(map[string]interface{}{
  365. "access_token": accessToken,
  366. }),
  367. }, "?"), &convertToUserIDRequest{
  368. OpenID: openID,
  369. }); err != nil {
  370. return "", err
  371. }
  372. result := &convertToUserIDResponse{}
  373. err = util.DecodeWithError(response, result, "ConvertToUserID")
  374. return result.UserID, err
  375. }