#1078 完善企业微信外部联系人相关接口

- 完成ExternalContact基础三个接口
- 外部联系人变更事件的消息解析
- 外部联系人的属性,增加标记公司名称和标记电话号码,还有tag分类
- 企业微信API url修改优化
This commit is contained in:
曹祖鹏 2019-06-18 18:01:38 +08:00 committed by Binary Wang
parent b2cf45297d
commit 90b5ca56c2
15 changed files with 393 additions and 28 deletions

View File

@ -0,0 +1,58 @@
package me.chanjar.weixin.cp.api;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.bean.WxCpUserExternalContactInfo;
import java.util.List;
/**
* <pre>
* 外部联系人管理接口企业微信的外部联系人的接口和通讯录接口已经拆离
* Created by Joe Cao on 2019/6/14
* </pre>
*
* @author <a href="https://github.com/JoeCao">JoeCao</a>
*/
public interface WxCpExternalContactService {
/**
* 获取外部联系人详情.
* <pre>
* 企业可通过此接口根据外部联系人的userid拉取外部联系人详情权限说明
* 企业需要使用外部联系人管理secret所获取的accesstoken来调用
* 第三方应用需拥有企业客户权限
* 第三方应用调用时返回的跟进人follow_user仅包含应用可见范围之内的成员
* </pre>
*
* @param userId 外部联系人的userid
*/
WxCpUserExternalContactInfo getExternalContact(String userId) throws WxErrorException;
/**
* 获取外部联系人列表.
* <pre>
* 企业可通过此接口获取指定成员添加的客户列表
* 客户是指配置了客户联系功能的成员所添加的外部联系人
* 没有配置客户联系功能的成员所添加的外部联系人将不会作为客户返回
* 第三方应用需拥有企业客户权限
* 第三方应用调用时返回的跟进人follow_user仅包含应用可见范围之内的成员
* </pre>
*
* @param userId 外部联系人的userid
* @return List of External wx id
*/
List<String> listExternalContacts(String userId) throws WxErrorException;
/**
* 企业和第三方服务商可通过此接口获取配置了客户联系功能的成员(Customer Contact)列表
* <pre>
* 企业需要使用外部联系人管理secret所获取的accesstoken来调用accesstoken如何获取
* 第三方应用需拥有企业客户权限
* 第三方应用只能获取到可见范围内的配置了客户联系功能的成员
* </pre>
*
* @return List of CpUser id
*/
List<String> listFollowUser() throws WxErrorException;
}

View File

@ -284,7 +284,9 @@ public interface WxCpService {
* 获取用户相关接口的服务类对象
*/
WxCpUserService getUserService();
WxCpExternalContactService getExternalContactService();
/**
* 获取群聊服务
*

View File

@ -149,4 +149,6 @@ public interface WxCpUserService {
* @param userId 外部联系人的userid
*/
WxCpUserExternalContactInfo getExternalContact(String userId) throws WxErrorException;
}

View File

