From 1483824dea62524ae00f10e8507653c15f9bb645 Mon Sep 17 00:00:00 2001 From: wangmeng3486 Date: Fri, 23 Dec 2022 11:47:32 +0800 Subject: [PATCH 1/2] =?UTF-8?q?:bug:=20=E4=BF=AE=E5=A4=8D=E7=9B=B4?= =?UTF-8?q?=E5=B1=9E=E9=A2=86=E5=AF=BC=E6=B2=A1=E6=9C=89=E8=A2=AB=E6=AD=A3?= =?UTF-8?q?=E5=B8=B8=E5=BA=8F=E5=88=97=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java index 8fd333a599..0c32ba0060 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java @@ -260,6 +260,13 @@ public JsonElement serialize(WxCpUser user, Type typeOfSrc, JsonSerializationCon } this.addProperty(o, "main_department", user.getMainDepartment()); + if (user.getDirectLeader() != null && user.getDirectLeader().length > 0) { + JsonArray ary = new JsonArray(); + for (String item : user.getDirectLeader()) { + ary.add(item); + } + o.add("direct_leader", ary); + } if (!user.getExtAttrs().isEmpty()) { JsonArray attrsJsonArray = new JsonArray(); for (Attr attr : user.getExtAttrs()) { From 61b0403b8d81708dc0a6e18c99ca7b1d21f8d340 Mon Sep 17 00:00:00 2001 From: wangmeng3486 Date: Fri, 3 Feb 2023 15:08:42 +0800 Subject: [PATCH 2/2] =?UTF-8?q?:new:=20=E3=80=90=E4=BC=81=E4=B8=9A?= =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E3=80=91=E5=A2=9E=E5=8A=A0=E5=9C=A8=E7=BA=BF?= =?UTF-8?q?=E4=BC=9A=E8=AE=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/cp/api/WxCpMeetingService.java | 97 ++++++ .../me/chanjar/weixin/cp/api/WxCpService.java | 7 + .../cp/api/impl/BaseWxCpServiceImpl.java | 7 + .../cp/api/impl/WxCpMeetingServiceImpl.java | 78 +++++ .../cp/bean/oa/meeting/WxCpMeeting.java | 305 ++++++++++++++++++ .../oa/meeting/WxCpMeetingUpdateResult.java | 41 +++ .../oa/meeting/WxCpUserMeetingIdResult.java | 40 +++ .../weixin/cp/constant/WxCpApiPathConsts.java | 22 ++ .../api/impl/WxCpMeetingServiceImplTest.java | 93 ++++++ 9 files changed, 690 insertions(+) create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMeetingService.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMeetingServiceImpl.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpMeeting.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpMeetingUpdateResult.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpUserMeetingIdResult.java create mode 100644 weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMeetingServiceImplTest.java diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMeetingService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMeetingService.java new file mode 100644 index 0000000000..e3ee866118 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMeetingService.java @@ -0,0 +1,97 @@ +package me.chanjar.weixin.cp.api; + +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.cp.bean.oa.meeting.WxCpMeeting; +import me.chanjar.weixin.cp.bean.oa.meeting.WxCpMeetingUpdateResult; +import me.chanjar.weixin.cp.bean.oa.meeting.WxCpUserMeetingIdResult; + +import java.util.List; + +/** + * 企业微信日程接口. + * 企业和开发者通过会议接口可以便捷地预定及管理会议,用于小组周会、部门例会等场景。 + * 调用接口的应用自动成为会议创建者,也可指定成员作为会议管理员辅助管理。 + * 官方文档:https://developer.work.weixin.qq.com/document/path/93626 + * + * @author wangmeng3486 created on 2023-01-31 + */ +public interface WxCpMeetingService { + /** + * 创建预约会议 + *

+ * 该接口用于创建一个预约会议。 + *

+ * 请求方式: POST(HTTPS) + * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/meeting/create?access_token=ACCESS_TOKEN + * + * @param meeting the meeting + * @return 会议ID string + * @throws WxErrorException the wx error exception + */ + String create(WxCpMeeting meeting) throws WxErrorException; + + /** + * 修改预约会议 + *

+ * 该接口用于修改一个指定的预约会议。。 + *

+ * 请求方式: POST(HTTPS) + * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/meeting/update?access_token=ACCESS_TOKEN + * + * @param meeting the meeting + * @return wx cp meeting update result + * @throws WxErrorException the wx error exception + */ + WxCpMeetingUpdateResult update(WxCpMeeting meeting) throws WxErrorException; + + + /** + * 取消预约会议 + * 该接口用于取消一个指定的预约会议。 + *

+ * 请求方式: POST(HTTPS) + * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/meeting/cancel?access_token=ACCESS_TOKEN + * + * @param meetingId 会议ID + * @throws WxErrorException the wx error exception + */ + void cancel(String meetingId) throws WxErrorException; + + /** + * 获取会议详情 + *

+ * 该接口用于获取指定会议的详情内容。 + *

+ * 请求方式: POST(HTTPS) + * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/oa/meeting/get?access_token=ACCESS_TOKEN + * + * @param meetingId the meeting ids + * @return the details + * @throws WxErrorException the wx error exception + */ + WxCpMeeting getDetail(String meetingId) throws WxErrorException; + + /** + * 获取成员会议ID列表 + * 该接口用于获取指定成员指定时间内的会议ID列表。 + *

+ * 权限说明: + * 只能拉取该应用创建的会议ID + * 自建应用需要配置在“可调用接口的应用”列表 + * 第三方服务商创建应用的时候,需要开启“会议接口权限” + * 代开发自建应用需要授权“会议接口权限” + *

+ * 请求方式: POST(HTTPS) + * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/meeting/get_user_meetingid?access_token=ACCESS_TOKEN + * + * @param userId 企业成员的userid + * @param cursor 上一次调用时返回的cursor,初次调用可以填"0" + * @param limit 每次拉取的数据量,默认值和最大值都为100 + * @param beginTime 开始时间 + * @param endTime 结束时间,时间跨度不超过180天。如果begin_time和end_time都没填的话,默认end_time为当前时间 + * @return result of listUserMeetingIds + * @throws WxErrorException the wx error exception + */ + WxCpUserMeetingIdResult getUserMeetingIds(String userId, String cursor, Integer limit, + Long beginTime, Long endTime) throws WxErrorException; +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java index 8a9bdb19ba..2c38f6fc52 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java @@ -562,4 +562,11 @@ public interface WxCpService extends WxService { * @param exportService 异步导出服务 */ void setExportService(WxCpExportService exportService); + + /** + * 相关接口的服务类对象 + * + * @return the meeting service + */ + WxCpMeetingService getMeetingService(); } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java index dea53f5dcc..752360003f 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java @@ -70,6 +70,8 @@ public abstract class BaseWxCpServiceImpl implements WxCpService, RequestH private WxCpExportService exportService = new WxCpExportServiceImpl(this); + private final WxCpMeetingService meetingService = new WxCpMeetingServiceImpl(this); + /** * 全局的是否正在刷新access token的锁. */ @@ -665,4 +667,9 @@ public WxCpExportService getExportService() { public void setExportService(WxCpExportService exportService) { this.exportService = exportService; } + + @Override + public WxCpMeetingService getMeetingService() { + return meetingService; + } } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMeetingServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMeetingServiceImpl.java new file mode 100644 index 0000000000..8ca7961ae1 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMeetingServiceImpl.java @@ -0,0 +1,78 @@ +package me.chanjar.weixin.cp.api.impl; + +import com.google.common.collect.ImmutableMap; +import lombok.RequiredArgsConstructor; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.cp.api.WxCpMeetingService; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.bean.oa.meeting.WxCpMeeting; +import me.chanjar.weixin.cp.bean.oa.meeting.WxCpMeetingUpdateResult; +import me.chanjar.weixin.cp.bean.oa.meeting.WxCpUserMeetingIdResult; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Oa.*; + +/** + * 企业微信日程接口. + * 企业和开发者通过会议接口可以便捷地预定及管理会议,用于小组周会、部门例会等场景。 + * 调用接口的应用自动成为会议创建者,也可指定成员作为会议管理员辅助管理。 + * 官方文档:https://developer.work.weixin.qq.com/document/path/93626 + * + * @author wangmeng3486 created on 2023-01-31 + */ +@RequiredArgsConstructor +public class WxCpMeetingServiceImpl implements WxCpMeetingService { + private final WxCpService cpService; + + @Override + public String create(WxCpMeeting meeting) throws WxErrorException { + return this.cpService.post(this.cpService.getWxCpConfigStorage().getApiUrl(MEETING_ADD), + WxCpGsonBuilder.create().toJson(meeting)); + } + + @Override + public WxCpMeetingUpdateResult update(WxCpMeeting meeting) throws WxErrorException { + final String response = this.cpService.post(this.cpService.getWxCpConfigStorage().getApiUrl(MEETING_UPDATE), + WxCpGsonBuilder.create().toJson(meeting)); + return WxCpGsonBuilder.create().fromJson(response, WxCpMeetingUpdateResult.class); + } + + @Override + public void cancel(String meetingId) throws WxErrorException { + this.cpService.post(this.cpService.getWxCpConfigStorage().getApiUrl(MEETING_CANCEL), + WxCpGsonBuilder.create().toJson(ImmutableMap.of("meetingid", meetingId))); + } + + @Override + public WxCpMeeting getDetail(String meetingId) throws WxErrorException { + final String response = this.cpService.post(this.cpService.getWxCpConfigStorage().getApiUrl(MEETING_DETAIL), + WxCpGsonBuilder.create().toJson(ImmutableMap.of("meetingid", meetingId))); + return WxCpGsonBuilder.create().fromJson(response, WxCpMeeting.class); + } + + @Override + public WxCpUserMeetingIdResult getUserMeetingIds(String userId, String cursor, Integer limit, + Long beginTime, Long endTime) throws WxErrorException { + final Map param = new HashMap<>(3); + param.put("userid", userId); + if (cursor != null) { + param.put("cursor", cursor); + } + if (limit != null) { + param.put("limit", limit); + } + if (limit != null) { + param.put("begin_time", beginTime); + } + if (limit != null) { + param.put("end_time", endTime); + } + final String response = this.cpService.post(this.cpService.getWxCpConfigStorage().getApiUrl(GET_USER_MEETING_ID), + WxCpGsonBuilder.create().toJson(param)); + return WxCpGsonBuilder.create().fromJson(response, WxCpUserMeetingIdResult.class); + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpMeeting.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpMeeting.java new file mode 100644 index 0000000000..0efbc5a772 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpMeeting.java @@ -0,0 +1,305 @@ +package me.chanjar.weixin.cp.bean.oa.meeting; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.experimental.Accessors; +import me.chanjar.weixin.common.bean.ToJson; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.io.Serializable; +import java.util.List; + +/** + * 会议信息bean. + * + * @author wangmeng3486 created on 2023-02-02 + */ +@Data +@Accessors(chain = true) +public class WxCpMeeting implements Serializable, ToJson { + private static final long serialVersionUID = 957588409099876012L; + + /** + * 会议id + */ + @SerializedName("meetingid") + private String meetingId; + /** + * 会议管理员userid + */ + @SerializedName("admin_userid") + private String adminUserId; + /** + * 会议的标题,最多支持40个字节或者20个utf8字符 + */ + @SerializedName("title") + private String title; + + /** + * 会议开始时间的unix时间戳。需大于当前时间 + */ + @SerializedName("meeting_start") + private Long meetingStart; + + /** + * 会议持续时间单位秒,最小300秒 + */ + @SerializedName("meeting_duration") + private Integer meetingDuration; + + /** + * 会议的描述,最多支持500个字节或者utf8字符 + */ + @SerializedName("description") + private String description; + + /** + * 会议地点,最多128个字符 + */ + @SerializedName("location") + private String location; + + /** + * 授权方安装的应用agentid。仅旧的第三方多应用套件需要填此参数 + */ + @SerializedName("agentid") + private Integer agentId; + + + /** + * 参与会议的成员。会议人数上限,以指定的「管理员」可预约的人数上限来校验,普通企业与会人员最多100; + * 付费企业根据企业选购的在线会议室容量。任何userid不合法或者不在应用可见范围,直接报错。 + */ + @SerializedName("attendees") + private Attendees attendees; + + + /** + * 会议所属日历ID。该日历必须是access_token所对应应用所创建的日历。 + * 注意,若参与人在日历分享范围内,则插入到该日历(同时会插入会议参与人的默认日历),若不在分享范围内,否则仅插入到参与者默认日历; + * 如果不填,那么插入到参与者的默认日历上。 + * 第三方应用必须指定cal_id + * 不多于64字节 + */ + @SerializedName("cal_id") + private String calId; + /** + * 会议配置 + */ + @SerializedName("settings") + private Setting settings; + + /** + * 重复会议相关配置 + */ + @SerializedName("reminders") + private Reminder reminders; + + @SerializedName("meeting_code") + private String meetingCode; + + @SerializedName("meeting_link") + private String meetingLink; + + @Override + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + /** + * The type Attendee. + */ + @Data + @Accessors(chain = true) + public static class Attendees implements Serializable { + private static final long serialVersionUID = 5419000348428480645L; + /** + * 会议参与者ID, + * 不多于64字节 + */ + @SerializedName("userid") + private List userId; + + @SerializedName("member") + private List member; + @SerializedName("tmp_external_user") + private List tmpExternalUser; + + /** + * 企业内部成员 + */ + @Data + @Accessors(chain = true) + public static class Member implements Serializable { + private static final long serialVersionUID = 1001531041411551854L; + /** + * 企业内部成员的userid + */ + @SerializedName("userid") + private String userid; + + /** + * 与会状态。1为已参与,2为未参与 + */ + @SerializedName("status") + private Integer status; + /** + * 参会人首次加入会议时间的unix时间戳 + */ + @SerializedName("first_join_time") + private Long firstJoinTime; + /** + * 参会人最后一次离开会议时间的unix时间戳 + */ + @SerializedName("last_quit_time") + private Long lastQuitTime; + /** + * 参会人累计参会时长,单位为秒 + */ + @SerializedName("cumulative_time") + private Long cumulativeTime; + + } + + /** + * 会中参会的外部联系人 + */ + @Data + @Accessors(chain = true) + public static class TmpExternalUser implements Serializable { + private static final long serialVersionUID = -1411758297144496040L; + /** + * 会中入会的外部用户临时id。同一个用户在不同会议中返回的该id不一致。 + */ + @SerializedName("tmp_external_userid") + private String tmpExternalUserid; + /** + * 参会人首次加入会议时间的unix时间戳 + */ + @SerializedName("first_join_time") + private Long firstJoinTime; + /** + * 参会人最后一次离开会议时间的unix时间戳 + */ + @SerializedName("last_quit_time") + private Long lastQuitTime; + + /** + * 参会人入会次数 + */ + @SerializedName("total_join_count") + private Integer totalJoinCount; + + /** + * 参会人累计参会时长,单位为秒 + */ + @SerializedName("cumulative_time") + private Integer cumulativeTime; + } + + } + + + /** + * The type Reminder. + */ + @Data + @Accessors(chain = true) + public static class Reminder implements Serializable { + private static final long serialVersionUID = -4097232428444045131L; + /** + * 是否是周期性会议,1:周期性会议 0:非周期性会议。默认为0 + */ + @SerializedName("is_repeat") + private Integer isRepeat; + /** + * 周期性会议重复类型,0.每天;1.每周;2.每月;7.每个工作日。默认为0。周期性会议该字段才生效 + */ + @SerializedName("repeat_type") + private Integer repeatType; + + /** + * 重复结束时刻。周期性会议该字段才生效。若会议结束时间超出最大结束时间或者未设置,则默认设置为最大结束时间。 + * 每天\每个工作日\每周 最多重复200次会议; + * 每两周\每月最多重复50次会议 + */ + @SerializedName("repeat_until") + private Long repeatUntil; + + /** + * 重复间隔 + * 仅当指定为自定义重复时有效 + * 目前仅当repeat_type为2时,即周期为周时,支持设置该字段,且值不能大于2。 + */ + @SerializedName("repeat_interval") + private Integer repeatInterval; + + /** + * 指定会议开始前多久提醒用户,相对于meeting_start前的秒数,默认不提醒。 + * 目前仅支持0:会议开始时提醒;300:5分钟前提醒;900:15分钟前提醒;3600:一小时前提醒;86400一天前提醒。 + * 若指定了非支持的值,则表现为会议开始时提醒 + */ + @SerializedName("remind_before") + private List remindBefore; + } + + + /** + * The Settings. + */ + @Data + @Accessors(chain = true) + public static class Setting implements Serializable { + private static final long serialVersionUID = 5030527150838243356L; + + /** + * 入会密码,仅可输入4-6位纯数字 + */ + @SerializedName("password") + private String password; + /** + * 是否开启等候室。true:开启等候室;false:不开启等候室;默认不开 + */ + @SerializedName("enable_waiting_room") + private boolean enableWaitingRoom; + /** + * 是否允许成员在主持人进会前加入。true:允许;false:不允许。默认允许 + */ + @SerializedName("allow_enter_before_host") + private boolean allowEnterBeforeHost; + /** + * 会议开始时来电提醒方式,1.不提醒 2.仅提醒主持人 3.提醒所有成员入 4.指定部分人响铃。默认仅提醒主持人 + */ + @SerializedName("remind_scope") + private Integer remindScope; + /** + * 成员入会时静音;1:开启;0:关闭;2:超过6人后自动开启静音。默认超过6人自动开启静音 + */ + @SerializedName("enable_enter_mute") + private Integer enableEnterMute; + + /** + * true:所有成员可入会;false:仅企业内部成员可入会 。默认所有成员可入会 + */ + @SerializedName("allow_external_user") + private boolean allowExternalUser; + + /** + * 是否开启屏幕水印,true:开启;false:不开启。默认不开启 + */ + @SerializedName("enable_screen_watermark") + private boolean enableScreenWatermark; + + /** + * 会议主持人人列表,主持人员最多10个。若包含ceaater_userid,会自动过滤。任何userid不合法,直接报错。 + */ + @SerializedName("hosts") + private Attendees hosts; + + /** + * 指定响铃的用户列表。如果remid_scope为4,但是ring_users为空,则全部成员均不响铃。 + */ + @SerializedName("ring_users") + private Attendees ringUsers; + } +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpMeetingUpdateResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpMeetingUpdateResult.java new file mode 100644 index 0000000000..dfd200f2a8 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpMeetingUpdateResult.java @@ -0,0 +1,41 @@ +package me.chanjar.weixin.cp.bean.oa.meeting; + +import com.google.common.base.Splitter; +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.cp.bean.WxCpBaseResp; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; +import org.apache.commons.lang3.StringUtils; + +import java.io.Serializable; +import java.util.Collections; +import java.util.List; + +/** + * 为标签添加或移除用户结果对象类. + * + * @author wangmeng3486 created on 2023-01-31 + */ +@Data +public class WxCpMeetingUpdateResult extends WxCpBaseResp implements Serializable { + private static final long serialVersionUID = -4993287594652231097L; + + @Override + public String toString() { + return WxCpGsonBuilder.create().toJson(this); + } + + /** + * From json wx cp tag add or remove users result. + * + * @param json the json + * @return the wx cp tag add or remove users result + */ + public static WxCpMeetingUpdateResult fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpMeetingUpdateResult.class); + } + + @SerializedName("excess_users") + private String[] excessUsers; + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpUserMeetingIdResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpUserMeetingIdResult.java new file mode 100644 index 0000000000..acdd47af0e --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpUserMeetingIdResult.java @@ -0,0 +1,40 @@ +package me.chanjar.weixin.cp.bean.oa.meeting; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.cp.bean.WxCpBaseResp; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.io.Serializable; + +/** + * 为标签添加或移除用户结果对象类. + * + * @author wangmeng3486 created on 2023-01-31 + */ +@Data +public class WxCpUserMeetingIdResult extends WxCpBaseResp implements Serializable { + private static final long serialVersionUID = -4993287594652231097L; + + @Override + public String toString() { + return WxCpGsonBuilder.create().toJson(this); + } + + /** + * From json wx cp tag add or remove users result. + * + * @param json the json + * @return the wx cp tag add or remove users result + */ + public static WxCpUserMeetingIdResult fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpUserMeetingIdResult.class); + } + + + @SerializedName("meetingid_list") + private String[] meetingIdList; + + @SerializedName("next_cursor") + private String nextCursor; +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java index 7baf48e719..c592682afa 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java @@ -374,6 +374,28 @@ interface Oa { /** * 会议 + * https://developer.work.weixin.qq.com/document/path/93626 + */ + String MEETING_ADD = "/cgi-bin/meeting/create"; + /** + * The constant MEETING_UPDATE. + */ + String MEETING_UPDATE = "/cgi-bin/meeting/update"; + /** + * The constant MEETING_CANCEL. + */ + String MEETING_CANCEL = "/cgi-bin/meeting/cancel"; + /** + * The constant MEETING_DETAIL. + */ + String MEETING_DETAIL = "/cgi-bin/meeting/get_info"; + /** + * The constant GET_USER_MEETING_ID. + */ + String GET_USER_MEETING_ID = "/cgi-bin/meeting/get_user_meetingid"; + + /** + * 会议室 * https://developer.work.weixin.qq.com/document/path/93624 */ String MEETINGROOM_ADD = "/cgi-bin/oa/meetingroom/add"; diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMeetingServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMeetingServiceImplTest.java new file mode 100644 index 0000000000..55ca45fc56 --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMeetingServiceImplTest.java @@ -0,0 +1,93 @@ +package me.chanjar.weixin.cp.api.impl; + +import com.google.inject.Inject; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.cp.api.ApiTestModule; +import me.chanjar.weixin.cp.api.WxCpMeetingService; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.bean.oa.meeting.WxCpMeeting; +import me.chanjar.weixin.cp.bean.oa.meeting.WxCpMeetingUpdateResult; +import me.chanjar.weixin.cp.bean.oa.meeting.WxCpUserMeetingIdResult; +import org.eclipse.jetty.util.ajax.JSON; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; +import org.testng.collections.Lists; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.testng.Assert.assertEquals; + + +/** + * 单元测试类. + * + * @author wangmeng3486 created on 2023-02-03 + */ +@Test +@Slf4j +@Guice(modules = ApiTestModule.class) +public class WxCpMeetingServiceImplTest { + /** + * The Wx service. + */ + @Inject + private WxCpService wxCpService; + /** + * The Config storage. + */ + @Inject + protected ApiTestModule.WxXmlCpInMemoryConfigStorage configStorage; + + /** + * Test + * + * @throws WxErrorException the wx error exception + */ + @Test + public void testAdd() throws WxErrorException { + WxCpMeetingService wxCpMeetingService = this.wxCpService.getMeetingService(); + /* + 测试 创建会议 + */ + long startTime = System.currentTimeMillis() / 1000 + 30 * 60L; + List userIds = Lists.newArrayList(this.configStorage.getUserId(), "lisi"); + WxCpMeeting wxCpMeeting = new WxCpMeeting().setAdminUserId(this.configStorage.getUserId()).setTitle("新建会议") + .setMeetingStart(startTime).setMeetingDuration(3600).setDescription("新建会议描述").setLocation("广州媒体港") + .setAttendees(new WxCpMeeting.Attendees().setUserId(userIds)) + .setSettings(new WxCpMeeting.Setting().setRemindScope(1).setPassword("1234").setEnableWaitingRoom(false) + .setAllowEnterBeforeHost(true).setEnableEnterMute(1).setAllowExternalUser(false).setEnableScreenWatermark(false) + .setHosts(new WxCpMeeting.Attendees().setUserId(userIds)).setRingUsers(new WxCpMeeting.Attendees().setUserId(userIds))) + .setReminders(new WxCpMeeting.Reminder().setIsRepeat(1).setRepeatType(0).setRepeatUntil(startTime + 24 * 60 * 60L) + .setRepeatInterval(1).setRemindBefore(Lists.newArrayList(0, 900))); + String meetingId = "hyXG0RCQAAogMgFb9Tx_b-1-lhJRWvvg";// wxCpMeetingService.create(wxCpMeeting); + assertThat(meetingId).isNotNull(); + /* + 测试 获取用户会议列表 + */ + wxCpMeeting.setMeetingId(meetingId); + WxCpUserMeetingIdResult wxCpUserMeetingIdResult = wxCpMeetingService.getUserMeetingIds(this.configStorage.getUserId(), null, null, startTime, null); + assertThat(wxCpUserMeetingIdResult.getMeetingIdList()).isNotNull(); + log.info("获取用户会议列表: {}", wxCpUserMeetingIdResult.toJson()); + /* + 测试 修改会议 + */ + wxCpMeeting.setTitle("修改会议"); + wxCpMeeting.setDescription("修改会议描述"); + WxCpMeetingUpdateResult wxCpMeetingUpdateResult = wxCpMeetingService.update(wxCpMeeting); + assertEquals(wxCpMeetingUpdateResult.getErrcode(), 0L); + /* + 测试 获取会议详情 + */ + WxCpMeeting wxCpMeetingResult = wxCpMeetingService.getDetail(meetingId); + log.info("获取会议详情: {}", wxCpMeetingResult.toJson()); + /* + 测试 取消会议 + */ + wxCpMeetingService.cancel(meetingId); + } +}