mirror of
				https://gitee.com/binary/weixin-java-tools.git
				synced 2025-11-01 03:25:35 +08:00 
			
		
		
		
	🆕 #1947 【企业微信】第三方应用增加用户管理、OA、外部联系人、部门、通讯录搜索等相关接口的实现
* 修复getSuiteJsApiTicket和getAuthCorpJsApiTicket方法代码错误 * 增加企业微信第三方应用用户管理、oa、外部联系人、部门、通讯录搜索相关接口实现
This commit is contained in:
		| @ -0,0 +1,62 @@ | ||||
| package me.chanjar.weixin.cp.bean; | ||||
|  | ||||
| import com.google.gson.annotations.SerializedName; | ||||
| import lombok.Data; | ||||
| import lombok.experimental.Accessors; | ||||
| import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | ||||
|  | ||||
| /** | ||||
|  * @author uianz | ||||
|  * @description | ||||
|  * @since 2020/12/23 下午 02:43 | ||||
|  */ | ||||
| @Data | ||||
| @Accessors(chain = true) | ||||
| public class WxCpTpContactSearch { | ||||
|  | ||||
|     /** | ||||
|      * 查询的企业corpid | ||||
|      */ | ||||
|     @SerializedName("auth_corpid") | ||||
|     private String authCorpId; | ||||
|  | ||||
|     /** | ||||
|      * 搜索关键词。当查询用户时应为用户名称、名称拼音或者英文名;当查询部门时应为部门名称或者部门名称拼音 | ||||
|      */ | ||||
|     @SerializedName("query_word") | ||||
|     private String queryWord; | ||||
|  | ||||
|     /** | ||||
|      * 查询类型 1:查询用户,返回用户userid列表 2:查询部门,返回部门id列表。 不填该字段或者填0代表同时查询部门跟用户 | ||||
|      */ | ||||
|     @SerializedName("query_type") | ||||
|     private Integer type; | ||||
|  | ||||
|     /** | ||||
|      * 应用id,若非0则只返回应用可见范围内的用户或者部门信息 | ||||
|      */ | ||||
|     @SerializedName("agentid") | ||||
|     private Integer agentId; | ||||
|  | ||||
|     /** | ||||
|      * 查询的偏移量,每次调用的offset在上一次offset基础上加上limit | ||||
|      */ | ||||
|     @SerializedName("offset") | ||||
|     private Integer offset; | ||||
|  | ||||
|     /** | ||||
|      * 查询返回的最大数量,默认为50,最多为200,查询返回的数量可能小于limit指定的值 | ||||
|      */ | ||||
|     @SerializedName("limit") | ||||
|     private Integer limit; | ||||
|  | ||||
|     /** | ||||
|      * 如果需要精确匹配用户名称或者部门名称或者英文名,不填则默认为模糊匹配;1:匹配用户名称或者部门名称 2:匹配用户英文名 | ||||
|      */ | ||||
|     @SerializedName("full_match_field") | ||||
|     private Integer fullMatchField; | ||||
|  | ||||
|     public String toJson() { | ||||
|         return WxCpGsonBuilder.create().toJson(this); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,53 @@ | ||||
| package me.chanjar.weixin.cp.bean; | ||||
|  | ||||
| import com.google.gson.annotations.SerializedName; | ||||
| import lombok.Data; | ||||
| import lombok.EqualsAndHashCode; | ||||
| import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * @author uianz | ||||
|  * @description | ||||
|  * @since 2020/12/23 下午 02:55 | ||||
|  */ | ||||
| @EqualsAndHashCode(callSuper = true) | ||||
| @Data | ||||
| public class WxCpTpContactSearchResp extends WxCpBaseResp { | ||||
|  | ||||
|     @SerializedName("is_last") | ||||
|     private Boolean isLast; | ||||
|  | ||||
|     @SerializedName("query_result") | ||||
|     private QueryResult queryResult; | ||||
|  | ||||
|     @Data | ||||
|     public static class QueryResult { | ||||
|  | ||||
|         @SerializedName("user") | ||||
|         private User user; | ||||
|         @SerializedName("party") | ||||
|         private Party party; | ||||
|  | ||||
|         @Data | ||||
|         public static class User { | ||||
|             @SerializedName("userid") | ||||
|             private List<String> userid; | ||||
|             @SerializedName("open_userid") | ||||
|             private List<String> openUserId; | ||||
|         } | ||||
|  | ||||
|         @Data | ||||
|         public static class Party { | ||||
|             @SerializedName("department_id") | ||||
|             private List<Integer> departmentId; | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public static WxCpTpContactSearchResp fromJson(String json) { | ||||
|       return WxCpGsonBuilder.create().fromJson(json, WxCpTpContactSearchResp.class); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,31 @@ | ||||
| package me.chanjar.weixin.cp.bean; | ||||
|  | ||||
| import lombok.Data; | ||||
| import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | ||||
|  | ||||
| import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * 企业微信的部门. | ||||
|  * | ||||
|  * @author Daniel Qian | ||||
|  */ | ||||
| @Data | ||||
| public class WxCpTpDepart implements Serializable { | ||||
|   private static final long serialVersionUID = -5028321625140879571L; | ||||
|  | ||||
|   private Integer id; | ||||
|   private String name; | ||||
|   private String enName; | ||||
|   private Integer parentid; | ||||
|   private Integer order; | ||||
|  | ||||
|   public static WxCpTpDepart fromJson(String json) { | ||||
|     return WxCpGsonBuilder.create().fromJson(json, WxCpTpDepart.class); | ||||
|   } | ||||
|  | ||||
|   public String toJson() { | ||||
|     return WxCpGsonBuilder.create().toJson(this); | ||||
|   } | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,142 @@ | ||||
| package me.chanjar.weixin.cp.bean; | ||||
|  | ||||
| import com.google.gson.annotations.SerializedName; | ||||
| import lombok.*; | ||||
| import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * <pre> | ||||
|  * 外部联系人详情 | ||||
|  * Created by Binary Wang on 2018/9/16. | ||||
|  * 参考文档:https://work.weixin.qq.com/api/doc#13878 | ||||
|  * </pre> | ||||
|  * | ||||
|  * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
|  */ | ||||
| @Getter | ||||
| @Setter | ||||
| public class WxCpUserExternalContactInfo { | ||||
|   @SerializedName("external_contact") | ||||
|   private ExternalContact externalContact; | ||||
|  | ||||
|   @SerializedName("follow_user") | ||||
|   private List<FollowedUser> followedUsers; | ||||
|  | ||||
|   @Getter | ||||
|   @Setter | ||||
|   public static class ExternalContact { | ||||
|     @SerializedName("external_userid") | ||||
|     private String externalUserId; | ||||
|  | ||||
|     @SerializedName("position") | ||||
|     private String position; | ||||
|  | ||||
|     @SerializedName("name") | ||||
|     private String name; | ||||
|  | ||||
|     @SerializedName("avatar") | ||||
|     private String avatar; | ||||
|  | ||||
|     @SerializedName("corp_name") | ||||
|     private String corpName; | ||||
|  | ||||
|     @SerializedName("corp_full_name") | ||||
|     private String corpFullName; | ||||
|  | ||||
|     @SerializedName("type") | ||||
|     private Integer type; | ||||
|  | ||||
|     @SerializedName("gender") | ||||
|     private Integer gender; | ||||
|  | ||||
|     @SerializedName("unionid") | ||||
|     private String unionId; | ||||
|  | ||||
|     @SerializedName("external_profile") | ||||
|     private ExternalProfile externalProfile; | ||||
|   } | ||||
|  | ||||
|   @Setter | ||||
|   @Getter | ||||
|   public static class ExternalProfile { | ||||
|     @SerializedName("external_attr") | ||||
|     private List<ExternalAttribute> externalAttrs; | ||||
|   } | ||||
|  | ||||
|   @Data | ||||
|   @Builder | ||||
|   @NoArgsConstructor | ||||
|   @AllArgsConstructor | ||||
|   public static class ExternalAttribute { | ||||
|     @Setter | ||||
|     @Getter | ||||
|     public static class Text { | ||||
|       private String value; | ||||
|     } | ||||
|  | ||||
|     @Setter | ||||
|     @Getter | ||||
|     public static class Web { | ||||
|       private String title; | ||||
|       private String url; | ||||
|     } | ||||
|  | ||||
|     @Setter | ||||
|     @Getter | ||||
|     public static class MiniProgram { | ||||
|       @SerializedName("pagepath") | ||||
|       private String pagePath; | ||||
|       private String appid; | ||||
|       private String title; | ||||
|     } | ||||
|  | ||||
|     private int type; | ||||
|  | ||||
|     private String name; | ||||
|  | ||||
|     private Text text; | ||||
|  | ||||
|     private Web web; | ||||
|  | ||||
|     @SerializedName("miniprogram") | ||||
|     private MiniProgram miniProgram; | ||||
|   } | ||||
|  | ||||
|   @Setter | ||||
|   @Getter | ||||
|   public static class FollowedUser { | ||||
|     @SerializedName("userid") | ||||
|     private String userId; | ||||
|     private String remark; | ||||
|     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; | ||||
|     @SerializedName("add_way") | ||||
|     private Integer addWay; | ||||
|     @SerializedName("oper_userid") | ||||
|     private String operUserid; | ||||
|  | ||||
|   } | ||||
|  | ||||
|   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; | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,65 @@ | ||||
| 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.util.List; | ||||
|  | ||||
| /** | ||||
|  * @description: 登录信息 | ||||
|  * @author: Jamie.shi | ||||
|  * @create: 2020-08-03 17:18 | ||||
|  **/ | ||||
| @Data | ||||
| public class WxTpLoginInfo extends WxCpBaseResp { | ||||
|   @SerializedName("usertype") | ||||
|   private Integer userType; | ||||
|   @SerializedName("user_info") | ||||
|   private UserInfo userInfo; | ||||
|   @SerializedName("corp_info") | ||||
|   private CorpInfoBean corpInfo; | ||||
|   @SerializedName("auth_info") | ||||
|   private AuthInfo authInfo; | ||||
|   private List<Agent> agent; | ||||
|  | ||||
|   @Data | ||||
|   public static class UserInfo { | ||||
|     @SerializedName("userid") | ||||
|     private String userId; | ||||
|     @SerializedName("open_userid") | ||||
|     private String openUserId; | ||||
|     private String name; | ||||
|     private String avatar; | ||||
|   } | ||||
|  | ||||
|   @Data | ||||
|   public static class CorpInfoBean { | ||||
|     @SerializedName("corpid") | ||||
|     private String corpId; | ||||
|   } | ||||
|  | ||||
|   @Data | ||||
|   public static class AuthInfo { | ||||
|     private List<Department> department; | ||||
|  | ||||
|     @Data | ||||
|     public static class Department { | ||||
|  | ||||
|       private int id; | ||||
|       private boolean writable; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   @Data | ||||
|   public static class Agent { | ||||
|     @SerializedName("agentid") | ||||
|     private int agentId; | ||||
|     @SerializedName("auth_type") | ||||
|     private int authType; | ||||
|   } | ||||
|  | ||||
|   public static WxTpLoginInfo fromJson(String json) { | ||||
|     return WxCpGsonBuilder.create().fromJson(json, WxTpLoginInfo.class); | ||||
|   } | ||||
| } | ||||
| @ -62,6 +62,11 @@ public interface WxCpTpConfigStorage { | ||||
|   String getCorpId(); | ||||
|   String getCorpSecret(); | ||||
|  | ||||
|   /** | ||||
|    * 服务商secret | ||||
|    */ | ||||
|   String getProviderSecret(); | ||||
|  | ||||
|   /** | ||||
|    * 授权企业的access token相关 | ||||
|    */ | ||||
| @ -83,6 +88,11 @@ public interface WxCpTpConfigStorage { | ||||
|   boolean isAuthSuiteJsApiTicketExpired(String authCorpId); | ||||
|   void updateAuthSuiteJsApiTicket(String authCorpId, String jsApiTicket, int expiredInSeconds);; | ||||
|  | ||||
|   boolean isProviderTokenExpired(); | ||||
|   void updateProviderToken(String providerToken, int expiredInSeconds); | ||||
|  | ||||
|   String getProviderToken(); | ||||
|  | ||||
|   /** | ||||
|    * 网络代理相关 | ||||
|    */ | ||||
|  | ||||
| @ -20,13 +20,19 @@ public class WxCpTpDefaultConfigImpl implements WxCpTpConfigStorage, Serializabl | ||||
|  | ||||
|   private volatile String corpId; | ||||
|   private volatile String corpSecret; | ||||
|   /** | ||||
|    * 服务商secret | ||||
|    */ | ||||
|   private volatile String providerSecret; | ||||
|   private volatile String providerToken; | ||||
|   private volatile long providerTokenExpiresTime; | ||||
|  | ||||
|   private volatile String suiteId; | ||||
|   private volatile String suiteSecret; | ||||
|  | ||||
|   private volatile String token; | ||||
|   private volatile String suiteAccessToken; | ||||
|   private volatile long   suiteAccessTokenExpiresTime; | ||||
|   private volatile long suiteAccessTokenExpiresTime; | ||||
|   private volatile String aesKey; | ||||
|  | ||||
|   private volatile String suiteTicket; | ||||
| @ -88,7 +94,7 @@ public class WxCpTpDefaultConfigImpl implements WxCpTpConfigStorage, Serializabl | ||||
|  | ||||
|   @Override | ||||
|   public synchronized void updateSuiteAccessToken(WxAccessToken suiteAccessToken) { | ||||
| 	  updateSuiteAccessToken(suiteAccessToken.getAccessToken(), suiteAccessToken.getExpiresIn()); | ||||
|     updateSuiteAccessToken(suiteAccessToken.getAccessToken(), suiteAccessToken.getExpiresIn()); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
| @ -196,6 +202,11 @@ public class WxCpTpDefaultConfigImpl implements WxCpTpConfigStorage, Serializabl | ||||
|     return this.corpSecret; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public String getProviderSecret() { | ||||
|     return providerSecret; | ||||
|   } | ||||
|  | ||||
|   @Deprecated | ||||
|   public void setCorpSecret(String corpSecret) { | ||||
|     this.corpSecret = corpSecret; | ||||
| @ -230,8 +241,7 @@ public class WxCpTpDefaultConfigImpl implements WxCpTpConfigStorage, Serializabl | ||||
|     Long t = this.authCorpJsApiTicketExpireTimeMap.get(authCorpId); | ||||
|     if (t == null) { | ||||
|       return System.currentTimeMillis() > t; | ||||
|     } | ||||
|     else { | ||||
|     } else { | ||||
|       return true; | ||||
|     } | ||||
|   } | ||||
| @ -254,8 +264,7 @@ public class WxCpTpDefaultConfigImpl implements WxCpTpConfigStorage, Serializabl | ||||
|     Long t = authSuiteJsApiTicketExpireTimeMap.get(authCorpId); | ||||
|     if (t == null) { | ||||
|       return System.currentTimeMillis() > t; | ||||
|     } | ||||
|     else { | ||||
|     } else { | ||||
|       return true; | ||||
|     } | ||||
|   } | ||||
| @ -268,6 +277,22 @@ public class WxCpTpDefaultConfigImpl implements WxCpTpConfigStorage, Serializabl | ||||
|     authSuiteJsApiTicketExpireTimeMap.put(authCorpId, System.currentTimeMillis() + (expiredInSeconds - 200) * 1000L); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public boolean isProviderTokenExpired() { | ||||
|     return System.currentTimeMillis() > providerTokenExpiresTime; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void updateProviderToken(String providerToken, int expiredInSeconds) { | ||||
|     this.providerToken = providerToken; | ||||
|     this.providerTokenExpiresTime = System.currentTimeMillis() + expiredInSeconds * 1000L; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public String getProviderToken() { | ||||
|     return providerToken; | ||||
|   } | ||||
|  | ||||
|   public void setOauth2redirectUri(String oauth2redirectUri) { | ||||
|     this.oauth2redirectUri = oauth2redirectUri; | ||||
|   } | ||||
|  | ||||
| @ -35,6 +35,8 @@ public class WxCpTpRedissonConfigImpl implements WxCpTpConfigStorage, Serializab | ||||
|  | ||||
|   private final String authSuiteJsApiTicketKey = ":authSuiteJsApiTicketKey:"; | ||||
|  | ||||
|   private final String providerTokenKey = ":providerTokenKey:"; | ||||
|  | ||||
|   private volatile String baseApiUrl; | ||||
|   private volatile String httpProxyHost; | ||||
|   private volatile int httpProxyPort; | ||||
| @ -59,6 +61,11 @@ public class WxCpTpRedissonConfigImpl implements WxCpTpConfigStorage, Serializab | ||||
|   private volatile String corpId; | ||||
|   private volatile String corpSecret; | ||||
|  | ||||
|   /** | ||||
|    * 服务商secret | ||||
|    */ | ||||
|   private volatile String providerSecret; | ||||
|  | ||||
|   @Override | ||||
|   public void setBaseApiUrl(String baseUrl) { | ||||
|     this.baseApiUrl = baseUrl; | ||||
| @ -69,7 +76,8 @@ public class WxCpTpRedissonConfigImpl implements WxCpTpConfigStorage, Serializab | ||||
|     if (baseApiUrl == null) { | ||||
|       baseApiUrl = "https://qyapi.weixin.qq.com"; | ||||
|     } | ||||
|     return baseApiUrl + path;  } | ||||
|     return baseApiUrl + path; | ||||
|   } | ||||
|  | ||||
|  | ||||
|   /** | ||||
| @ -164,6 +172,10 @@ public class WxCpTpRedissonConfigImpl implements WxCpTpConfigStorage, Serializab | ||||
|     return corpSecret; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public String getProviderSecret() { | ||||
|     return providerSecret; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 授权企业的access token相关 | ||||
| @ -203,7 +215,8 @@ public class WxCpTpRedissonConfigImpl implements WxCpTpConfigStorage, Serializab | ||||
|  | ||||
|   @Override | ||||
|   public void updateAuthCorpJsApiTicket(String authCorpId, String jsApiTicket, int expiredInSeconds) { | ||||
|     wxRedisOps.setValue(keyWithPrefix(authCorpId) + authCorpJsApiTicketKey, jsApiTicket, expiredInSeconds, TimeUnit.SECONDS); | ||||
|     wxRedisOps.setValue(keyWithPrefix(authCorpId) + authCorpJsApiTicketKey, jsApiTicket, expiredInSeconds, | ||||
|       TimeUnit.SECONDS); | ||||
|   } | ||||
|  | ||||
|  | ||||
| @ -224,7 +237,24 @@ public class WxCpTpRedissonConfigImpl implements WxCpTpConfigStorage, Serializab | ||||
|  | ||||
|   @Override | ||||
|   public void updateAuthSuiteJsApiTicket(String authCorpId, String jsApiTicket, int expiredInSeconds) { | ||||
|     wxRedisOps.setValue(keyWithPrefix(authCorpId) + authSuiteJsApiTicketKey, jsApiTicket, expiredInSeconds, TimeUnit.SECONDS); | ||||
|     wxRedisOps.setValue(keyWithPrefix(authCorpId) + authSuiteJsApiTicketKey, jsApiTicket, expiredInSeconds, | ||||
|       TimeUnit.SECONDS); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public boolean isProviderTokenExpired() { | ||||
|     //remain time to live in seconds, or key not exist | ||||
|     return wxRedisOps.getExpire(keyWithPrefix(providerTokenKey)) == 0L || wxRedisOps.getExpire(keyWithPrefix(providerTokenKey)) == -2; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void updateProviderToken(String providerToken, int expiredInSeconds) { | ||||
|     wxRedisOps.setValue(keyWithPrefix(providerTokenKey), providerToken, expiredInSeconds, TimeUnit.SECONDS); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public String getProviderToken() { | ||||
|     return wxRedisOps.getValue(keyWithPrefix(providerTokenKey)); | ||||
|   } | ||||
|  | ||||
|  | ||||
|  | ||||
| @ -119,6 +119,8 @@ public final class WxCpApiPathConsts { | ||||
|     public static final String SCHEDULE_GET = "/cgi-bin/oa/schedule/get"; | ||||
|     public static final String SCHEDULE_DEL = "/cgi-bin/oa/schedule/del"; | ||||
|     public static final String SCHEDULE_LIST = "/cgi-bin/oa/schedule/get_by_calendar"; | ||||
|  | ||||
|     public static final String COPY_TEMPLATE = "/cgi-bin/oa/approval/copytemplate"; | ||||
|   } | ||||
|  | ||||
|   @UtilityClass | ||||
| @ -150,6 +152,10 @@ public final class WxCpApiPathConsts { | ||||
|     public static final String GET_SUITE_JSAPI_TICKET = "/cgi-bin/ticket/get"; | ||||
|     public static final String GET_USERINFO3RD = "/cgi-bin/service/getuserinfo3rd"; | ||||
|     public static final String GET_USERDETAIL3RD = "/cgi-bin/service/getuserdetail3rd"; | ||||
|     public static final String GET_LOGIN_INFO = "/cgi-bin/service/get_login_info"; | ||||
|  | ||||
|  | ||||
|     public static final String CONTACT_SEARCH = "/cgi-bin/service/contact/search"; | ||||
|   } | ||||
|  | ||||
|   @UtilityClass | ||||
|  | ||||
| @ -0,0 +1,22 @@ | ||||
| package me.chanjar.weixin.cp.tp.service; | ||||
|  | ||||
| import me.chanjar.weixin.common.error.WxErrorException; | ||||
| import me.chanjar.weixin.cp.bean.WxCpTpContactSearch; | ||||
| import me.chanjar.weixin.cp.bean.WxCpTpContactSearchResp; | ||||
|  | ||||
| /** | ||||
|  * @author uianz | ||||
|  * @description | ||||
|  * @since 2020/12/23 下午 02:39 | ||||
|  */ | ||||
| public interface WxCpTpContactService { | ||||
|  | ||||
|     /** | ||||
|      * https://work.weixin.qq.com/api/doc/90001/90143/91844 | ||||
|      * 通讯录单个搜索 | ||||
|      * @param wxCpTpContactSearch | ||||
|      * @return | ||||
|      * @throws WxErrorException | ||||
|      */ | ||||
|     WxCpTpContactSearchResp contactSearch(WxCpTpContactSearch wxCpTpContactSearch) throws WxErrorException; | ||||
| } | ||||
| @ -0,0 +1,75 @@ | ||||
| package me.chanjar.weixin.cp.tp.service; | ||||
|  | ||||
| import me.chanjar.weixin.common.error.WxErrorException; | ||||
| import me.chanjar.weixin.cp.bean.WxCpTpDepart; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * <pre> | ||||
|  *  部门管理接口 | ||||
|  *  Created by jamie on 2020/7/22. | ||||
|  * </pre> | ||||
|  */ | ||||
| public interface WxCpTpDepartmentService { | ||||
|  | ||||
|     /** | ||||
|      * <pre> | ||||
|      * 部门管理接口 - 创建部门. | ||||
|      * 最多支持创建500个部门 | ||||
|      * 详情请见: https://work.weixin.qq.com/api/doc#90000/90135/90205 | ||||
|      * </pre> | ||||
|      * | ||||
|      * @param depart 部门 | ||||
|      * @return 部门id | ||||
|      * @throws WxErrorException 异常 | ||||
|      */ | ||||
|     Long create(WxCpTpDepart depart) throws WxErrorException; | ||||
|  | ||||
|     /** | ||||
|      * <pre> | ||||
|      * 部门管理接口 - 获取部门列表. | ||||
|      * 详情请见: https://work.weixin.qq.com/api/doc#90000/90135/90208 | ||||
|      * </pre> | ||||
|      * | ||||
|      * @param id 部门id。获取指定部门及其下的子部门。非必需,可为null | ||||
|      * @return 获取的部门列表 | ||||
|      * @throws WxErrorException 异常 | ||||
|      */ | ||||
|     List<WxCpTpDepart> list(Long id, String corpId) throws WxErrorException; | ||||
|  | ||||
|     /** | ||||
|      * <pre> | ||||
|      * 部门管理接口 - 更新部门. | ||||
|      * 详情请见: https://work.weixin.qq.com/api/doc#90000/90135/90206 | ||||
|      * 如果id为0(未部门),1(黑名单),2(星标组),或者不存在的id,微信会返回系统繁忙的错误 | ||||
|      * </pre> | ||||
|      * | ||||
|      * @param group 要更新的group,group的id,name必须设置 | ||||
|      * @throws WxErrorException 异常 | ||||
|      */ | ||||
|     void update(WxCpTpDepart group) throws WxErrorException; | ||||
|  | ||||
|     /** | ||||
|      * <pre> | ||||
|      * 部门管理接口 - 删除部门. | ||||
|      * 详情请见: https://work.weixin.qq.com/api/doc#90000/90135/90207 | ||||
|      * 应用须拥有指定部门的管理权限 | ||||
|      * </pre> | ||||
|      * | ||||
|      * @param departId 部门id | ||||
|      * @throws WxErrorException 异常 | ||||
|      */ | ||||
|     void delete(Long departId) throws WxErrorException; | ||||
|  | ||||
|     /** | ||||
|      * <pre> | ||||
|      * 部门管理接口 - 获取部门列表. | ||||
|      * 详情请见: https://work.weixin.qq.com/api/doc#90000/90135/90208 | ||||
|      * </pre> | ||||
|      * | ||||
|      * @return 获取所有的部门列表 | ||||
|      * @throws WxErrorException 异常 | ||||
|      */ | ||||
|     List<WxCpTpDepart> list(String corpId) throws WxErrorException; | ||||
| } | ||||
| @ -0,0 +1,60 @@ | ||||
| package me.chanjar.weixin.cp.tp.service; | ||||
|  | ||||
| import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | ||||
| import me.chanjar.weixin.common.error.WxErrorException; | ||||
|  | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
|  | ||||
| /** | ||||
|  * <pre> | ||||
|  *  媒体管理接口. | ||||
|  *  Created by BinaryWang on 2017/6/24. | ||||
|  * </pre> | ||||
|  * | ||||
|  * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
|  */ | ||||
| public interface WxCpTpMediaService { | ||||
|  | ||||
|     /** | ||||
|      * <pre> | ||||
|      * 上传多媒体文件. | ||||
|      * 上传的多媒体文件有格式和大小限制,如下: | ||||
|      *   图片(image): 1M,支持JPG格式 | ||||
|      *   语音(voice):2M,播放长度不超过60s,支持AMR\MP3格式 | ||||
|      *   视频(video):10MB,支持MP4格式 | ||||
|      *   缩略图(thumb):64KB,支持JPG格式 | ||||
|      * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=上传下载多媒体文件 | ||||
|      * </pre> | ||||
|      * | ||||
|      * @param mediaType   媒体类型, 请看{@link me.chanjar.weixin.common.api.WxConsts} | ||||
|      * @param fileType    文件类型,请看{@link me.chanjar.weixin.common.api.WxConsts} | ||||
|      * @param inputStream 输入流,需要调用方控制关闭该输入流 | ||||
|      */ | ||||
|     WxMediaUploadResult upload(String mediaType, String fileType, InputStream inputStream, String corpId) | ||||
|             throws WxErrorException, IOException; | ||||
|  | ||||
|     /** | ||||
|      * 上传多媒体文件. | ||||
|      * | ||||
|      * @param mediaType 媒体类型 | ||||
|      * @param file      文件对象 | ||||
|      * @see #upload(String, String, InputStream, String) | ||||
|      */ | ||||
|     WxMediaUploadResult upload(String mediaType, File file, String corpId) throws WxErrorException; | ||||
|  | ||||
|     /** | ||||
|      * <pre> | ||||
|      * 上传图片. | ||||
|      * 上传图片得到图片URL,该URL永久有效 | ||||
|      * 返回的图片URL,仅能用于图文消息(mpnews)正文中的图片展示;若用于非企业微信域名下的页面,图片将被屏蔽。 | ||||
|      * 每个企业每天最多可上传100张图片 | ||||
|      * 接口url格式:https://qyapi.weixin.qq.com/cgi-bin/media/uploadimg?access_token=ACCESS_TOKEN | ||||
|      * </pre> | ||||
|      * | ||||
|      * @param file 上传的文件对象 | ||||
|      * @return 返回图片url | ||||
|      */ | ||||
|     String uploadImg(File file, String corpId) throws WxErrorException; | ||||
| } | ||||
| @ -0,0 +1,60 @@ | ||||
| package me.chanjar.weixin.cp.tp.service; | ||||
|  | ||||
| import lombok.NonNull; | ||||
| import me.chanjar.weixin.common.error.WxErrorException; | ||||
| import me.chanjar.weixin.cp.bean.oa.WxCpApprovalDetailResult; | ||||
| import me.chanjar.weixin.cp.bean.oa.WxCpOaApplyEventRequest; | ||||
| import me.chanjar.weixin.cp.bean.oa.WxCpTemplateResult; | ||||
|  | ||||
| /** | ||||
|  * 企业微信OA相关接口. | ||||
|  * | ||||
|  * @author Element | ||||
|  * @date 2019-04-06 10:52 | ||||
|  */ | ||||
| public interface WxCpTpOAService { | ||||
|  | ||||
|     /** | ||||
|      * <pre>提交审批申请 | ||||
|      * 调试工具 | ||||
|      * 企业可通过审批应用或自建应用Secret调用本接口,代应用可见范围内员工在企业微信“审批应用”内提交指定类型的审批申请。 | ||||
|      * | ||||
|      * 请求方式:POST(HTTPS) | ||||
|      * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/oa/applyevent?access_token=ACCESS_TOKEN | ||||
|      * 文档地址:https://work.weixin.qq.com/api/doc/90000/90135/91853 | ||||
|      * </pre> | ||||
|      * | ||||
|      * @param request 请求 | ||||
|      * @return 表单提交成功后,返回的表单编号 | ||||
|      * @throws WxErrorException . | ||||
|      */ | ||||
|     String apply(WxCpOaApplyEventRequest request, String corpId) throws WxErrorException; | ||||
|  | ||||
|     /** | ||||
|      * 获取审批模板详情 | ||||
|      * | ||||
|      * @param templateId 模板ID | ||||
|      * @return . | ||||
|      * @throws WxErrorException . | ||||
|      */ | ||||
|     WxCpTemplateResult getTemplateDetail(@NonNull String templateId, String corpId) throws WxErrorException; | ||||
|  | ||||
|     /** | ||||
|      * 复制/更新模板到企业 | ||||
|      * | ||||
|      * @param openTemplateId 模板ID | ||||
|      * @return . | ||||
|      * @throws WxErrorException . | ||||
|      */ | ||||
|     String copyTemplate(@NonNull String openTemplateId, String corpId) throws WxErrorException; | ||||
|  | ||||
|     /** | ||||
|      * <pre> | ||||
|      *   获取审批申请详情 | ||||
|      * | ||||
|      * @param spNo 审批单编号。 | ||||
|      * @return WxCpApprovaldetail | ||||
|      * @throws WxErrorException . | ||||
|      */ | ||||
|     WxCpApprovalDetailResult getApprovalDetail(@NonNull String spNo, String corpId) throws WxErrorException; | ||||
| } | ||||
| @ -312,4 +312,79 @@ public interface WxCpTpService { | ||||
|    * @return | ||||
|    */ | ||||
|   WxCpTpUserDetail getUserDetail3rd(String userTicket) throws WxErrorException; | ||||
|  | ||||
|   /** | ||||
|    * 企业用户登录信息 | ||||
|    * @param authCode | ||||
|    * @return | ||||
|    * @throws WxErrorException | ||||
|    */ | ||||
|   WxTpLoginInfo getLoginInfo(String authCode) throws WxErrorException; | ||||
|  | ||||
|   /** | ||||
|    * 获取服务商providerToken | ||||
|    * @return | ||||
|    * @throws WxErrorException | ||||
|    */ | ||||
|   String getWxCpProviderToken() throws WxErrorException; | ||||
|  | ||||
|   /** | ||||
|    * get contact service | ||||
|    * @return WxCpTpContactService | ||||
|    */ | ||||
|   WxCpTpContactService getWxCpTpContactService(); | ||||
|  | ||||
|   /** | ||||
|    * get department service | ||||
|    * @return WxCpTpDepartmentService | ||||
|    */ | ||||
|   WxCpTpDepartmentService getWxCpTpDepartmentService(); | ||||
|  | ||||
|   /** | ||||
|    * get media service | ||||
|    * @return WxCpTpMediaService | ||||
|    */ | ||||
|   WxCpTpMediaService getWxCpTpMediaService(); | ||||
|  | ||||
|   /** | ||||
|    * get oa service | ||||
|    * @return WxCpTpOAService | ||||
|    */ | ||||
|   WxCpTpOAService getWxCpTpOAService(); | ||||
|  | ||||
|   /** | ||||
|    * get user service | ||||
|    * @return WxCpTpUserService | ||||
|    */ | ||||
|   WxCpTpUserService getWxCpTpUserService(); | ||||
|  | ||||
|   /** | ||||
|    * set contact service | ||||
|    * @param wxCpTpContactService the contact service | ||||
|    */ | ||||
|   void setWxCpTpContactService(WxCpTpContactService wxCpTpContactService); | ||||
|  | ||||
|   /** | ||||
|    * set department service | ||||
|    * @param wxCpTpDepartmentService the department service | ||||
|    */ | ||||
|   void setWxCpTpDepartmentService(WxCpTpDepartmentService wxCpTpDepartmentService); | ||||
|  | ||||
|   /** | ||||
|    * set media service | ||||
|    * @param wxCpTpMediaService the media service | ||||
|    */ | ||||
|   void setWxCpTpMediaService(WxCpTpMediaService wxCpTpMediaService); | ||||
|  | ||||
|   /** | ||||
|    * set oa service | ||||
|    * @param wxCpTpOAService the oa service | ||||
|    */ | ||||
|   void setWxCpTpOAService(WxCpTpOAService wxCpTpOAService); | ||||
|  | ||||
|   /** | ||||
|    * set user service | ||||
|    * @param wxCpTpUserService the set user service | ||||
|    */ | ||||
|   void setWxCpTpUserService(WxCpTpUserService wxCpTpUserService); | ||||
| } | ||||
|  | ||||
| @ -0,0 +1,172 @@ | ||||
| package me.chanjar.weixin.cp.tp.service; | ||||
|  | ||||
| import me.chanjar.weixin.common.error.WxErrorException; | ||||
| import me.chanjar.weixin.cp.bean.WxCpInviteResult; | ||||
| import me.chanjar.weixin.cp.bean.WxCpUser; | ||||
| import me.chanjar.weixin.cp.bean.WxCpUserExternalContactInfo; | ||||
|  | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
|  | ||||
| /** | ||||
|  * <pre> | ||||
|  * 用户管理接口 | ||||
|  *  Created by jamie on 2020/7/22. | ||||
|  * </pre> | ||||
|  * | ||||
|  */ | ||||
| public interface WxCpTpUserService { | ||||
|  | ||||
|   /** | ||||
|    * <pre> | ||||
|    *   用在二次验证的时候. | ||||
|    *   企业在员工验证成功后,调用本方法告诉企业号平台该员工关注成功。 | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param userId 用户id | ||||
|    */ | ||||
|   void authenticate(String userId) throws WxErrorException; | ||||
|  | ||||
|   /** | ||||
|    * <pre> | ||||
|    * 获取部门成员(详情). | ||||
|    * | ||||
|    * http://qydev.weixin.qq.com/wiki/index.php?title=管理成员#.E8.8E.B7.E5.8F.96.E9.83.A8.E9.97.A8.E6.88.90.E5.91.98.28.E8.AF.A6.E6.83.85.29 | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param departId   必填。部门id | ||||
|    * @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 | ||||
|    * @param status     非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 | ||||
|    */ | ||||
|   List<WxCpUser> listByDepartment(Long departId, Boolean fetchChild, Integer status,String corpId) throws WxErrorException; | ||||
|  | ||||
|   /** | ||||
|    * <pre> | ||||
|    * 获取部门成员. | ||||
|    * | ||||
|    * http://qydev.weixin.qq.com/wiki/index.php?title=管理成员#.E8.8E.B7.E5.8F.96.E9.83.A8.E9.97.A8.E6.88.90.E5.91.98 | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param departId   必填。部门id | ||||
|    * @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 | ||||
|    * @param status     非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 | ||||
|    */ | ||||
|   List<WxCpUser> listSimpleByDepartment(Long departId, Boolean fetchChild, Integer status) throws WxErrorException; | ||||
|  | ||||
|   /** | ||||
|    * 新建用户. | ||||
|    * | ||||
|    * @param user 用户对象 | ||||
|    */ | ||||
|   void create(WxCpUser user) throws WxErrorException; | ||||
|  | ||||
|   /** | ||||
|    * 更新用户. | ||||
|    * | ||||
|    * @param user 用户对象 | ||||
|    */ | ||||
|   void update(WxCpUser user) throws WxErrorException; | ||||
|  | ||||
|   /** | ||||
|    * <pre> | ||||
|    * 删除用户/批量删除成员. | ||||
|    * http://qydev.weixin.qq.com/wiki/index.php?title=管理成员#.E6.89.B9.E9.87.8F.E5.88.A0.E9.99.A4.E6.88.90.E5.91.98 | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param userIds 员工UserID列表。对应管理端的帐号 | ||||
|    */ | ||||
|   void delete(String... userIds) throws WxErrorException; | ||||
|  | ||||
|   /** | ||||
|    * 获取用户. | ||||
|    * | ||||
|    * @param userid 用户id | ||||
|    */ | ||||
|   WxCpUser getById(String userid,String corpId) throws WxErrorException; | ||||
|  | ||||
|   /** | ||||
|    * <pre> | ||||
|    * 邀请成员. | ||||
|    * 企业可通过接口批量邀请成员使用企业微信,邀请后将通过短信或邮件下发通知。 | ||||
|    * 请求方式:POST(HTTPS) | ||||
|    * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/batch/invite?access_token=ACCESS_TOKEN | ||||
|    * 文档地址:https://work.weixin.qq.com/api/doc#12543 | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param userIds  成员ID列表, 最多支持1000个。 | ||||
|    * @param partyIds 部门ID列表,最多支持100个。 | ||||
|    * @param tagIds   标签ID列表,最多支持100个。 | ||||
|    */ | ||||
|   WxCpInviteResult invite(List<String> userIds, List<String> partyIds, List<String> tagIds) throws WxErrorException; | ||||
|  | ||||
|   /** | ||||
|    * <pre> | ||||
|    *  userid转openid. | ||||
|    *  该接口使用场景为微信支付、微信红包和企业转账。 | ||||
|    * | ||||
|    * 在使用微信支付的功能时,需要自行将企业微信的userid转成openid。 | ||||
|    * 在使用微信红包功能时,需要将应用id和userid转成appid和openid才能使用。 | ||||
|    * 注:需要成员使用微信登录企业微信或者关注微信插件才能转成openid | ||||
|    * | ||||
|    * 文档地址:https://work.weixin.qq.com/api/doc#11279 | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param userId  企业内的成员id | ||||
|    * @param agentId 非必填,整型,仅用于发红包。其它场景该参数不要填,如微信支付、企业转账、电子发票 | ||||
|    * @return map对象,可能包含以下值: | ||||
|    * - openid 企业微信成员userid对应的openid,若有传参agentid,则是针对该agentid的openid。否则是针对企业微信corpid的openid | ||||
|    * - appid 应用的appid,若请求包中不包含agentid则不返回appid。该appid在使用微信红包时会用到 | ||||
|    */ | ||||
|   Map<String, String> userId2Openid(String userId, Integer agentId) throws WxErrorException; | ||||
|  | ||||
|   /** | ||||
|    * <pre> | ||||
|    * openid转userid. | ||||
|    * | ||||
|    * 该接口主要应用于使用微信支付、微信红包和企业转账之后的结果查询。 | ||||
|    * 开发者需要知道某个结果事件的openid对应企业微信内成员的信息时,可以通过调用该接口进行转换查询。 | ||||
|    * 权限说明: | ||||
|    * 管理组需对openid对应的企业微信成员有查看权限。 | ||||
|    * | ||||
|    * 文档地址:https://work.weixin.qq.com/api/doc#11279 | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param openid 在使用微信支付、微信红包和企业转账之后,返回结果的openid | ||||
|    * @return userid 该openid在企业微信对应的成员userid | ||||
|    */ | ||||
|   String openid2UserId(String openid) throws WxErrorException; | ||||
|  | ||||
|   /** | ||||
|    * <pre> | ||||
|    * | ||||
|    * 通过手机号获取其所对应的userid。 | ||||
|    * | ||||
|    * 请求方式:POST(HTTPS) | ||||
|    * 请求地址:https://qyapi.weixin.qq.com/cgi-bin/user/getuserid?access_token=ACCESS_TOKEN | ||||
|    * | ||||
|    * 文档地址:https://work.weixin.qq.com/api/doc#90001/90143/91693 | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param mobile 手机号码。长度为5~32个字节 | ||||
|    * @return userid  mobile对应的成员userid | ||||
|    * @throws WxErrorException . | ||||
|    */ | ||||
|   String getUserId(String mobile) throws WxErrorException; | ||||
|  | ||||
|   /** | ||||
|    * 获取外部联系人详情. | ||||
|    * <pre> | ||||
|    *   企业可通过此接口,根据外部联系人的userid,拉取外部联系人详情。权限说明: | ||||
|    * 企业需要使用外部联系人管理secret所获取的accesstoken来调用 | ||||
|    * 第三方应用需拥有“企业客户”权限。 | ||||
|    * 第三方应用调用时,返回的跟进人follow_user仅包含应用可见范围之内的成员。 | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param userId 外部联系人的userid | ||||
|    * @return 联系人详情 | ||||
|    * @throws WxErrorException . | ||||
|    */ | ||||
|   WxCpUserExternalContactInfo getExternalContact(String userId) throws WxErrorException; | ||||
|  | ||||
|  | ||||
| } | ||||
| @ -22,7 +22,7 @@ import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; | ||||
| import me.chanjar.weixin.common.util.json.GsonParser; | ||||
| import me.chanjar.weixin.cp.bean.*; | ||||
| import me.chanjar.weixin.cp.config.WxCpTpConfigStorage; | ||||
| import me.chanjar.weixin.cp.tp.service.WxCpTpService; | ||||
| import me.chanjar.weixin.cp.tp.service.*; | ||||
| import org.apache.commons.lang3.StringUtils; | ||||
|  | ||||
| import java.io.File; | ||||
| @ -41,6 +41,12 @@ import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Tp.*; | ||||
| @Slf4j | ||||
| public abstract class BaseWxCpTpServiceImpl<H, P> implements WxCpTpService, RequestHttp<H, P> { | ||||
|  | ||||
|   private WxCpTpContactService wxCpTpContactService = new WxCpTpContactServiceImpl(this); | ||||
|   private WxCpTpDepartmentService wxCpTpDepartmentService = new WxCpTpDepartmentServiceImpl(this); | ||||
|   private WxCpTpMediaService wxCpTpMediaService = new WxCpTpMediaServiceImpl(this); | ||||
|   private WxCpTpOAService wxCpTpOAService = new WxCpTpOAServiceImpl(this); | ||||
|   private WxCpTpUserService wxCpTpUserService = new WxCpTpUserServiceImpl(this); | ||||
|  | ||||
|   /** | ||||
|    * 全局的是否正在刷新access token的锁. | ||||
|    */ | ||||
| @ -57,6 +63,13 @@ public abstract class BaseWxCpTpServiceImpl<H, P> implements WxCpTpService, Requ | ||||
|    */ | ||||
|   protected final Object globalJsApiTicketRefreshLock = new Object(); | ||||
|  | ||||
|   /** | ||||
|    * 全局的是否正在刷新auth_corp_jsapi_ticket的锁. | ||||
|    */ | ||||
|   protected final Object globalAuthCorpJsApiTicketRefreshLock = new Object(); | ||||
|  | ||||
|   protected final Object globalProviderTokenRefreshLock = new Object(); | ||||
|  | ||||
|   protected WxCpTpConfigStorage configStorage; | ||||
|  | ||||
|   private WxSessionManager sessionManager = new StandardSessionManager(); | ||||
| @ -104,12 +117,12 @@ public abstract class BaseWxCpTpServiceImpl<H, P> implements WxCpTpService, Requ | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void setSuiteTicket(String suiteTicket){ | ||||
|   public void setSuiteTicket(String suiteTicket) { | ||||
|     setSuiteTicket(suiteTicket, 28 * 60); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void setSuiteTicket(String suiteTicket, int expiresInSeconds){ | ||||
|   public void setSuiteTicket(String suiteTicket, int expiresInSeconds) { | ||||
|     synchronized (globalSuiteTicketRefreshLock) { | ||||
|       this.configStorage.updateSuiteTicket(suiteTicket, expiresInSeconds); | ||||
|     } | ||||
| @ -117,7 +130,7 @@ public abstract class BaseWxCpTpServiceImpl<H, P> implements WxCpTpService, Requ | ||||
|  | ||||
|   @Override | ||||
|   public String getSuiteJsApiTicket(String authCorpId) throws WxErrorException { | ||||
|     if (this.configStorage.isSuiteAccessTokenExpired()) { | ||||
|     if (this.configStorage.isAuthSuiteJsApiTicketExpired(authCorpId)) { | ||||
|  | ||||
|       String resp = get(configStorage.getApiUrl(GET_SUITE_JSAPI_TICKET), | ||||
|         "type=agent_config&access_token=" + this.configStorage.getAccessToken(authCorpId)); | ||||
| @ -129,18 +142,17 @@ public abstract class BaseWxCpTpServiceImpl<H, P> implements WxCpTpService, Requ | ||||
|         synchronized (globalJsApiTicketRefreshLock) { | ||||
|           configStorage.updateAuthSuiteJsApiTicket(authCorpId, jsApiTicket, expiredInSeconds); | ||||
|         } | ||||
|       } | ||||
|       else { | ||||
|       } else { | ||||
|         throw new WxErrorException(WxError.fromJson(resp)); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     return configStorage.getSuiteAccessToken(); | ||||
|     return configStorage.getAuthSuiteJsApiTicket(authCorpId); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public String getAuthCorpJsApiTicket(String authCorpId) throws WxErrorException { | ||||
|     if (this.configStorage.isSuiteAccessTokenExpired()) { | ||||
|     if (this.configStorage.isAuthCorpJsApiTicketExpired(authCorpId)) { | ||||
|  | ||||
|       String resp = get(configStorage.getApiUrl(GET_AUTH_CORP_JSAPI_TICKET), | ||||
|         "access_token=" + this.configStorage.getAccessToken(authCorpId)); | ||||
| @ -150,16 +162,14 @@ public abstract class BaseWxCpTpServiceImpl<H, P> implements WxCpTpService, Requ | ||||
|         String jsApiTicket = jsonObject.get("ticket").getAsString(); | ||||
|         int expiredInSeconds = jsonObject.get("expires_in").getAsInt(); | ||||
|  | ||||
|         synchronized (globalJsApiTicketRefreshLock) { | ||||
|         synchronized (globalAuthCorpJsApiTicketRefreshLock) { | ||||
|           configStorage.updateAuthCorpJsApiTicket(authCorpId, jsApiTicket, expiredInSeconds); | ||||
|         } | ||||
|       } | ||||
|       else { | ||||
|       } else { | ||||
|         throw new WxErrorException(WxError.fromJson(resp)); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     return configStorage.getSuiteAccessToken(); | ||||
|     return configStorage.getProviderToken(); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
| @ -223,9 +233,9 @@ public abstract class BaseWxCpTpServiceImpl<H, P> implements WxCpTpService, Requ | ||||
|     WxCpTpPreauthCode preAuthCode = WxCpTpPreauthCode.fromJson(result); | ||||
|     String setSessionUrl = "https://qyapi.weixin.qq.com/cgi-bin/service/set_session_info"; | ||||
|  | ||||
|     Map<String,Object> sessionInfo = new HashMap<>(1); | ||||
|     Map<String, Object> sessionInfo = new HashMap<>(1); | ||||
|     sessionInfo.put("auth_type", authType); | ||||
|     Map<String,Object> param = new HashMap<>(2); | ||||
|     Map<String, Object> param = new HashMap<>(2); | ||||
|     param.put("pre_auth_code", preAuthCode.getPreAuthCode()); | ||||
|     param.put("session_info", sessionInfo); | ||||
|     String postData = new Gson().toJson(param); | ||||
| @ -373,18 +383,97 @@ public abstract class BaseWxCpTpServiceImpl<H, P> implements WxCpTpService, Requ | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public WxCpTpUserInfo getUserInfo3rd(String code) throws WxErrorException{ | ||||
|   public WxCpTpUserInfo getUserInfo3rd(String code) throws WxErrorException { | ||||
|     String url = configStorage.getApiUrl(GET_USERINFO3RD); | ||||
|     String result = get(url+"?code="+code,null); | ||||
|     String result = get(url + "?code=" + code, null); | ||||
|     return WxCpTpUserInfo.fromJson(result); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public WxCpTpUserDetail getUserDetail3rd(String userTicket) throws WxErrorException{ | ||||
|   public WxCpTpUserDetail getUserDetail3rd(String userTicket) throws WxErrorException { | ||||
|     JsonObject jsonObject = new JsonObject(); | ||||
|     jsonObject.addProperty("user_ticket", userTicket); | ||||
|     String result = post(configStorage.getApiUrl(GET_USERDETAIL3RD), jsonObject.toString()); | ||||
|     return WxCpTpUserDetail.fromJson(result); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public WxTpLoginInfo getLoginInfo(String authCode) throws WxErrorException { | ||||
|     JsonObject jsonObject = new JsonObject(); | ||||
|     jsonObject.addProperty("auth_code", authCode); | ||||
|     jsonObject.addProperty("access_token", configStorage.getAccessToken(authCode)); | ||||
|     String responseText = post(configStorage.getApiUrl(GET_LOGIN_INFO), jsonObject.toString()); | ||||
|     return WxTpLoginInfo.fromJson(responseText); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public String getWxCpProviderToken() throws WxErrorException { | ||||
|     if (this.configStorage.isProviderTokenExpired()) { | ||||
|  | ||||
|       JsonObject jsonObject = new JsonObject(); | ||||
|       jsonObject.addProperty("corpid", configStorage.getCorpId()); | ||||
|       jsonObject.addProperty("provider_secret", configStorage.getProviderSecret()); | ||||
|       WxCpProviderToken wxCpProviderToken = | ||||
|         WxCpProviderToken.fromJson(this.post(this.configStorage.getApiUrl(GET_PROVIDER_TOKEN) | ||||
|           , jsonObject.toString())); | ||||
|       String providerAccessToken = wxCpProviderToken.getProviderAccessToken(); | ||||
|       Integer expiresIn = wxCpProviderToken.getExpiresIn(); | ||||
|  | ||||
|       synchronized (globalProviderTokenRefreshLock) { | ||||
|         configStorage.updateProviderToken(providerAccessToken, expiresIn - 200); | ||||
|       } | ||||
|     } | ||||
|     return configStorage.getProviderToken(); | ||||
|   } | ||||
|  | ||||
|  | ||||
|   @Override | ||||
|   public WxCpTpContactService getWxCpTpContactService() { | ||||
|     return wxCpTpContactService; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public WxCpTpDepartmentService getWxCpTpDepartmentService(){ | ||||
|     return wxCpTpDepartmentService; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public WxCpTpMediaService getWxCpTpMediaService(){ | ||||
|     return wxCpTpMediaService; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public WxCpTpOAService getWxCpTpOAService(){ | ||||
|     return wxCpTpOAService; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public WxCpTpUserService getWxCpTpUserService(){ | ||||
|     return wxCpTpUserService; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void setWxCpTpContactService(WxCpTpContactService wxCpTpContactService) { | ||||
|     this.wxCpTpContactService = wxCpTpContactService; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void setWxCpTpDepartmentService(WxCpTpDepartmentService wxCpTpDepartmentService) { | ||||
|     this.wxCpTpDepartmentService = wxCpTpDepartmentService; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void setWxCpTpMediaService(WxCpTpMediaService wxCpTpMediaService) { | ||||
|     this.wxCpTpMediaService = wxCpTpMediaService; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void setWxCpTpOAService(WxCpTpOAService wxCpTpOAService) { | ||||
|     this.wxCpTpOAService = wxCpTpOAService; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void setWxCpTpUserService(WxCpTpUserService wxCpTpUserService) { | ||||
|     this.wxCpTpUserService = wxCpTpUserService; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -0,0 +1,29 @@ | ||||
| package me.chanjar.weixin.cp.tp.service.impl; | ||||
|  | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import me.chanjar.weixin.common.error.WxErrorException; | ||||
| import me.chanjar.weixin.cp.bean.WxCpTpContactSearch; | ||||
| import me.chanjar.weixin.cp.bean.WxCpTpContactSearchResp; | ||||
| import me.chanjar.weixin.cp.tp.service.WxCpTpContactService; | ||||
| import me.chanjar.weixin.cp.tp.service.WxCpTpService; | ||||
|  | ||||
| import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Tp.CONTACT_SEARCH; | ||||
|  | ||||
| /** | ||||
|  * @author uianz | ||||
|  * @description | ||||
|  * @since 2020/12/23 下午 02:39 | ||||
|  */ | ||||
| @RequiredArgsConstructor | ||||
| public class WxCpTpContactServiceImpl implements WxCpTpContactService { | ||||
|  | ||||
|   private final WxCpTpService mainService; | ||||
|  | ||||
|   @Override | ||||
|   public WxCpTpContactSearchResp contactSearch(WxCpTpContactSearch wxCpTpContactSearch) throws WxErrorException { | ||||
|     String responseText = | ||||
|       mainService.post(mainService.getWxCpTpConfigStorage().getApiUrl(CONTACT_SEARCH) + "?provider_access_token=" + mainService.getWxCpTpConfigStorage().getCorpSecret(), wxCpTpContactSearch.toJson()); | ||||
|     return WxCpTpContactSearchResp.fromJson(responseText); | ||||
|   } | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,70 @@ | ||||
| package me.chanjar.weixin.cp.tp.service.impl; | ||||
|  | ||||
| import com.google.gson.JsonObject; | ||||
| import com.google.gson.reflect.TypeToken; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import me.chanjar.weixin.common.error.WxErrorException; | ||||
| import me.chanjar.weixin.common.util.json.GsonHelper; | ||||
| import me.chanjar.weixin.common.util.json.GsonParser; | ||||
| import me.chanjar.weixin.cp.api.impl.WxCpDepartmentServiceImpl; | ||||
| import me.chanjar.weixin.cp.bean.WxCpDepart; | ||||
| import me.chanjar.weixin.cp.bean.WxCpTpDepart; | ||||
| import me.chanjar.weixin.cp.tp.service.WxCpTpDepartmentService; | ||||
| import me.chanjar.weixin.cp.tp.service.WxCpTpService; | ||||
| import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Department.*; | ||||
|  | ||||
| /** | ||||
|  * @author uianz | ||||
|  * @description corp from {@link WxCpDepartmentServiceImpl )} | ||||
|  * 唯一不同在于获取部门列表时需要传对应企业的accessToken | ||||
|  * @since 2020/12/23 下午 02:39 | ||||
|  */ | ||||
| @RequiredArgsConstructor | ||||
| public class WxCpTpDepartmentServiceImpl implements WxCpTpDepartmentService { | ||||
|   private final WxCpTpService mainService; | ||||
|  | ||||
|   @Override | ||||
|   public Long create(WxCpTpDepart depart) throws WxErrorException { | ||||
|     String url = this.mainService.getWxCpTpConfigStorage().getApiUrl(DEPARTMENT_CREATE); | ||||
|     String responseContent = this.mainService.post(url, depart.toJson()); | ||||
|     JsonObject tmpJsonObject = GsonParser.parse(responseContent); | ||||
|     return GsonHelper.getAsLong(tmpJsonObject.get("id")); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void update(WxCpTpDepart group) throws WxErrorException { | ||||
|     String url = this.mainService.getWxCpTpConfigStorage().getApiUrl(DEPARTMENT_UPDATE); | ||||
|     this.mainService.post(url, group.toJson()); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void delete(Long departId) throws WxErrorException { | ||||
|     String url = String.format(this.mainService.getWxCpTpConfigStorage().getApiUrl(DEPARTMENT_DELETE), departId); | ||||
|     this.mainService.get(url, null); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public List<WxCpTpDepart> list(Long id, String corpId) throws WxErrorException { | ||||
|     String url = this.mainService.getWxCpTpConfigStorage().getApiUrl(DEPARTMENT_LIST); | ||||
|     url += "?access_token=" + this.mainService.getWxCpTpConfigStorage().getAccessToken(corpId); | ||||
|     if (id != null) { | ||||
|       url += "&id=" + id; | ||||
|     } | ||||
|     String responseContent = this.mainService.get(url, null); | ||||
|     JsonObject tmpJsonObject = GsonParser.parse(responseContent); | ||||
|     return WxCpGsonBuilder.create() | ||||
|       .fromJson(tmpJsonObject.get("department"), | ||||
|         new TypeToken<List<WxCpDepart>>() { | ||||
|         }.getType() | ||||
|       ); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public List<WxCpTpDepart> list(String corpId) throws WxErrorException { | ||||
|     return list(null, corpId); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,50 @@ | ||||
| package me.chanjar.weixin.cp.tp.service.impl; | ||||
|  | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | ||||
| import me.chanjar.weixin.common.error.WxErrorException; | ||||
| import me.chanjar.weixin.common.util.fs.FileUtils; | ||||
| import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; | ||||
| import me.chanjar.weixin.cp.tp.service.WxCpTpMediaService; | ||||
| import me.chanjar.weixin.cp.tp.service.WxCpTpService; | ||||
|  | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.util.UUID; | ||||
|  | ||||
| import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Media.IMG_UPLOAD; | ||||
| import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Media.MEDIA_UPLOAD; | ||||
|  | ||||
| /** | ||||
|  * <pre> | ||||
|  * 媒体管理接口. | ||||
|  * Created by Binary Wang on 2017-6-25. | ||||
|  * </pre> | ||||
|  * | ||||
|  * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
|  */ | ||||
| @RequiredArgsConstructor | ||||
| public class WxCpTpMediaServiceImpl implements WxCpTpMediaService { | ||||
|     private final WxCpTpService mainService; | ||||
|  | ||||
|     @Override | ||||
|     public WxMediaUploadResult upload(String mediaType, String fileType, InputStream inputStream, String corpId) | ||||
|             throws WxErrorException, IOException { | ||||
|         return this.upload(mediaType, FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType), corpId); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public WxMediaUploadResult upload(String mediaType, File file, String corpId) throws WxErrorException { | ||||
|         return this.mainService.execute(MediaUploadRequestExecutor.create(this.mainService.getRequestHttp()), | ||||
|           mainService.getWxCpTpConfigStorage().getApiUrl(MEDIA_UPLOAD + mediaType) + "&access_token=" + mainService.getWxCpTpConfigStorage().getAccessToken(corpId), file); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String uploadImg(File file, String corpId) throws WxErrorException { | ||||
|         String url = mainService.getWxCpTpConfigStorage().getApiUrl(IMG_UPLOAD); | ||||
|         url += "&access_token=" + mainService.getWxCpTpConfigStorage().getAccessToken(corpId); | ||||
|         return this.mainService.execute(MediaUploadRequestExecutor.create(this.mainService.getRequestHttp()), url, file) | ||||
|                 .getUrl(); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,66 @@ | ||||
| package me.chanjar.weixin.cp.tp.service.impl; | ||||
|  | ||||
| import com.google.gson.JsonObject; | ||||
| import lombok.NonNull; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import me.chanjar.weixin.common.error.WxErrorException; | ||||
| import me.chanjar.weixin.common.util.json.GsonParser; | ||||
| import me.chanjar.weixin.cp.bean.oa.WxCpApprovalDetailResult; | ||||
| import me.chanjar.weixin.cp.bean.oa.WxCpOaApplyEventRequest; | ||||
| import me.chanjar.weixin.cp.bean.oa.WxCpTemplateResult; | ||||
| import me.chanjar.weixin.cp.tp.service.WxCpTpOAService; | ||||
| import me.chanjar.weixin.cp.tp.service.WxCpTpService; | ||||
| import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | ||||
|  | ||||
| import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Oa.*; | ||||
|  | ||||
| /** | ||||
|  * 企业微信 OA 接口实现 | ||||
|  * | ||||
|  * @author Element | ||||
|  * @date 2019-04-06 11:20 | ||||
|  */ | ||||
| @RequiredArgsConstructor | ||||
| public class WxCpTpOAServiceImpl implements WxCpTpOAService { | ||||
|     private final WxCpTpService mainService; | ||||
|  | ||||
|  | ||||
|     @Override | ||||
|     public String apply(WxCpOaApplyEventRequest request, String corpId) throws WxErrorException { | ||||
|         String url = mainService.getWxCpTpConfigStorage().getApiUrl(APPLY_EVENT) + | ||||
|                 "?access_token=" + mainService.getWxCpTpConfigStorage().getAccessToken(corpId); | ||||
|  | ||||
|         String responseContent = this.mainService.post(url, request.toJson()); | ||||
|         return GsonParser.parse(responseContent).get("sp_no").getAsString(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public WxCpTemplateResult getTemplateDetail(@NonNull String templateId, String corpId) throws WxErrorException { | ||||
|         JsonObject jsonObject = new JsonObject(); | ||||
|         jsonObject.addProperty("template_id", templateId); | ||||
|         String url = mainService.getWxCpTpConfigStorage().getApiUrl(GET_TEMPLATE_DETAIL) + | ||||
|                 "?access_token=" + mainService.getWxCpTpConfigStorage().getAccessToken(corpId); | ||||
|         String responseContent = this.mainService.post(url, jsonObject.toString()); | ||||
|         return WxCpGsonBuilder.create().fromJson(responseContent, WxCpTemplateResult.class); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String copyTemplate(@NonNull String openTemplateId, String corpId) throws WxErrorException { | ||||
|         JsonObject jsonObject = new JsonObject(); | ||||
|         jsonObject.addProperty("open_template_id", openTemplateId); | ||||
|         String url = mainService.getWxCpTpConfigStorage().getApiUrl(COPY_TEMPLATE) + | ||||
|                 "?access_token=" + mainService.getWxCpTpConfigStorage().getAccessToken(corpId); | ||||
|         String responseContent = this.mainService.post(url, jsonObject.toString()); | ||||
|         return GsonParser.parse(responseContent).get("template_id").getAsString(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public WxCpApprovalDetailResult getApprovalDetail(@NonNull String spNo, String corpId) throws WxErrorException { | ||||
|         JsonObject jsonObject = new JsonObject(); | ||||
|         jsonObject.addProperty("sp_no", spNo); | ||||
|         final String url = mainService.getWxCpTpConfigStorage().getApiUrl(GET_APPROVAL_DETAIL) + | ||||
|                 "?access_token=" + mainService.getWxCpTpConfigStorage().getAccessToken(corpId); | ||||
|         String responseContent = this.mainService.post(url, jsonObject.toString()); | ||||
|         return WxCpGsonBuilder.create().fromJson(responseContent, WxCpApprovalDetailResult.class); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,204 @@ | ||||
| package me.chanjar.weixin.cp.tp.service.impl; | ||||
|  | ||||
| import com.google.common.collect.Maps; | ||||
| 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.WxCpInviteResult; | ||||
| import me.chanjar.weixin.cp.bean.WxCpUser; | ||||
| import me.chanjar.weixin.cp.bean.WxCpUserExternalContactInfo; | ||||
| import me.chanjar.weixin.cp.tp.service.WxCpTpService; | ||||
| import me.chanjar.weixin.cp.tp.service.WxCpTpUserService; | ||||
| import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | ||||
|  | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
|  | ||||
| import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.User.*; | ||||
|  | ||||
| /** | ||||
|  * <pre> | ||||
|  *  Created by jamie on 2020/7/22. | ||||
|  * </pre> | ||||
|  */ | ||||
| @RequiredArgsConstructor | ||||
| public class WxCpTpUserServiceImpl implements WxCpTpUserService { | ||||
|   private final WxCpTpService mainService; | ||||
|  | ||||
|   @Override | ||||
|   public void authenticate(String userId) throws WxErrorException { | ||||
|     this.mainService.get(mainService.getWxCpTpConfigStorage().getApiUrl(USER_AUTHENTICATE + userId), null); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void create(WxCpUser user) throws WxErrorException { | ||||
|     String url = mainService.getWxCpTpConfigStorage().getApiUrl(USER_CREATE); | ||||
|     this.mainService.post(url, user.toJson()); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void update(WxCpUser user) throws WxErrorException { | ||||
|     String url = mainService.getWxCpTpConfigStorage().getApiUrl(USER_UPDATE); | ||||
|     this.mainService.post(url, user.toJson()); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void delete(String... userIds) throws WxErrorException { | ||||
|     if (userIds.length == 1) { | ||||
|       String url = mainService.getWxCpTpConfigStorage().getApiUrl(USER_DELETE + userIds[0]); | ||||
|       this.mainService.get(url, null); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     JsonObject jsonObject = new JsonObject(); | ||||
|     JsonArray jsonArray = new JsonArray(); | ||||
|     for (String userId : userIds) { | ||||
|       jsonArray.add(new JsonPrimitive(userId)); | ||||
|     } | ||||
|  | ||||
|     jsonObject.add("useridlist", jsonArray); | ||||
|     this.mainService.post(mainService.getWxCpTpConfigStorage().getApiUrl(USER_BATCH_DELETE), | ||||
|       jsonObject.toString()); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public WxCpUser getById(String userid, String corpId) throws WxErrorException { | ||||
|     String url = mainService.getWxCpTpConfigStorage().getApiUrl(USER_GET + userid); | ||||
|     url += "&access_token=" + mainService.getWxCpTpConfigStorage().getAccessToken(corpId); | ||||
|     String responseContent = this.mainService.get(url, null); | ||||
|     return WxCpUser.fromJson(responseContent); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public List<WxCpUser> listByDepartment(Long departId, Boolean fetchChild, Integer status, String corpId) throws WxErrorException { | ||||
|     String params = ""; | ||||
|     if (fetchChild != null) { | ||||
|       params += "&fetch_child=" + (fetchChild ? "1" : "0"); | ||||
|     } | ||||
|     if (status != null) { | ||||
|       params += "&status=" + status; | ||||
|     } else { | ||||
|       params += "&status=0"; | ||||
|     } | ||||
|     params += "&access_token=" + mainService.getWxCpTpConfigStorage().getAccessToken(corpId); | ||||
|  | ||||
|     String url = mainService.getWxCpTpConfigStorage().getApiUrl(USER_LIST + departId); | ||||
|     String responseContent = this.mainService.get(url, params); | ||||
|     JsonObject tmpJsonElement = GsonParser.parse(responseContent); | ||||
|     return WxCpGsonBuilder.create() | ||||
|       .fromJson(tmpJsonElement.getAsJsonObject().get("userlist"), | ||||
|         new TypeToken<List<WxCpUser>>() { | ||||
|         }.getType() | ||||
|       ); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public List<WxCpUser> listSimpleByDepartment(Long departId, Boolean fetchChild, Integer status) | ||||
|     throws WxErrorException { | ||||
|     String params = ""; | ||||
|     if (fetchChild != null) { | ||||
|       params += "&fetch_child=" + (fetchChild ? "1" : "0"); | ||||
|     } | ||||
|     if (status != null) { | ||||
|       params += "&status=" + status; | ||||
|     } else { | ||||
|       params += "&status=0"; | ||||
|     } | ||||
|  | ||||
|     String url = mainService.getWxCpTpConfigStorage().getApiUrl(USER_SIMPLE_LIST + departId); | ||||
|     String responseContent = this.mainService.get(url, params); | ||||
|     JsonObject tmpJsonElement = GsonParser.parse(responseContent); | ||||
|     return WxCpGsonBuilder.create() | ||||
|       .fromJson( | ||||
|         tmpJsonElement.getAsJsonObject().get("userlist"), | ||||
|         new TypeToken<List<WxCpUser>>() { | ||||
|         }.getType() | ||||
|       ); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public WxCpInviteResult invite(List<String> userIds, List<String> partyIds, List<String> tagIds) | ||||
|     throws WxErrorException { | ||||
|     JsonObject jsonObject = new JsonObject(); | ||||
|     if (userIds != null) { | ||||
|       JsonArray jsonArray = new JsonArray(); | ||||
|       for (String userId : userIds) { | ||||
|         jsonArray.add(new JsonPrimitive(userId)); | ||||
|       } | ||||
|       jsonObject.add("user", jsonArray); | ||||
|     } | ||||
|  | ||||
|     if (partyIds != null) { | ||||
|       JsonArray jsonArray = new JsonArray(); | ||||
|       for (String userId : partyIds) { | ||||
|         jsonArray.add(new JsonPrimitive(userId)); | ||||
|       } | ||||
|       jsonObject.add("party", jsonArray); | ||||
|     } | ||||
|  | ||||
|     if (tagIds != null) { | ||||
|       JsonArray jsonArray = new JsonArray(); | ||||
|       for (String tagId : tagIds) { | ||||
|         jsonArray.add(new JsonPrimitive(tagId)); | ||||
|       } | ||||
|       jsonObject.add("tag", jsonArray); | ||||
|     } | ||||
|  | ||||
|     String url = mainService.getWxCpTpConfigStorage().getApiUrl(BATCH_INVITE); | ||||
|     return WxCpInviteResult.fromJson(this.mainService.post(url, jsonObject.toString())); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public Map<String, String> userId2Openid(String userId, Integer agentId) throws WxErrorException { | ||||
|     String url = mainService.getWxCpTpConfigStorage().getApiUrl(USER_CONVERT_TO_OPENID); | ||||
|     JsonObject jsonObject = new JsonObject(); | ||||
|     jsonObject.addProperty("userid", userId); | ||||
|     if (agentId != null) { | ||||
|       jsonObject.addProperty("agentid", agentId); | ||||
|     } | ||||
|  | ||||
|     String responseContent = this.mainService.post(url, jsonObject.toString()); | ||||
|     JsonObject tmpJsonElement = GsonParser.parse(responseContent); | ||||
|     Map<String, String> result = Maps.newHashMap(); | ||||
|     if (tmpJsonElement.getAsJsonObject().get("openid") != null) { | ||||
|       result.put("openid", tmpJsonElement.getAsJsonObject().get("openid").getAsString()); | ||||
|     } | ||||
|  | ||||
|     if (tmpJsonElement.getAsJsonObject().get("appid") != null) { | ||||
|       result.put("appid", tmpJsonElement.getAsJsonObject().get("appid").getAsString()); | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public String openid2UserId(String openid) throws WxErrorException { | ||||
|     JsonObject jsonObject = new JsonObject(); | ||||
|     jsonObject.addProperty("openid", openid); | ||||
|     String url = mainService.getWxCpTpConfigStorage().getApiUrl(USER_CONVERT_TO_USERID); | ||||
|     String responseContent = this.mainService.post(url, jsonObject.toString()); | ||||
|     JsonObject tmpJsonElement = GsonParser.parse(responseContent); | ||||
|     return tmpJsonElement.getAsJsonObject().get("userid").getAsString(); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public String getUserId(String mobile) throws WxErrorException { | ||||
|     JsonObject jsonObject = new JsonObject(); | ||||
|     jsonObject.addProperty("mobile", mobile); | ||||
|     String url = mainService.getWxCpTpConfigStorage().getApiUrl(GET_USER_ID); | ||||
|     String responseContent = this.mainService.post(url, jsonObject.toString()); | ||||
|     JsonObject tmpJsonElement = GsonParser.parse(responseContent); | ||||
|     return tmpJsonElement.getAsJsonObject().get("userid").getAsString(); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public WxCpUserExternalContactInfo getExternalContact(String userId) throws WxErrorException { | ||||
|     String url = mainService.getWxCpTpConfigStorage().getApiUrl(GET_EXTERNAL_CONTACT + userId); | ||||
|     String responseContent = this.mainService.get(url, null); | ||||
|     return WxCpUserExternalContactInfo.fromJson(responseContent); | ||||
|   } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 uianz
					uianz