user.go 20 KB

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