Skip to content

Commit

Permalink
🆕 #1474 企业微信新增客户联系「联系我」管理接口 修正 / #1590 开放平台刷新AccessToken同步更新RefreshToken
Browse files Browse the repository at this point in the history
* #1474 新增客户联系「联系我」管理接口

* fix #1590 提及的me.chanjar.weixin.open.api.impl.WxOpenComponentServiceImpl#getAuthorizerAccessToken()刷新AccessToken后没有同步对应的refreshToken

* 补充 me.chanjar.weixin.open.api.impl.WxOpenInMemoryConfigStorage#updateToken 方法对 expireInSeconds 边界判断
  • Loading branch information
forfuns committed Jul 21, 2020
1 parent 04fb35d commit 0758049
Show file tree
Hide file tree
Showing 12 changed files with 563 additions and 19 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package me.chanjar.weixin.cp.api;

import lombok.NonNull;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.bean.*;

Expand All @@ -15,6 +16,83 @@
* @author <a href="https://github.com/JoeCao">JoeCao</a>
*/
public interface WxCpExternalContactService {

/**
* 配置客户联系「联系我」方式
* <pre>
* 企业可以在管理后台-客户联系中配置成员的「联系我」的二维码或者小程序按钮,客户通过扫描二维码或点击小程序上的按钮,即可获取成员联系方式,主动联系到成员。
* 企业可通过此接口为具有客户联系功能的成员生成专属的「联系我」二维码或者「联系我」按钮。
* 如果配置的是「联系我」按钮,需要开发者的小程序接入小程序插件。
*
* 注意:
* 通过API添加的「联系我」不会在管理端进行展示,每个企业可通过API最多配置50万个「联系我」。
* 用户需要妥善存储返回的config_id,config_id丢失可能导致用户无法编辑或删除「联系我」。
* 临时会话模式不占用「联系我」数量,但每日最多添加10万个,并且仅支持单人。
* 临时会话模式的二维码,添加好友完成后该二维码即刻失效。
* </pre>
*
* @param info 客户联系「联系我」方式
* @return
* @throws WxErrorException
*/
WxCpContactWayResult addContactWay(@NonNull WxCpContactWayInfo info) throws WxErrorException;

/**
* 获取企业已配置的「联系我」方式
*
* <pre>
* <b>批量</b>获取企业配置的「联系我」二维码和「联系我」小程序按钮。
* </pre>
*
* @param configId 联系方式的配置id,必填
* @return
* @throws WxErrorException
*/
WxCpContactWayInfo getContactWay(@NonNull String configId) throws WxErrorException;

/**
* 更新企业已配置的「联系我」方式
*
* <pre>
* 更新企业配置的「联系我」二维码和「联系我」小程序按钮中的信息,如使用人员和备注等。
* </pre>
*
* @param info 客户联系「联系我」方式
* @return
* @throws WxErrorException
*/
WxCpBaseResp updateContactWay(@NonNull WxCpContactWayInfo info) throws WxErrorException;

/**
* 删除企业已配置的「联系我」方式
*
* <pre>
* 删除一个已配置的「联系我」二维码或者「联系我」小程序按钮。
* </pre>
*
* @param configId 企业联系方式的配置id,必填
* @return
* @throws WxErrorException
*/
WxCpBaseResp deleteContactWay(@NonNull String configId) throws WxErrorException;

/**
* 结束临时会话
*
* <pre>
* 将指定的企业成员和客户之前的临时会话断开,断开前会自动下发已配置的结束语。
*
* 注意:请保证传入的企业成员和客户之间有仍然有效的临时会话, 通过<b>其他方式的添加外部联系人无法通过此接口关闭会话</b>。
* </pre>
*
* @param userId
* @param externalUserId
* @return
* @throws WxErrorException
*/
WxCpBaseResp closeTempChat(@NonNull String userId, @NonNull String externalUserId) throws WxErrorException;


/**
* 获取外部联系人详情.
* <pre>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import me.chanjar.weixin.common.error.WxCpErrorMsgEnum;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.api.WxCpExternalContactService;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.*;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.Collections;
import java.util.Date;
Expand All @@ -23,6 +25,70 @@
public class WxCpExternalContactServiceImpl implements WxCpExternalContactService {
private final WxCpService mainService;

@Override
public WxCpContactWayResult addContactWay(@NonNull WxCpContactWayInfo info) throws WxErrorException {

if (info.getUsers() != null && info.getUsers().size() > 100) {
throw new RuntimeException("「联系我」使用人数默认限制不超过100人(包括部门展开后的人数)");
}

final String url = this.mainService.getWxCpConfigStorage().getApiUrl(ADD_CONTACT_WAY);
String responseContent = this.mainService.post(url, info.toJson());

return WxCpContactWayResult.fromJson(responseContent);
}

@Override
public WxCpContactWayInfo getContactWay(@NonNull String configId) throws WxErrorException {
JsonObject json = new JsonObject();
json.addProperty("config_id", configId);

final String url = this.mainService.getWxCpConfigStorage().getApiUrl(GET_CONTACT_WAY);
String responseContent = this.mainService.post(url, json.toString());

return WxCpContactWayInfo.fromJson(responseContent);
}

@Override
public WxCpBaseResp updateContactWay(@NonNull WxCpContactWayInfo info) throws WxErrorException {
if (StringUtils.isBlank(info.getConfigId())) {
throw new RuntimeException("更新「联系我」方式需要指定configId");
}
if (info.getUsers() != null && info.getUsers().size() > 100) {
throw new RuntimeException("「联系我」使用人数默认限制不超过100人(包括部门展开后的人数)");
}

final String url = this.mainService.getWxCpConfigStorage().getApiUrl(UPDATE_CONTACT_WAY);
String responseContent = this.mainService.post(url, info.toJson());

return WxCpBaseResp.fromJson(responseContent);
}

@Override
public WxCpBaseResp deleteContactWay(@NonNull String configId) throws WxErrorException {
JsonObject json = new JsonObject();
json.addProperty("config_id",configId);

final String url = this.mainService.getWxCpConfigStorage().getApiUrl(DEL_CONTACT_WAY);
String responseContent = this.mainService.post(url, json.toString());

return WxCpBaseResp.fromJson(responseContent);
}

@Override
public WxCpBaseResp closeTempChat(@NonNull String userId, @NonNull String externalUserId) throws WxErrorException {

JsonObject json = new JsonObject();
json.addProperty("userid",userId);
json.addProperty("external_userid",externalUserId);


final String url = this.mainService.getWxCpConfigStorage().getApiUrl(CLOSE_TEMP_CHAT);
String responseContent = this.mainService.post(url, json.toString());

return WxCpBaseResp.fromJson(responseContent);
}

@Override
public WxCpUserExternalContactInfo getExternalContact(String userId) throws WxErrorException {
final String url = this.mainService.getWxCpConfigStorage().getApiUrl(GET_EXTERNAL_CONTACT + userId);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
package me.chanjar.weixin.cp.bean;

import com.google.gson.annotations.JsonAdapter;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.NoArgsConstructor;
import me.chanjar.weixin.cp.util.json.WxCpConclusionAdapter;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;

import java.util.List;

/**
* 「联系我」方式 对象
*
* @author element
*/
@Data
@NoArgsConstructor
public class WxCpContactWayInfo {

/**
* 联系方式的配置id
*/
@SerializedName("config_id")
private String configId;

/**
* <pre>
* 必填
* 联系方式类型,1-单人, 2-多人
* </pre>
*/
private TYPE type;

/**
* <pre>
* 必填
* 场景,1-在小程序中联系,2-通过二维码联系
* </pre>
*/
private SCENE scene;

/**
* <pre>
* 非必填
* 在小程序中联系时使用的控件样式
* <b>单人样式(type=1)时可选1,2,3</b>
* <b>多人样式(type=2)时可选1,2</b>
* </pre>
*/
private Integer style;

/**
* <pre>
* 非必填
* 联系方式的备注信息,用于助记,不超过30个字符
* </pre>
*/
private String remark;

/**
* <pre>
* 非必填
* 外部客户添加时是否无需验证,默认为true
* </pre>
*/
@SerializedName("skip_verify")
private Boolean skipVerify = Boolean.TRUE;

/**
* <pre>
* 非必填
* 企业自定义的state参数,用于区分不同的添加渠道,在调用“获取外部联系人详情(WxCpExternalContactService.getContactDetail)” 时会返回该参数值,不超过30个字符
* </pre>
*/
private String state;

/**
* <pre>
* 使用该联系方式的用户userID列表,在type为1时为必填,且只能有一个
* </pre>
*/
@SerializedName("user")
private List<String> users;


/**
* <pre>
* 非必填
* 使用该联系方式的部门id列表,只在type为2时有效
* </pre>
*/
@SerializedName("party")
private List<String> partys;

/**
* <pre>
* 非必填
* 是否临时会话模式,true表示使用临时会话模式,默认为false
* </pre>
*/
@SerializedName("is_temp")
private Boolean isTemp = Boolean.FALSE;

/**
* <pre>
* 非必填
* 临时会话二维码有效期,以秒为单位。该参数仅在is_temp为true时有效,默认7天
* </pre>
*/
@SerializedName("expires_in")
private Integer expiresIn;

/**
* <pre>
* 非必填
* 临时会话有效期,以秒为单位。该参数仅在is_temp为true时有效,默认为添加好友后24小时
* </pre>
*/
@SerializedName("chat_expires_in")
private Integer chatExpiresIn;

/**
* <pre>
* 非必填
* 可进行临时会话的客户unionid,该参数仅在is_temp为true时有效,如不指定则不进行限制
* </pre>
*/
@SerializedName("unionid")
private String unionId;

/**
* <pre>
* 非必填
* 结束语,会话结束时自动发送给客户,可参考“结束语定义”,仅在is_temp为true时有效
* </pre>
*/
private Conclusion conclusions;

public static WxCpContactWayInfo fromJson(String json) {
return WxCpGsonBuilder.create().fromJson(json, WxCpContactWayInfo.class);
}

public String toJson() {
return WxCpGsonBuilder.create().toJson(this);
}

/**
* 结束语定义
*/
@Data
@JsonAdapter(WxCpConclusionAdapter.class)
public static class Conclusion {
private String textContent;
private String imgMediaId;
private String imgPicUrl;
private String linkTitle;
private String linkPicUrl;
private String linkDesc;
private String linkUrl;
private String miniProgramTitle;
private String miniProgramPicMediaId;
private String miniProgramAppId;
private String miniProgramPage;
}

public enum TYPE {
/**
* 单人
*/
@SerializedName("1")
SIGLE,

/**
* 多人
*/
@SerializedName("2")
MULTI;

}

public enum SCENE {

/**
* 在小程序中联系
*/
@SerializedName("1")
MINIPROGRAM,

/**
* 通过二维码联系
*/
@SerializedName("2")
QRCODE;

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package me.chanjar.weixin.cp.bean;

import com.google.gson.annotations.SerializedName;
import lombok.Data;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;

/**
* 「联系我」方式 处理结果
*/
@Data
public class WxCpContactWayResult extends WxCpBaseResp {
@SerializedName("config_id")
private String configId;

public static WxCpContactWayResult fromJson(String json) {
return WxCpGsonBuilder.create().fromJson(json, WxCpContactWayResult.class);
}
}
Loading

0 comments on commit 0758049

Please sign in to comment.