@ -19,17 +19,7 @@ import me.chanjar.weixin.common.util.http.RequestExecutor;
import me.chanjar.weixin.common.util.http.RequestHttp;
import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
import me.chanjar.weixin.cp.api.WxCpAgentService;
import me.chanjar.weixin.cp.api.WxCpChatService;
import me.chanjar.weixin.cp.api.WxCpDepartmentService;
import me.chanjar.weixin.cp.api.WxCpMediaService;
import me.chanjar.weixin.cp.api.WxCpMenuService;
import me.chanjar.weixin.cp.api.WxCpOAuth2Service;
import me.chanjar.weixin.cp.api.WxCpOaService;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.api.WxCpTagService;
import me.chanjar.weixin.cp.api.WxCpTaskCardService;
import me.chanjar.weixin.cp.api.WxCpUserService;
import me.chanjar.weixin.cp.api.*;
import me.chanjar.weixin.cp.bean.WxCpMaJsCode2SessionResult;
import me.chanjar.weixin.cp.bean.WxCpMessage;
import me.chanjar.weixin.cp.bean.WxCpMessageSendResult;
@ -60,6 +50,7 @@ public abstract class BaseWxCpServiceImpl<H, P> implements WxCpService, RequestH
private WxCpAgentService agentService = new WxCpAgentServiceImpl(this);
private WxCpOaService oaService = new WxCpOaServiceImpl(this);
private WxCpTaskCardService taskCardService = new WxCpTaskCardServiceImpl(this);
private WxCpExternalContactService externalContactService = new WxCpExternalContactServiceImpl(this);
/**
* 全局的是否正在刷新access token的锁
@ -396,6 +387,11 @@ public abstract class BaseWxCpServiceImpl<H, P> implements WxCpService, RequestH
return userService;
}
@Override
public WxCpExternalContactService getExternalContactService() {
return externalContactService;
}
@Override
public WxCpChatService getChatService() {
return chatService;

View File

@ -0,0 +1,41 @@
package me.chanjar.weixin.cp.api.impl;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.api.WxCpExternalContactService;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.WxCpUserExternalContactInfo;
import me.chanjar.weixin.cp.bean.WxCpUserExternalContactList;
import me.chanjar.weixin.cp.bean.WxCpUserWithExternalPermission;
import java.util.List;
import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.ExternalContact.*;
public class WxCpExternalContactServiceImpl implements WxCpExternalContactService {
private WxCpService mainService;
public WxCpExternalContactServiceImpl(WxCpService mainService) {
this.mainService = mainService;
}
@Override
public WxCpUserExternalContactInfo getExternalContact(String userId) throws WxErrorException {
String responseContent = this.mainService.get(this.mainService.getWxCpConfigStorage().getApiUrl(GET_EXTERNAL_CONTACT + userId), null);
return WxCpUserExternalContactInfo.fromJson(responseContent);
}
@Override
public List<String> listExternalContacts(String userId) throws WxErrorException {
String responseContent = this.mainService.get(this.mainService.getWxCpConfigStorage().getApiUrl(LIST_EXTERNAL_CONTACT + userId), null);
WxCpUserExternalContactList list = WxCpUserExternalContactList.fromJson(responseContent);
return list.getExternalUserId();
}
@Override
public List<String> listFollowUser() throws WxErrorException {
String responseContent = this.mainService.get(this.mainService.getWxCpConfigStorage().getApiUrl(GET_FOLLOW_USER_LIST), null);
WxCpUserWithExternalPermission list = WxCpUserWithExternalPermission.fromJson(responseContent);
return list.getFollowUser();
}
}

View File

@ -1,16 +1,11 @@
package me.chanjar.weixin.cp.bean;
import java.util.List;
import com.google.gson.annotations.SerializedName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.*;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
import java.util.List;
/**
* <pre>
* 外部联系人详情
@ -118,9 +113,26 @@ public class WxCpUserExternalContactInfo {
private String description;
@SerializedName("createtime")
private Long createTime;
private String state;
@SerializedName("remark_company")
private String remarkCompany;
@SerializedName("remark_mobiles")
private String[] remarkMobiles;
private Tag[] tags;
}
public static WxCpUserExternalContactInfo fromJson(String json) {
return WxCpGsonBuilder.create().fromJson(json, WxCpUserExternalContactInfo.class);
}
@Setter
@Getter
public static class Tag {
@SerializedName("group_name")
private String groupName;
@SerializedName("tag_name")
private String tagName;
private int type;
}
}

View File

@ -0,0 +1,58 @@
package me.chanjar.weixin.cp.bean;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
import java.util.List;
/**
* <pre>
* 外部联系人列表
* Created by Joe Cao on 2019/6/16.
* 参考文档https://work.weixin.qq.com/api/doc#90001/90143/91570
* </pre>
*
* @author <a href="https://github.com/JoeCao">Joe Cao</a>
*/
public class WxCpUserExternalContactList {
@SerializedName("errcode")
@Expose
private Long errcode;
@SerializedName("errmsg")
@Expose
private String errmsg;
@SerializedName("external_userid")
@Expose
private List<String> externalUserId = null;
public Long getErrcode() {
return errcode;
}
public void setErrcode(Long errcode) {
this.errcode = errcode;
}
public String getErrmsg() {
return errmsg;
}
public void setErrmsg(String errmsg) {
this.errmsg = errmsg;
}
public List<String> getExternalUserId() {
return externalUserId;
}
public void setExternalUserId(List<String> externalUserId) {
this.externalUserId = externalUserId;
}
public static WxCpUserExternalContactList fromJson(String json) {
return WxCpGsonBuilder.create().fromJson(json, WxCpUserExternalContactList.class);
}
}

View File

@ -0,0 +1,49 @@
package me.chanjar.weixin.cp.bean;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
import java.util.List;
public class WxCpUserWithExternalPermission {
@SerializedName("errcode")
@Expose
private Long errcode;
@SerializedName("errmsg")
@Expose
private String errmsg;
@SerializedName("follow_user")
@Expose
private List<String> followUser = null;
public Long getErrcode() {
return errcode;
}
public void setErrcode(Long errcode) {
this.errcode = errcode;
}
public String getErrmsg() {
return errmsg;
}
public void setErrmsg(String errmsg) {
this.errmsg = errmsg;
}
public List<String> getFollowUser() {
return followUser;
}
public void setFollowUser(List<String> followUser) {
this.followUser = followUser;
}
public static WxCpUserWithExternalPermission fromJson(String json) {
return WxCpGsonBuilder.create().fromJson(json, WxCpUserWithExternalPermission.class);
}
}

