user.go 19 KB

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