diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpTag.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpTag.java new file mode 100644 index 0000000000..b584b31dd1 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpTag.java @@ -0,0 +1,28 @@ +package me.chanjar.weixin.cp.bean; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.io.Serializable; + +/** + * + * @author zhangq + * @since 2021-02-14 16:15 16:15 + */ +@Data +public class WxCpTpTag implements Serializable { + + private static final long serialVersionUID = 581740383760234134L; + + @SerializedName("tagid") + private String tagId; + + @SerializedName("tagname") + private String tagName; + + public static WxCpTpTag deserialize(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpTpTag.class); + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpTagAddOrRemoveUsersResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpTagAddOrRemoveUsersResult.java new file mode 100644 index 0000000000..35319b1baf --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpTagAddOrRemoveUsersResult.java @@ -0,0 +1,16 @@ +package me.chanjar.weixin.cp.bean; + +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +/** + * 企业微信第三方开发-增加标签成员成员api响应体 + * @author zhangq + * @since 2021/2/14 16:44 + */ +public class WxCpTpTagAddOrRemoveUsersResult extends WxCpTagAddOrRemoveUsersResult { + private static final long serialVersionUID = 3490401800490702052L; + + public static WxCpTpTagAddOrRemoveUsersResult deserialize(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpTpTagAddOrRemoveUsersResult.class); + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpTagGetResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpTagGetResult.java new file mode 100644 index 0000000000..d77e99b131 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpTagGetResult.java @@ -0,0 +1,17 @@ +package me.chanjar.weixin.cp.bean; + +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +/** + * 获取标签成员接口响应体 + * @author zhangq + * @since 2021/2/14 16:28 + */ +public class WxCpTpTagGetResult extends WxCpTagGetResult { + private static final long serialVersionUID = 9051748686315562400L; + + public static WxCpTpTagGetResult deserialize(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpTpTagGetResult.class); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpService.java index 73a173b98a..8018e2eb21 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpService.java @@ -491,4 +491,32 @@ public interface WxCpTpService { */ WxJsapiSignature createSuiteJsApiTicketSignature(String url, String authCorpId) throws WxErrorException; + /** + * 使套件accessToken缓存失效 + */ + void expireSuiteAccessToken(); + + /** + * 使机构accessToken缓存失效 + * @param authCorpId 机构id + */ + void expireAccessToken(String authCorpId); + + /** + * 使机构jsapiticket缓存失效 + * @param authCorpId 机构id + */ + void expireAuthCorpJsApiTicket(String authCorpId); + + /** + * 使应用jsapiticket失效 + * @param authCorpId 机构id + */ + void expireAuthSuiteJsApiTicket(String authCorpId); + + /** + * 使供应商accessToken失效 + */ + void expireProviderToken(); + } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpTagService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpTagService.java new file mode 100644 index 0000000000..25c5cf88b3 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpTagService.java @@ -0,0 +1,90 @@ +package me.chanjar.weixin.cp.tp.service; + +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.cp.bean.WxCpTpTag; +import me.chanjar.weixin.cp.bean.WxCpTpTagAddOrRemoveUsersResult; +import me.chanjar.weixin.cp.bean.WxCpTpTagGetResult; + +import java.util.List; + +/** + *
+ *   企业微信第三方开发-标签相关接口
+ * 
+ * + * @author zhangq + * @since 2021-02-14 16:02 + */ +public interface WxCpTpTagService { + /** + * 创建标签. + *
+   * 请求地址:https://qyapi.weixin.qq.com/cgi-bin/tag/create?access_token=ACCESS_TOKEN
+   * 文档地址:https://work.weixin.qq.com/api/doc/90001/90143/90346
+   * 
+ * + * @param name 标签名称,长度限制为32个字以内(汉字或英文字母),标签名不可与其他标签重名。 + * @param id 标签id,非负整型,指定此参数时新增的标签会生成对应的标签id,不指定时则以目前最大的id自增。 + * @return 标签id + * @throws WxErrorException + */ + String create(String name, Integer id) throws WxErrorException; + + /** + * 更新标签. + * + * @param tagId 标签id + * @param tagName 标签名 + * @throws WxErrorException . + */ + void update(String tagId, String tagName) throws WxErrorException; + + /** + * 删除标签. + * + * @param tagId 标签id + * @throws WxErrorException . + */ + void delete(String tagId) throws WxErrorException; + + /** + * 获取标签成员 + * @param tagId + * @return + * @throws WxErrorException + */ + WxCpTpTagGetResult get(String tagId) throws WxErrorException; + + /** + * 增加标签成员. + * + * @param tagId 标签id + * @param userIds 用户ID 列表 + * @param partyIds 企业部门ID列表 + * @return . + * @throws WxErrorException . + */ + WxCpTpTagAddOrRemoveUsersResult addUsers2Tag(String tagId, List userIds, List partyIds) + throws WxErrorException; + + /** + * 移除标签成员. + * + * @param tagId 标签id + * @param userIds 用户id列表 + * @param partyIds 企业部门ID列表 + * @return . + * @throws WxErrorException . + */ + WxCpTpTagAddOrRemoveUsersResult removeUsersFromTag(String tagId, List userIds, List partyIds) + throws WxErrorException; + + /** + * 获得标签列表. + * + * @return 标签列表 + * @throws WxErrorException . + */ + List listAll() throws WxErrorException; + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImpl.java index c61f1a8c9f..c8409d21aa 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImpl.java @@ -548,6 +548,31 @@ public WxJsapiSignature createSuiteJsApiTicketSignature(String url, String authC return doCreateWxJsapiSignature(url, authCorpId, this.getSuiteJsApiTicket(authCorpId)); } + @Override + public void expireSuiteAccessToken() { + this.configStorage.expireSuiteAccessToken(); + } + + @Override + public void expireAccessToken(String authCorpId) { + this.configStorage.expireAccessToken(authCorpId); + } + + @Override + public void expireAuthCorpJsApiTicket(String authCorpId) { + this.configStorage.expireAuthCorpJsApiTicket(authCorpId); + } + + @Override + public void expireAuthSuiteJsApiTicket(String authCorpId) { + this.configStorage.expireAuthSuiteJsApiTicket(authCorpId); + } + + @Override + public void expireProviderToken() { + this.configStorage.expireProviderToken(); + } + private WxJsapiSignature doCreateWxJsapiSignature(String url, String authCorpId, String jsapiTicket) { long timestamp = System.currentTimeMillis() / 1000; String noncestr = RandomUtils.getRandomStr(); diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpTagServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpTagServiceImpl.java new file mode 100644 index 0000000000..1b03f18c79 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpTagServiceImpl.java @@ -0,0 +1,132 @@ +package me.chanjar.weixin.cp.tp.service.impl; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import com.google.gson.reflect.TypeToken; +import lombok.RequiredArgsConstructor; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.json.GsonParser; +import me.chanjar.weixin.cp.bean.WxCpTpTag; +import me.chanjar.weixin.cp.bean.WxCpTpTagAddOrRemoveUsersResult; +import me.chanjar.weixin.cp.bean.WxCpTpTagGetResult; +import me.chanjar.weixin.cp.config.WxCpTpConfigStorage; +import me.chanjar.weixin.cp.tp.service.WxCpTpService; +import me.chanjar.weixin.cp.tp.service.WxCpTpTagService; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.util.List; + +import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Tag.*; + +/** + *
+ *   企业微信第三方开发-标签相关接口,部分照搬了WxCpTagServiceImpl
+ * 
+ * + * @author zhangq + * @since 2021-02-14 16:02 + */ +@RequiredArgsConstructor +public class WxCpTpTagServiceImpl implements WxCpTpTagService { + private final WxCpTpService mainService; + + @Override + public String create(String name, Integer id) throws WxErrorException { + JsonObject o = new JsonObject(); + o.addProperty("tagname", name); + + if (id != null) { + o.addProperty("tagid", id); + } + return this.create(o); + } + + private String create(JsonObject param) throws WxErrorException { + String url = getWxCpTpConfigStorage().getApiUrl(TAG_CREATE); + String responseContent = this.mainService.post(url, param.toString()); + JsonObject jsonObject = GsonParser.parse(responseContent); + return jsonObject.get("tagid").getAsString(); + } + + @Override + public void update(String tagId, String tagName) throws WxErrorException { + String url = getWxCpTpConfigStorage().getApiUrl(TAG_UPDATE); + JsonObject o = new JsonObject(); + o.addProperty("tagid", tagId); + o.addProperty("tagname", tagName); + this.mainService.post(url, o.toString()); + } + + @Override + public void delete(String tagId) throws WxErrorException { + String url = String.format(getWxCpTpConfigStorage().getApiUrl(TAG_DELETE), tagId); + this.mainService.get(url, null); + } + + @Override + public List listAll() throws WxErrorException { + String url = getWxCpTpConfigStorage().getApiUrl(TAG_LIST); + String responseContent = this.mainService.get(url, null); + JsonObject tmpJson = GsonParser.parse(responseContent); + return WxCpGsonBuilder.create().fromJson(tmpJson.get("taglist"), new TypeToken>() { + // do nothing + }.getType()); + } + + @Override + public WxCpTpTagGetResult get(String tagId) throws WxErrorException { + if (tagId == null) { + throw new IllegalArgumentException("缺少tagId参数"); + } + + String url = String.format(getWxCpTpConfigStorage().getApiUrl(TAG_GET), tagId); + String responseContent = this.mainService.get(url, null); + return WxCpTpTagGetResult.deserialize(responseContent); + } + + @Override + public WxCpTpTagAddOrRemoveUsersResult addUsers2Tag(String tagId, List userIds, List partyIds) + throws WxErrorException { + String url = getWxCpTpConfigStorage().getApiUrl(TAG_ADD_TAG_USERS); + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("tagid", tagId); + this.addUserIdsAndPartyIdsToJson(userIds, partyIds, jsonObject); + + return WxCpTpTagAddOrRemoveUsersResult.deserialize(this.mainService.post(url, jsonObject.toString())); + } + + @Override + public WxCpTpTagAddOrRemoveUsersResult removeUsersFromTag(String tagId, List userIds, List partyIds) + throws WxErrorException { + String url = getWxCpTpConfigStorage().getApiUrl(TAG_DEL_TAG_USERS); + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("tagid", tagId); + this.addUserIdsAndPartyIdsToJson(userIds, partyIds, jsonObject); + + return WxCpTpTagAddOrRemoveUsersResult.deserialize(this.mainService.post(url, jsonObject.toString())); + } + + private void addUserIdsAndPartyIdsToJson(List userIds, List partyIds, JsonObject jsonObject) { + if (userIds != null) { + JsonArray jsonArray = new JsonArray(); + for (String userId : userIds) { + jsonArray.add(new JsonPrimitive(userId)); + } + jsonObject.add("userlist", jsonArray); + } + + if (partyIds != null) { + JsonArray jsonArray = new JsonArray(); + for (String userId : partyIds) { + jsonArray.add(new JsonPrimitive(userId)); + } + jsonObject.add("partylist", jsonArray); + } + } + + @SuppressWarnings("deprecation") + private WxCpTpConfigStorage getWxCpTpConfigStorage() { + return this.mainService.getWxCpTpConfigStorage(); + } +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpTagServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpTagServiceImplTest.java new file mode 100644 index 0000000000..44c3ff68d1 --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpTagServiceImplTest.java @@ -0,0 +1,147 @@ +package me.chanjar.weixin.cp.tp.service.impl; + +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.cp.bean.WxCpTpTag; +import me.chanjar.weixin.cp.bean.WxCpTpTagAddOrRemoveUsersResult; +import me.chanjar.weixin.cp.bean.WxCpTpTagGetResult; +import me.chanjar.weixin.cp.config.WxCpTpConfigStorage; +import me.chanjar.weixin.cp.config.impl.WxCpTpDefaultConfigImpl; +import me.chanjar.weixin.cp.tp.service.WxCpTpTagService; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import org.testng.collections.CollectionUtils; + +import java.util.Arrays; +import java.util.List; + +import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Tag.*; +import static org.mockito.Matchers.*; +import static org.mockito.Mockito.when; +import static org.testng.Assert.*; + +/** + * 企业微信-第三方开发-标签管理相关测试 + * + * @author zhangq + * @since 2021/2/15 9:14 + */ +public class WxCpTpTagServiceImplTest { + + @Mock + private WxCpTpServiceImpl wxCpTpService; + + private WxCpTpConfigStorage configStorage; + + private WxCpTpTagService wxCpTpTagService; + + @BeforeClass + public void setUp() { + MockitoAnnotations.initMocks(this); + configStorage = new WxCpTpDefaultConfigImpl(); + when(wxCpTpService.getWxCpTpConfigStorage()).thenReturn(configStorage); + wxCpTpTagService = new WxCpTpTagServiceImpl(wxCpTpService); + } + + @Test + public void testCreate() throws WxErrorException { + String url = configStorage.getApiUrl(TAG_CREATE); + String tagName = "test_tag_name"; + int tagId = 12; + String result = "{\"errcode\":0,\"errmsg\":\"created\",\"tagid\":12}"; + when(wxCpTpService.post(eq(url), any(String.class))).thenReturn(result); + + assertEquals(wxCpTpTagService.create(tagName, tagId), String.valueOf(tagId)); + } + + @Test + public void testListAll() throws WxErrorException { + String url = configStorage.getApiUrl(TAG_LIST); + String result = "{\"errcode\":0,\"errmsg\":\"ok\",\"taglist\":[{\"tagid\":1,\"tagname\":\"a\"},{\"tagid\":2,\"tagname\":\"b\"}]}"; + when(wxCpTpService.get(eq(url), anyString())).thenReturn(result); + + List wxCpTpTags = wxCpTpTagService.listAll(); + assertNotNull(wxCpTpTags); + assertTrue(CollectionUtils.hasElements(wxCpTpTags)); + assertEquals(wxCpTpTags.get(0).getTagId(), "1"); + assertEquals(wxCpTpTags.get(1).getTagName(), "b"); + } + + @Test + public void testGet() throws WxErrorException { + String tagId = "anyTagId"; + String url = String.format(configStorage.getApiUrl(TAG_GET), tagId); + String result = "{\"errcode\":0,\"errmsg\":\"ok\",\"tagname\":\"乒乓球协会\",\"userlist\":[{\"userid\":\"zhangsan\",\"name\":\"李四\"}],\"partylist\":[2]}"; + when(wxCpTpService.get(eq(url), anyString())).thenReturn(result); + + WxCpTpTagGetResult getResult = wxCpTpTagService.get(tagId); + assertEquals(getResult.getTagname(), "乒乓球协会"); + assertEquals((int) getResult.getPartylist().get(0), 2); + assertEquals(getResult.getUserlist().get(0).getUserId(), "zhangsan"); + } + + @Test + public void testAddUsers2Tag() throws WxErrorException { + String tagId = "anyTagId"; + String url = configStorage.getApiUrl(TAG_ADD_TAG_USERS); + // 成功时返回对象 + String success = "{\"errcode\":0,\"errmsg\":\"ok\"}"; + when(wxCpTpService.post(eq(url), anyString())).thenReturn(success); + WxCpTpTagAddOrRemoveUsersResult postResult = wxCpTpTagService + .addUsers2Tag(tagId, Arrays.asList("usr1", "usr2"), Arrays.asList("dept1", "dept2")); + assertEquals((int) postResult.getErrCode(), 0); + assertNull(postResult.getInvalidParty()); + assertNull(postResult.getInvalidUsers()); + + // 部分失败时返回对象 + String partFailure = "{\"errcode\":0,\"errmsg\":\"ok\",\"invalidlist\":\"usr1|usr2\",\"invalidparty\":[2,3,4]}"; + when(wxCpTpService.post(eq(url), anyString())).thenReturn(partFailure); + postResult = wxCpTpTagService.addUsers2Tag(tagId, Arrays.asList("usr1", "usr2"), Arrays.asList("dept1", "dept2")); + assertEquals((int) postResult.getErrCode(), 0); + assertEquals(postResult.getInvalidUserList().size(), 2); + assertEquals(postResult.getInvalidUserList().get(1), "usr2"); + assertEquals(postResult.getInvalidParty().length, 3); + assertEquals(postResult.getInvalidParty()[1], "3"); + + // 全部失败时返回对象 + String allFailure = "{\"errcode\":40070,\"errmsg\":\"all list invalid \"}"; + when(wxCpTpService.post(eq(url), anyString())).thenReturn(allFailure); + postResult = wxCpTpTagService.addUsers2Tag(tagId, Arrays.asList("usr1", "usr2"), Arrays.asList("dept1", "dept2")); + assertEquals((int) postResult.getErrCode(), 40070); + assertNull(postResult.getInvalidParty()); + assertNull(postResult.getInvalidUsers()); + } + + @Test + public void testRemoveUsersFromTag() throws WxErrorException { + String tagId = "anyTagId"; + String url = configStorage.getApiUrl(TAG_DEL_TAG_USERS); + // 成功时返回对象 + String success = "{\"errcode\":0,\"errmsg\":\"ok\"}"; + when(wxCpTpService.post(eq(url), anyString())).thenReturn(success); + WxCpTpTagAddOrRemoveUsersResult postResult = wxCpTpTagService + .removeUsersFromTag(tagId, Arrays.asList("usr1", "usr2"), Arrays.asList("dept1", "dept2")); + assertEquals((int) postResult.getErrCode(), 0); + assertNull(postResult.getInvalidParty()); + assertNull(postResult.getInvalidUsers()); + + // 部分失败时返回对象 + String partFailure = "{\"errcode\":0,\"errmsg\":\"ok\",\"invalidlist\":\"usr1|usr2\",\"invalidparty\":[2,3,4]}"; + when(wxCpTpService.post(eq(url), anyString())).thenReturn(partFailure); + postResult = wxCpTpTagService.removeUsersFromTag(tagId, Arrays.asList("usr1", "usr2"), Arrays.asList("dept1", "dept2")); + assertEquals((int) postResult.getErrCode(), 0); + assertEquals(postResult.getInvalidUserList().size(), 2); + assertEquals(postResult.getInvalidUserList().get(1), "usr2"); + assertEquals(postResult.getInvalidParty().length, 3); + assertEquals(postResult.getInvalidParty()[1], "3"); + + // 全部失败时返回对象 + String allFailure = "{\"errcode\":40070,\"errmsg\":\"all list invalid \"}"; + when(wxCpTpService.post(eq(url), anyString())).thenReturn(allFailure); + postResult = wxCpTpTagService.removeUsersFromTag(tagId, Arrays.asList("usr1", "usr2"), Arrays.asList("dept1", "dept2")); + assertEquals((int) postResult.getErrCode(), 40070); + assertNull(postResult.getInvalidParty()); + assertNull(postResult.getInvalidUsers()); + } +} diff --git a/weixin-java-cp/src/test/resources/testng.xml b/weixin-java-cp/src/test/resources/testng.xml index 942c73fdd8..0bd6fbdd23 100644 --- a/weixin-java-cp/src/test/resources/testng.xml +++ b/weixin-java-cp/src/test/resources/testng.xml @@ -8,6 +8,7 @@ +