View File

@ -175,6 +175,26 @@ public class WxCpXmlMessage implements Serializable {
@XStreamConverter(value = XStreamCDataConverter.class)
private String userId;
/**
* 变更信息的外部联系人的userid注意不是企业成员的帐号.
*/
@XStreamAlias("ExternalUserID")
@XStreamConverter(value = XStreamCDataConverter.class)
private String externalUserID;
/**
* 添加此用户的联系我方式配置的state参数可用于识别添加此用户的渠道
*/
@XStreamAlias("State")
@XStreamConverter(value = XStreamCDataConverter.class)
private String state;
/**
* 欢迎语code可用于发送欢迎语
*/
@XStreamAlias("WelcomeCode")
@XStreamConverter(value = XStreamCDataConverter.class)
private String welcomeCode;
/**
* 新的UserID变更时推送userid由系统生成时可更改一次.
*/

View File

@ -103,4 +103,10 @@ public final class WxCpApiPathConsts {
public static final String USER_CONVERT_TO_USERID = "/cgi-bin/user/convert_to_userid";
public static final String GET_EXTERNAL_CONTACT = "/cgi-bin/crm/get_external_contact?external_userid=";
}
public static class ExternalContact {
public static final String GET_EXTERNAL_CONTACT = "/cgi-bin/crm/get_external_contact?external_userid=";
public static final String LIST_EXTERNAL_CONTACT = "/cgi-bin/externalcontact/list?userid=";
public static final String GET_FOLLOW_USER_LIST = "/cgi-bin/externalcontact/get_follow_user_list";
}
}

View File

