user.go 17 KB

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