diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java new file mode 100644 index 00000000..92f22586 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java @@ -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; + +/** + *
+ * 外部联系人管理接口,企业微信的外部联系人的接口和通讯录接口已经拆离 + * Created by Joe Cao on 2019/6/14 + *+ * + * @author JoeCao + */ +public interface WxCpExternalContactService { + /** + * 获取外部联系人详情. + *
+ * 企业可通过此接口,根据外部联系人的userid,拉取外部联系人详情。权限说明: + * 企业需要使用外部联系人管理secret所获取的accesstoken来调用 + * 第三方应用需拥有“企业客户”权限。 + * 第三方应用调用时,返回的跟进人follow_user仅包含应用可见范围之内的成员。 + *+ * + * @param userId 外部联系人的userid + */ + WxCpUserExternalContactInfo getExternalContact(String userId) throws WxErrorException; + + /** + * 获取外部联系人列表. + *
+ * 企业可通过此接口获取指定成员添加的客户列表。 + * 客户是指配置了客户联系功能的成员所添加的外部联系人。 + * 没有配置客户联系功能的成员,所添加的外部联系人将不会作为客户返回。 + * 第三方应用需拥有“企业客户”权限。 + * 第三方应用调用时,返回的跟进人follow_user仅包含应用可见范围之内的成员。 + *+ * + * @param userId 外部联系人的userid + * @return List of External wx id + */ + List
+ * 企业需要使用外部联系人管理secret所获取的accesstoken来调用(accesstoken如何获取?); + * 第三方应用需拥有“企业客户”权限。 + * 第三方应用只能获取到可见范围内的配置了客户联系功能的成员 + *+ * + * @return List of CpUser id + */ + List
* 外部联系人详情 @@ -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; + } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserExternalContactList.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserExternalContactList.java new file mode 100644 index 00000000..25e42ffc --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserExternalContactList.java @@ -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; + +/** + *+ * 外部联系人列表 + * Created by Joe Cao on 2019/6/16. + * 参考文档:https://work.weixin.qq.com/api/doc#90001/90143/91570 + *+ * + * @author Joe Cao + */ +public class WxCpUserExternalContactList { + @SerializedName("errcode") + @Expose + private Long errcode; + @SerializedName("errmsg") + @Expose + private String errmsg; + + @SerializedName("external_userid") + @Expose + private ListexternalUserId = 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 getExternalUserId() { + return externalUserId; + } + + public void setExternalUserId(List externalUserId) { + this.externalUserId = externalUserId; + } + + public static WxCpUserExternalContactList fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpUserExternalContactList.class); + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserWithExternalPermission.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserWithExternalPermission.java new file mode 100644 index 00000000..2530c79d --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUserWithExternalPermission.java @@ -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 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 getFollowUser() { + return followUser; + } + + public void setFollowUser(List followUser) { + this.followUser = followUser; + } + + + public static WxCpUserWithExternalPermission fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpUserWithExternalPermission.class); + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java index 72f63b5d..c201af5c 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java @@ -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由系统生成时可更改一次). */ diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java index 9e1294db..61c3459f 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java @@ -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"; + } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java index b3809ad0..aa4eded4 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java @@ -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"; } /** diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java index c87b6455..5ef750f8 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java @@ -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 + '\'' + + '}'; } } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java new file mode 100644 index 00000000..d39fd6e4 --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java @@ -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 ret = this.wxCpService.getExternalContactService().listExternalContacts(userId); + System.out.println(ret); + assertNotNull(ret); + } + + @Test + public void testListExternalWithPermission() throws WxErrorException { + List ret = this.wxCpService.getExternalContactService().listFollowUser(); + System.out.println(ret); + assertNotNull(ret); + } +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java index 2ec33e7b..6b88876f 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpUserServiceImplTest.java @@ -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); - } + } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java index 11a2dbe4..ad9a04b6 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlMessageTest.java @@ -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 { " 2 " + "" + ""; - WxCpXmlMessage wxMessage = WxCpXmlMessage.fromXml(xml.replace("","")); + WxCpXmlMessage wxMessage = WxCpXmlMessage.fromXml(xml.replace(" ", "")); 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 = " " + + " "; + 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 = "" + + " " + + " 1403610513 " + + "" + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " "; + 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"); + } }" + + " " + + " 1403610513 " + + "" + + " " + + " " + + " " + + " " + + "