@ -89,6 +89,26 @@ public class WxCpConsts {
*/
public static final String TASKCARD_CLICK = "taskcard_click";
/**
* 企业成员添加外部联系人事件推送
*/
public static final String CHANGE_EXTERNAL_CONTACT = "change_external_contact";
}
/**
* 企业外部联系人变更事件的CHANGE_TYPE
*/
public static class ExternalContactChangeType {
/**
* 新增外部联系人
*/
public static final String ADD_EXTERNAL_CONTACT = "add_external_contact";
/**
* 删除外部联系人
*/
public static final String DEL_EXTERNAL_CONTACT = "del_external_contact";
}
/**

View File

@ -52,6 +52,8 @@ public class ApiTestModule implements Module {
protected String tagId;
protected String externalUserId;
public String getUserId() {
return this.userId;
}
@ -76,12 +78,22 @@ public class ApiTestModule implements Module {
this.tagId = tagId;
}
public String getExternalUserId() {
return externalUserId;
}
public void setExternalUserId(String externalUserId) {
this.externalUserId = externalUserId;
}
@Override
public String toString() {
return super.toString() + " > WxXmlCpConfigStorage{" +
"userId='" + this.userId + '\'' +
", departmentId='" + this.departmentId + '\'' +
", tagId='" + this.tagId + '\'' +
", externalUserId='" + this.externalUserId + '\'' +
'}';
}
}

View File

@ -0,0 +1,45 @@
package me.chanjar.weixin.cp.api.impl;
import com.google.inject.Inject;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.api.ApiTestModule;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.WxCpUserExternalContactInfo;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import java.util.List;
import static org.testng.Assert.assertNotNull;
@Guice(modules = ApiTestModule.class)
public class WxCpExternalContactServiceImplTest {
@Inject
private WxCpService wxCpService;
@Inject
protected ApiTestModule.WxXmlCpInMemoryConfigStorage configStorage;
private String userId = "someone" + System.currentTimeMillis();
@Test
public void testGetExternalContact() throws WxErrorException {
String externalUserId = this.configStorage.getExternalUserId();
WxCpUserExternalContactInfo result = this.wxCpService.getExternalContactService().getExternalContact(externalUserId);
System.out.println(result);
assertNotNull(result);
}
@Test
public void testListExternalContacts() throws WxErrorException {
String userId = this.configStorage.getUserId();
List<String> ret = this.wxCpService.getExternalContactService().listExternalContacts(userId);
System.out.println(ret);
assertNotNull(ret);
}
@Test
public void testListExternalWithPermission() throws WxErrorException {
List<String> ret = this.wxCpService.getExternalContactService().listFollowUser();
System.out.println(ret);
assertNotNull(ret);
}
}

View File

@ -93,7 +93,7 @@ public class WxCpUserServiceImplTest {
@Test
public void testInvite() throws Exception {
WxCpInviteResult result = this.wxCpService.getUserService().invite(
Lists.newArrayList(userId), null,null);
Lists.newArrayList(userId), null, null);
System.out.println(result);
}
@ -111,10 +111,5 @@ public class WxCpUserServiceImplTest {
assertNotNull(result);
}
@Test
public void testGetExternalContact() throws WxErrorException {
WxCpUserExternalContactInfo result = this.wxCpService.getUserService().getExternalContact(userId);
System.out.println(result);
assertNotNull(result);
}
}

View File

@ -1,6 +1,7 @@
package me.chanjar.weixin.cp.bean;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.cp.constant.WxCpConsts;
import org.testng.annotations.Test;
import static me.chanjar.weixin.cp.constant.WxCpConsts.EventType.TASKCARD_CLICK;
@ -106,7 +107,7 @@ public class WxCpXmlMessageTest {
"<Count>2</Count>" +
"</SendPicsInfo>" +
"</xml>";
WxCpXmlMessage wxMessage = WxCpXmlMessage.fromXml(xml.replace("</PicList><PicList>",""));
WxCpXmlMessage wxMessage = WxCpXmlMessage.fromXml(xml.replace("</PicList><PicList>", ""));
assertEquals(wxMessage.getToUserName(), "wx45a0972125658be9");
assertEquals(wxMessage.getFromUserName(), "xiaohe");
assertEquals(wxMessage.getCreateTime(), new Long(1502012364L));
@ -173,4 +174,52 @@ public class WxCpXmlMessageTest {
assertEquals(wxMessage.getEventKey(), "key111");
assertEquals(wxMessage.getTaskId(), "taskid111");
}
public void testAddExternalUserEvent() {
String xml = "<xml>" +
"<ToUserName><![CDATA[toUser]]></ToUserName>" +
"<FromUserName><![CDATA[sys]]></FromUserName>" +
"<CreateTime>1403610513</CreateTime>" +
"<MsgType><![CDATA[event]]></MsgType>" +
"<Event><![CDATA[change_external_contact]]></Event>" +
"<ChangeType><![CDATA[add_external_contact]]></ChangeType>" +
"<UserID><![CDATA[zhangsan]]></UserID>" +
"<ExternalUserID><![CDATA[woAJ2GCAAAXtWyujaWJHDDGi0mACH71w]]></ExternalUserID>" +
"<State><![CDATA[teststate]]></State>" +
"<WelcomeCode><![CDATA[WELCOMECODE]]></WelcomeCode>" +
"</xml >";
WxCpXmlMessage wxMessage = WxCpXmlMessage.fromXml(xml);
assertEquals(wxMessage.getToUserName(), "toUser");
assertEquals(wxMessage.getFromUserName(), "sys");
assertEquals(wxMessage.getCreateTime(), Long.valueOf(1403610513L));
assertEquals(wxMessage.getMsgType(), WxConsts.XmlMsgType.EVENT);
assertEquals(wxMessage.getEvent(), WxCpConsts.EventType.CHANGE_EXTERNAL_CONTACT);
assertEquals(wxMessage.getChangeType(), WxCpConsts.ExternalContactChangeType.ADD_EXTERNAL_CONTACT);
assertEquals(wxMessage.getExternalUserID(), "woAJ2GCAAAXtWyujaWJHDDGi0mACH71w");
assertEquals(wxMessage.getState(), "teststate");
assertEquals(wxMessage.getWelcomeCode(), "WELCOMECODE");
}
public void testDelExternalUserEvent() {
String xml = "<xml>" +
"<ToUserName><![CDATA[toUser]]></ToUserName>" +
"<FromUserName><![CDATA[sys]]></FromUserName>" +
"<CreateTime>1403610513</CreateTime>" +
"<MsgType><![CDATA[event]]></MsgType>" +
"<Event><![CDATA[change_external_contact]]></Event>" +
"<ChangeType><![CDATA[del_external_contact]]></ChangeType>" +
"<UserID><![CDATA[zhangsan]]></UserID>" +
"<ExternalUserID><![CDATA[woAJ2GCAAAXtWyujaWJHDDGi0mACH71w]]></ExternalUserID>" +
"</xml>";
WxCpXmlMessage wxMessage = WxCpXmlMessage.fromXml(xml);
assertEquals(wxMessage.getToUserName(), "toUser");
assertEquals(wxMessage.getFromUserName(), "sys");
assertEquals(wxMessage.getCreateTime(), Long.valueOf(1403610513L));
assertEquals(wxMessage.getMsgType(), WxConsts.XmlMsgType.EVENT);
assertEquals(wxMessage.getEvent(), WxCpConsts.EventType.CHANGE_EXTERNAL_CONTACT);
assertEquals(wxMessage.getChangeType(), WxCpConsts.ExternalContactChangeType.DEL_EXTERNAL_CONTACT);
assertEquals(wxMessage.getUserId(), "zhangsan");
assertEquals(wxMessage.getExternalUserID(), "woAJ2GCAAAXtWyujaWJHDDGi0mACH71w");
}
}