From c2d565459b6776aa5bc726483885629f563ce178 Mon Sep 17 00:00:00 2001 From: Jimmy Wu Date: Fri, 9 Oct 2020 13:52:18 +0800 Subject: [PATCH 1/9] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86=E5=A4=96?= =?UTF-8?q?=E9=83=A8=E8=81=94=E7=B3=BB=E4=BA=BA=E7=AE=A1=E7=90=86--?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AE=A1=E7=90=86=E7=9B=B8=E5=85=B3=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AdvancedAPIs/External/ExternalApi.cs | 170 ++++++++++++++++++ .../GetExternalContactInfoBatchResult.cs | 27 +++ .../GetExternalContactListResult.cs | 20 +++ .../UpdateExternalContactRemarkRequest.cs | 40 +++++ .../Senparc.Weixin.Work.csproj | 3 + 5 files changed, 260 insertions(+) create mode 100644 src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/GetExternalContactInfoBatchResult.cs create mode 100644 src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/GetExternalContactListResult.cs create mode 100644 src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/UpdateExternalContactRemarkRequest.cs diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalApi.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalApi.cs index e8d0f77b27..997b1d4974 100644 --- a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalApi.cs +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalApi.cs @@ -18,6 +18,7 @@ using Senparc.Weixin.CommonAPIs; using Senparc.Weixin.Entities; using Senparc.Weixin.Work.AdvancedAPIs.External; +using Senparc.Weixin.Work.AdvancedAPIs.External.ExternalJson; using System.Threading.Tasks; namespace Senparc.Weixin.Work.AdvancedAPIs @@ -74,6 +75,89 @@ public static GetExternalContactResultJson GetExternalContact(string accessToken } + #region 客户管理 + + /// + /// 获取客户列表 + /// + /// 调用接口凭证 + /// 企业成员的userid + /// + /// + [ApiBind(NeuChar.PlatformType.WeChat_Work, "ExternalApi.GetExternalContactList", true)] + public static GetExternalContactListResult GetExternalContactList(string accessTokenOrAppKey, string userid, int timeOut = Config.TIME_OUT) + { + return ApiHandlerWapper.TryCommonApi(accessToken => + { + var url = $"{Config.ApiWorkHost}/cgi-bin/externalcontact/list?access_token={accessToken}&userid={userid}"; + + return CommonJsonSend.Send(null, url, null, CommonJsonSendType.GET, timeOut); + }, accessTokenOrAppKey); + } + + /// + /// 获取客户详情 + /// + /// 调用接口凭证 + /// 外部联系人的userid,注意不是企业成员的帐号 + /// + /// + [ApiBind(NeuChar.PlatformType.WeChat_Work, "ExternalApi.GetExternalContactInfo", true)] + public static GetExternalContactResultJson GetExternalContactInfo(string accessTokenOrAppKey, string externalUserId, int timeOut = Config.TIME_OUT) + { + return ApiHandlerWapper.TryCommonApi(accessToken => + { + var url = $"{Config.ApiWorkHost}/cgi-bin/externalcontact/get?access_token={accessToken}&external_userid={externalUserId}"; + + return CommonJsonSend.Send(null, url, null, CommonJsonSendType.GET, timeOut); + }, accessTokenOrAppKey); + } + + /// + /// 批量获取客户详情 + /// + /// + /// + /// + /// + /// + [ApiBind(NeuChar.PlatformType.WeChat_Work, "ExternalApi.GetExternalContactInfoBatch", true)] + public static GetExternalContactInfoBatchResult GetExternalContactInfoBatch(string accessTokenOrAppKey, string userid, string cursor = "", int limit = 50, int timeOut = Config.TIME_OUT) + { + return ApiHandlerWapper.TryCommonApi(accessToken => + { + var url = $"{Config.ApiWorkHost}/cgi-bin/externalcontact/batch/get_by_user?access_token={accessToken}"; + + var data = new { + userid, + cursor, + limit + }; + + return CommonJsonSend.Send(null, url, data, CommonJsonSendType.POST, timeOut); + }, accessTokenOrAppKey); + } + + /// + /// 修改客户备注信息 + /// + /// 调用接口凭证 + /// 请求报文 + /// + /// + [ApiBind(NeuChar.PlatformType.WeChat_Work, "ExternalApi.UpdateExternalContactRemark", true)] + public static WorkJsonResult UpdateExternalContactRemark(string accessTokenOrAppKey, UpdateExternalContactRemarkRequest rquest, int timeOut = Config.TIME_OUT) + { + return ApiHandlerWapper.TryCommonApi(accessToken => + { + var url = $"{Config.ApiWorkHost}/cgi-bin/externalcontact/remark?access_token={accessToken}"; + + return CommonJsonSend.Send(null, url, rquest, CommonJsonSendType.POST, timeOut); + }, accessTokenOrAppKey); + } + + #endregion + #endregion @@ -124,6 +208,92 @@ public static async Task GetExternalContactAsync(s } + + #region 客户管理 + + /// + /// 【异步方法】获取客户列表 + /// + /// 调用接口凭证 + /// 企业成员的userid + /// + /// + [ApiBind(NeuChar.PlatformType.WeChat_Work, "ExternalApi.GetExternalContactListAsync", true)] + public static async Task GetExternalContactListAsync(string accessTokenOrAppKey, string userid, int timeOut = Config.TIME_OUT) + { + return await ApiHandlerWapper.TryCommonApiAsync(async accessToken => + { + var url = $"{Config.ApiWorkHost}/cgi-bin/externalcontact/list?access_token={accessToken}&userid={userid}"; + + return await CommonJsonSend.SendAsync(null, url, null, CommonJsonSendType.GET, timeOut).ConfigureAwait(false); + }, accessTokenOrAppKey).ConfigureAwait(false); + } + + /// + /// 【异步方法】获取客户详情 + /// + /// 调用接口凭证 + /// 外部联系人的userid,注意不是企业成员的帐号 + /// + /// + [ApiBind(NeuChar.PlatformType.WeChat_Work, "ExternalApi.GetExternalContactInfoAsync", true)] + public static async Task GetExternalContactInfoAsync(string accessTokenOrAppKey, string externalUserId, int timeOut = Config.TIME_OUT) + { + return await ApiHandlerWapper.TryCommonApiAsync(async accessToken => + { + var url = $"{Config.ApiWorkHost}/cgi-bin/externalcontact/get?access_token={accessToken}&external_userid={externalUserId}"; + + return await CommonJsonSend.SendAsync(null, url, null, CommonJsonSendType.GET, timeOut).ConfigureAwait(false); + }, accessTokenOrAppKey).ConfigureAwait(false); + } + + /// + /// 【异步方法】批量获取客户详情 + /// + /// + /// + /// + /// + /// + [ApiBind(NeuChar.PlatformType.WeChat_Work, "ExternalApi.GetExternalContactInfoBatchAsync", true)] + public static async Task GetExternalContactInfoBatchAsync(string accessTokenOrAppKey, string userid, string cursor = "", int limit = 50, int timeOut = Config.TIME_OUT) + { + return await ApiHandlerWapper.TryCommonApiAsync(async accessToken => + { + var url = $"{Config.ApiWorkHost}/cgi-bin/externalcontact/batch/get_by_user?access_token={accessToken}"; + + var data = new + { + userid, + cursor, + limit + }; + + return await CommonJsonSend.SendAsync(null, url, data, CommonJsonSendType.POST, timeOut).ConfigureAwait(false); + }, accessTokenOrAppKey).ConfigureAwait(false); + } + + /// + /// 修改客户备注信息 + /// + /// 调用接口凭证 + /// 请求报文 + /// + /// + [ApiBind(NeuChar.PlatformType.WeChat_Work, "ExternalApi.UpdateExternalContactRemarkAsync", true)] + public static async Task UpdateExternalContactRemarkAsync(string accessTokenOrAppKey, UpdateExternalContactRemarkRequest rquest, int timeOut = Config.TIME_OUT) + { + return await ApiHandlerWapper.TryCommonApiAsync(async accessToken => + { + var url = $"{Config.ApiWorkHost}/cgi-bin/externalcontact/remark?access_token={accessToken}"; + + return await CommonJsonSend.SendAsync(null, url, rquest, CommonJsonSendType.POST, timeOut).ConfigureAwait(false); + }, accessTokenOrAppKey).ConfigureAwait(false); + } + + #endregion + + #endregion } } diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/GetExternalContactInfoBatchResult.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/GetExternalContactInfoBatchResult.cs new file mode 100644 index 0000000000..98311bffca --- /dev/null +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/GetExternalContactInfoBatchResult.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Senparc.Weixin.Entities; + +namespace Senparc.Weixin.Work.AdvancedAPIs.External.ExternalJson +{ + public class GetExternalContactInfoBatchResult : WorkJsonResult + { + /// + /// + /// + public List external_contact_list { get; set; } + + /// + /// 分页游标,再下次请求时填写以获取之后分页的记录,如果已经没有更多的数据则返回空 + /// + public string next_cursor { get; set; } + } + + public class ExternalContactList + { + public GetExternalContactResultJson external_contact { get; set; } + } +} diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/GetExternalContactListResult.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/GetExternalContactListResult.cs new file mode 100644 index 0000000000..359874ac5e --- /dev/null +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/GetExternalContactListResult.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Senparc.Weixin.Entities; + +namespace Senparc.Weixin.Work.AdvancedAPIs.External.ExternalJson +{ + /// + /// 获取客户列表返回实体 + /// + public class GetExternalContactListResult : WorkJsonResult + { + /// + /// 外部联系人的userid列表 + /// + public List external_userid { get; set; } + } +} diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/UpdateExternalContactRemarkRequest.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/UpdateExternalContactRemarkRequest.cs new file mode 100644 index 0000000000..17fdcff8e3 --- /dev/null +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/UpdateExternalContactRemarkRequest.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Senparc.Weixin.Work.AdvancedAPIs.External.ExternalJson +{ + public class UpdateExternalContactRemarkRequest + { + /// + /// 企业成员的userid + /// + public string userid { get; set; } + /// + /// 外部联系人userid + /// + public string external_userid { get; set; } + /// + /// 此用户对外部联系人的备注,最多20个字符 + /// + public string remark { get; set; } + /// + /// 此用户对外部联系人的描述,最多150个字符 + /// + public string description { get; set; } + /// + /// 此用户对外部联系人备注的所属公司名称,最多20个字符 + /// + public string remark_company { get; set; } + /// + /// 此用户对外部联系人备注的手机号 + /// + public string[] remark_mobiles { get; set; } + /// + /// 备注图片的mediaid + /// + public string remark_pic_mediaid { get; set; } + } +} diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Senparc.Weixin.Work.csproj b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Senparc.Weixin.Work.csproj index 4a3dcaa8c5..1c551dfc5c 100644 --- a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Senparc.Weixin.Work.csproj +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Senparc.Weixin.Work.csproj @@ -82,6 +82,9 @@ + + + From 3dd0b0771bd287ac966c42a545e6c6ea9767242d Mon Sep 17 00:00:00 2001 From: Jimmy Wu Date: Fri, 9 Oct 2020 15:39:47 +0800 Subject: [PATCH 2/9] pull --- .../Senparc.Weixin.Work.Test.NetCore3.csproj | 32 ++ .../External/GroupChatGetResult.cs | 104 +++++++ .../External/GroupChatListParam.cs | 78 +++++ .../External/GroupChatListResult.cs | 61 ++++ .../AdvancedAPIs/Schedule/ScheduleApi.cs | 210 +++++++++++++ .../ScheduleJson/AddScheduleJsonResult.cs | 28 ++ .../ScheduleJson/GetScheduleJsonResult.cs | 89 ++++++ .../Schedule/ScheduleJson/Schedule.cs | 112 +++++++ .../RequestMessageEvent_ExternalContact.cs | 159 ++++++++++ .../RequestMessageEvent_External_Chat.cs | 31 ++ .../WorkResponseMessageUnknownType.cs | 59 ++++ .../Response/WorkSuccessResponseMessage.cs | 17 ++ .../DefaultWorkMessageContext.cs | 243 +++++++++++++++ .../Async/WorkMessageHandler.Async.cs | 79 +++++ .../Senparc.Weixin.Work.netcore3.csproj | 240 +++++++++++++++ .../Tencent/WXBizMsgCrypt.cs.bak.txt | 280 ++++++++++++++++++ 16 files changed, 1822 insertions(+) create mode 100644 src/Senparc.Weixin.Work/Senparc.Weixin.Work.Test/Senparc.Weixin.Work.Test.NetCore3.csproj create mode 100644 src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/GroupChatGetResult.cs create mode 100644 src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/GroupChatListParam.cs create mode 100644 src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/GroupChatListResult.cs create mode 100644 src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/Schedule/ScheduleApi.cs create mode 100644 src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/Schedule/ScheduleJson/AddScheduleJsonResult.cs create mode 100644 src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/Schedule/ScheduleJson/GetScheduleJsonResult.cs create mode 100644 src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/Schedule/ScheduleJson/Schedule.cs create mode 100644 src/Senparc.Weixin.Work/Senparc.Weixin.Work/Entities/Request/Event/RequestMessageEvent_ExternalContact.cs create mode 100644 src/Senparc.Weixin.Work/Senparc.Weixin.Work/Entities/Request/Event/RequestMessageEvent_External_Chat.cs create mode 100644 src/Senparc.Weixin.Work/Senparc.Weixin.Work/Entities/Response/WorkResponseMessageUnknownType.cs create mode 100644 src/Senparc.Weixin.Work/Senparc.Weixin.Work/Entities/Response/WorkSuccessResponseMessage.cs create mode 100644 src/Senparc.Weixin.Work/Senparc.Weixin.Work/MessageContext/DefaultWorkMessageContext.cs create mode 100644 src/Senparc.Weixin.Work/Senparc.Weixin.Work/MessageHandlers/Async/WorkMessageHandler.Async.cs create mode 100644 src/Senparc.Weixin.Work/Senparc.Weixin.Work/Senparc.Weixin.Work.netcore3.csproj create mode 100644 src/Senparc.Weixin.Work/Senparc.Weixin.Work/Tencent/WXBizMsgCrypt.cs.bak.txt diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work.Test/Senparc.Weixin.Work.Test.NetCore3.csproj b/src/Senparc.Weixin.Work/Senparc.Weixin.Work.Test/Senparc.Weixin.Work.Test.NetCore3.csproj new file mode 100644 index 0000000000..6e60c473f6 --- /dev/null +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work.Test/Senparc.Weixin.Work.Test.NetCore3.csproj @@ -0,0 +1,32 @@ + + + + netcoreapp3.1 + + false + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/GroupChatGetResult.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/GroupChatGetResult.cs new file mode 100644 index 0000000000..ebc455acff --- /dev/null +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/GroupChatGetResult.cs @@ -0,0 +1,104 @@ +#region Apache License Version 2.0 +/*---------------------------------------------------------------- + +Copyright 2020 Jeffrey Su & Suzhou Senparc Network Technology Co.,Ltd. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the +License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +either express or implied. See the License for the specific language governing permissions +and limitations under the License. + +Detail: https://github.com/JeffreySu/WeiXinMPSDK/blob/master/license.md + +----------------------------------------------------------------*/ +#endregion Apache License Version 2.0 + +/*---------------------------------------------------------------- + Copyright (C) 2020 Senparc + + 文件名:GroupChatGetResult.cs + 文件功能描述:获取客户群详情 返回结果 + + + 创建标识:lishewen - 20200318 +----------------------------------------------------------------*/ + + +using Senparc.Weixin.Entities; + +namespace Senparc.Weixin.Work.AdvancedAPIs.External +{ + /// + /// 获取客户群详情 返回结果 + /// + public class GroupChatGetResult : WorkJsonResult + { + /// + /// 客户群详情 + /// + public Group_Chat group_chat { get; set; } + } + /// + /// 客户群详情 + /// + public class Group_Chat + { + /// + /// 客户群ID + /// + public string chat_id { get; set; } + /// + /// 群名 + /// + public string name { get; set; } + /// + /// 群主ID + /// + public string owner { get; set; } + /// + /// 群的创建时间 + /// + public int create_time { get; set; } + /// + /// 群公告 + /// + public string notice { get; set; } + /// + /// 群成员列表 + /// + public Member_List[] member_list { get; set; } + } + /// + /// 群成员列表 + /// + public class Member_List + { + /// + /// 群成员id + /// + public string userid { get; set; } + /// + /// 成员类型。 + /// 1 - 企业成员 + /// 2 - 外部联系人 + /// + public int type { get; set; } + /// + /// 入群时间 + /// + public int join_time { get; set; } + /// + /// 入群方式。 + /// 1 - 由成员邀请入群(直接邀请入群) + /// 2 - 由成员邀请入群(通过邀请链接入群) + /// 3 - 通过扫描群二维码入群 + /// + public int join_scene { get; set; } + } + +} diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/GroupChatListParam.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/GroupChatListParam.cs new file mode 100644 index 0000000000..fbb1a59bdb --- /dev/null +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/GroupChatListParam.cs @@ -0,0 +1,78 @@ +#region Apache License Version 2.0 +/*---------------------------------------------------------------- + +Copyright 2020 Jeffrey Su & Suzhou Senparc Network Technology Co.,Ltd. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the +License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +either express or implied. See the License for the specific language governing permissions +and limitations under the License. + +Detail: https://github.com/JeffreySu/WeiXinMPSDK/blob/master/license.md + +----------------------------------------------------------------*/ +#endregion Apache License Version 2.0 + +/*---------------------------------------------------------------- + Copyright (C) 2020 Senparc + + 文件名:GroupChatListParam.cs + 文件功能描述:客户群列表查询参数 + + + 创建标识:lishewen - 20200318 +----------------------------------------------------------------*/ + +namespace Senparc.Weixin.Work.AdvancedAPIs.External +{ + /// + /// 群状态 + /// + public enum StatusFilter + { + 普通列表 = 0, + 离职待继承 = 1, + 离职继承中 = 2, + 离职继承完成 = 3 + } + /// + /// 客户群列表查询参数 + /// + public class GroupChatListParam + { + /// + /// 群状态过滤。 + /// + public StatusFilter status_filter { get; set; } = StatusFilter.普通列表; + /// + /// 群主过滤。如果不填,表示获取全部群主的数据 + /// + public Owner_Filter owner_filter { get; set; } + /// + /// 分页,偏移量 + /// + public int offset { get; set; } + /// + /// 分页,预期请求的数据量,取值范围 1 ~ 1000s + /// + public int limit { get; set; } + } + + public class Owner_Filter + { + /// + /// 用户ID列表。最多100个 + /// + public string[] userid_list { get; set; } + /// + /// 部门ID列表。最多100个 + /// + public int[] partyid_list { get; set; } + } + +} diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/GroupChatListResult.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/GroupChatListResult.cs new file mode 100644 index 0000000000..41e417eedb --- /dev/null +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/GroupChatListResult.cs @@ -0,0 +1,61 @@ +#region Apache License Version 2.0 +/*---------------------------------------------------------------- + +Copyright 2020 Jeffrey Su & Suzhou Senparc Network Technology Co.,Ltd. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the +License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +either express or implied. See the License for the specific language governing permissions +and limitations under the License. + +Detail: https://github.com/JeffreySu/WeiXinMPSDK/blob/master/license.md + +----------------------------------------------------------------*/ +#endregion Apache License Version 2.0 + +/*---------------------------------------------------------------- + Copyright (C) 2020 Senparc + + 文件名:GroupChatListResult.cs + 文件功能描述:获取客户群列表 返回结果 + + + 创建标识:lishewen - 20200318 +----------------------------------------------------------------*/ + +using Senparc.Weixin.Entities; + +namespace Senparc.Weixin.Work.AdvancedAPIs.External +{ + /// + /// 获取客户群列表 返回结果 + /// + public class GroupChatListResult : WorkJsonResult + { + /// + /// 客户群列表 + /// + public Group_Chat_List[] group_chat_list { get; set; } + } + + public class Group_Chat_List + { + /// + /// 客户群IDs + /// + public string chat_id { get; set; } + /// + /// 客户群状态。 + /// 0 - 正常 + /// 1 - 跟进人离职 + /// 2 - 离职继承中 + /// 3 - 离职继承完成 + /// + public int status { get; set; } + } +} diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/Schedule/ScheduleApi.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/Schedule/ScheduleApi.cs new file mode 100644 index 0000000000..0c78d13350 --- /dev/null +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/Schedule/ScheduleApi.cs @@ -0,0 +1,210 @@ +/*---------------------------------------------------------------- + Copyright (C) 2020 Senparc + + 文件名:ScheduleApi.cs + 文件功能描述:日程相关API + + + 创建标识:lishewen - 20191226 + +----------------------------------------------------------------*/ + +using Senparc.NeuChar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Senparc.Weixin.Work.AdvancedAPIs.Schedule.ScheduleJson; +using Senparc.Weixin.Entities; + +namespace Senparc.Weixin.Work.AdvancedAPIs.Schedule +{ + /// + /// 日程相关API + /// + public static class ScheduleApi + { + #region 同步方法 + /// + /// 创建日程(每个应用每天最多可创建1万个日程。) + /// + /// 接口调用凭证 + /// 日程信息 + /// + /// + [ApiBind(NeuChar.PlatformType.WeChat_Work, "ScheduleApi.Add", true)] + public static AddScheduleJsonResult Add(string accessTokenOrAppKey, ScheduleJson.Schedule schedule, int timeOut = Config.TIME_OUT) + { + return ApiHandlerWapper.TryCommonApi(accessToken => + { + var url = Config.ApiWorkHost + "/cgi-bin/oa/schedule/add?access_token={0}"; + + var data = new + { + schedule + }; + + return Senparc.Weixin.CommonAPIs.CommonJsonSend.Send(accessToken, url, data, CommonJsonSendType.POST, timeOut); + }, accessTokenOrAppKey); + } + /// + /// 更新日程(注意,更新日程,不可变更组织者) + /// + /// 接口调用凭证 + /// 日程信息 + /// + /// + [ApiBind(NeuChar.PlatformType.WeChat_Work, "ScheduleApi.Update", true)] + public static WorkJsonResult Update(string accessTokenOrAppKey, ScheduleUpdate schedule, int timeOut = Config.TIME_OUT) + { + return ApiHandlerWapper.TryCommonApi(accessToken => + { + var url = Config.ApiWorkHost + "/cgi-bin/oa/schedule/update?access_token={0}"; + + var data = new + { + schedule + }; + + return Senparc.Weixin.CommonAPIs.CommonJsonSend.Send(accessToken, url, data, CommonJsonSendType.POST, timeOut); + }, accessTokenOrAppKey); + } + /// + /// 取消日程 + /// + /// 接口调用凭证 + /// 日程ID + /// + /// + [ApiBind(NeuChar.PlatformType.WeChat_Work, "ScheduleApi.Del", true)] + public static WorkJsonResult Del(string accessTokenOrAppKey, string schedule_id, int timeOut = Config.TIME_OUT) + { + return ApiHandlerWapper.TryCommonApi(accessToken => + { + var url = Config.ApiWorkHost + "/cgi-bin/oa/schedule/del?access_token={0}"; + + var data = new + { + schedule_id + }; + + return Senparc.Weixin.CommonAPIs.CommonJsonSend.Send(accessToken, url, data, CommonJsonSendType.POST, timeOut); + }, accessTokenOrAppKey); + } + /// + /// 获取日程(注意,被取消的日程也可以拉取详情,调用者需要检查status) + /// + /// 接口调用凭证 + /// 日程ID列表。一次最多拉取1000条 + /// + /// + [ApiBind(NeuChar.PlatformType.WeChat_Work, "ScheduleApi.Get", true)] + public static GetScheduleJsonResult Get(string accessTokenOrAppKey, IEnumerable schedule_id_list, int timeOut = Config.TIME_OUT) + { + return ApiHandlerWapper.TryCommonApi(accessToken => + { + var url = Config.ApiWorkHost + "/cgi-bin/oa/schedule/get?access_token={0}"; + + var data = new + { + schedule_id_list + }; + + return Senparc.Weixin.CommonAPIs.CommonJsonSend.Send(accessToken, url, data, CommonJsonSendType.POST, timeOut); + }, accessTokenOrAppKey); + } + #endregion + + #region 异步方法 + /// + /// 创建日程(每个应用每天最多可创建1万个日程。) + /// + /// 接口调用凭证 + /// 日程信息 + /// + /// + [ApiBind(NeuChar.PlatformType.WeChat_Work, "ScheduleApi.AddAsync", true)] + public static async Task AddAsync(string accessTokenOrAppKey, ScheduleJson.Schedule schedule, int timeOut = Config.TIME_OUT) + { + return await ApiHandlerWapper.TryCommonApiAsync(async accessToken => + { + var url = Config.ApiWorkHost + "/cgi-bin/oa/schedule/add?access_token={0}"; + + var data = new + { + schedule + }; + + return await Weixin.CommonAPIs.CommonJsonSend.SendAsync(accessToken, url, data, CommonJsonSendType.POST, timeOut).ConfigureAwait(false); + }, accessTokenOrAppKey).ConfigureAwait(false); + } + /// + /// 更新日程(注意,更新日程,不可变更组织者) + /// + /// 接口调用凭证 + /// 日程信息 + /// + /// + [ApiBind(NeuChar.PlatformType.WeChat_Work, "ScheduleApi.UpdateAsync", true)] + public static async Task UpdateAsync(string accessTokenOrAppKey, ScheduleUpdate schedule, int timeOut = Config.TIME_OUT) + { + return await ApiHandlerWapper.TryCommonApiAsync(async accessToken => + { + var url = Config.ApiWorkHost + "/cgi-bin/oa/schedule/update?access_token={0}"; + + var data = new + { + schedule + }; + + return await Weixin.CommonAPIs.CommonJsonSend.SendAsync(accessToken, url, data, CommonJsonSendType.POST, timeOut).ConfigureAwait(false); + }, accessTokenOrAppKey).ConfigureAwait(false); + } + /// + /// 取消日程 + /// + /// 接口调用凭证 + /// 日程ID + /// + /// + [ApiBind(NeuChar.PlatformType.WeChat_Work, "ScheduleApi.DelAsync", true)] + public static async Task DelAsync(string accessTokenOrAppKey, string schedule_id, int timeOut = Config.TIME_OUT) + { + return await ApiHandlerWapper.TryCommonApiAsync(async accessToken => + { + var url = Config.ApiWorkHost + "/cgi-bin/oa/schedule/del?access_token={0}"; + + var data = new + { + schedule_id + }; + + return await Weixin.CommonAPIs.CommonJsonSend.SendAsync(accessToken, url, data, CommonJsonSendType.POST, timeOut).ConfigureAwait(false); + }, accessTokenOrAppKey).ConfigureAwait(false); + } + /// + /// 获取日程(注意,被取消的日程也可以拉取详情,调用者需要检查status) + /// + /// 接口调用凭证 + /// 日程ID列表。一次最多拉取1000条 + /// + /// + [ApiBind(NeuChar.PlatformType.WeChat_Work, "ScheduleApi.GetAsync", true)] + public static async Task GetAsync(string accessTokenOrAppKey, IEnumerable schedule_id_list, int timeOut = Config.TIME_OUT) + { + return await ApiHandlerWapper.TryCommonApiAsync(async accessToken => + { + var url = Config.ApiWorkHost + "/cgi-bin/oa/schedule/get?access_token={0}"; + + var data = new + { + schedule_id_list + }; + + return await Weixin.CommonAPIs.CommonJsonSend.SendAsync(accessToken, url, data, CommonJsonSendType.POST, timeOut).ConfigureAwait(false); + }, accessTokenOrAppKey).ConfigureAwait(false); + } + #endregion + } +} diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/Schedule/ScheduleJson/AddScheduleJsonResult.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/Schedule/ScheduleJson/AddScheduleJsonResult.cs new file mode 100644 index 0000000000..906341c1d5 --- /dev/null +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/Schedule/ScheduleJson/AddScheduleJsonResult.cs @@ -0,0 +1,28 @@ +/*---------------------------------------------------------------- + Copyright (C) 2020 Senparc + + 文件名:AddScheduleJsonResult.cs + 文件功能描述:创建日程接口返回参数 + + + 创建标识:lishewen - 20191226 + +----------------------------------------------------------------*/ + +using Senparc.Weixin.Entities; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Senparc.Weixin.Work.AdvancedAPIs.Schedule.ScheduleJson +{ + public class AddScheduleJsonResult : WorkJsonResult + { + /// + /// 日程ID + /// + public string schedule_id { get; set; } + } +} diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/Schedule/ScheduleJson/GetScheduleJsonResult.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/Schedule/ScheduleJson/GetScheduleJsonResult.cs new file mode 100644 index 0000000000..a123654086 --- /dev/null +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/Schedule/ScheduleJson/GetScheduleJsonResult.cs @@ -0,0 +1,89 @@ +/*---------------------------------------------------------------- + Copyright (C) 2020 Senparc + + 文件名:GetScheduleJsonResult.cs + 文件功能描述:获取日程接口返回参数 + + + 创建标识:lishewen - 20191226 + +----------------------------------------------------------------*/ + +using Senparc.Weixin.Entities; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Senparc.Weixin.Work.AdvancedAPIs.Schedule.ScheduleJson +{ + public enum Response_Status + { + 未处理 = 0, + 待定 = 1, + 全部接受 = 2, + 仅接受一次 = 3, + 拒绝 = 4 + } + /// + /// 注意,被取消的日程也可以拉取详情,调用者需要检查status + /// + public class GetScheduleJsonResult : WorkJsonResult + { + /// + /// 日程列表 + /// + public IEnumerable schedule_list { get; set; } + } + + public class Schedule_Item + { + /// + /// 日程ID + /// + public string schedule_id { get; set; } + /// + /// 组织者 + /// + public string organizer { get; set; } + /// + /// 日程参与者列表。最多支持2000人 + /// + public IEnumerable attendees { get; set; } + /// + /// 日程标题。0 ~ 128 字符。不填会默认显示为“新建事件” + /// + public string summary { get; set; } + /// + /// 日程描述。0 ~ 512 字符 + /// + public string description { get; set; } + /// + /// 提醒相关信息 + /// + public Reminders reminders { get; set; } + /// + /// 日程地址。0 ~ 128 字符 + /// + public string location { get; set; } + /// + /// 日程开始时间,Unix时间戳 + /// + public int start_time { get; set; } + /// + /// 日程结束时间,Unix时间戳 + /// + public int end_time { get; set; } + /// + /// 日程状态。0-正常;1-已取消 + /// + public int status { get; set; } + } + + public class AttendeeResult : Attendee + { + public Response_Status response_status { get; set; } + } + +} diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/Schedule/ScheduleJson/Schedule.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/Schedule/ScheduleJson/Schedule.cs new file mode 100644 index 0000000000..d7fa3c7078 --- /dev/null +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/Schedule/ScheduleJson/Schedule.cs @@ -0,0 +1,112 @@ +/*---------------------------------------------------------------- + Copyright (C) 2020 Senparc + + 文件名:Schedule.cs + 文件功能描述:日程信息 + + + 创建标识:lishewen - 20191226 + +----------------------------------------------------------------*/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Senparc.Weixin.Work.AdvancedAPIs.Schedule.ScheduleJson +{ + public enum Remind_Before_Event_Secs + { + 事件开始时 = 0, + 五分钟 = 300, + 十五分钟 = 900, + 一小时 = 3600, + 一天 = 86400 + } + public enum Repeat_Type + { + 每日 = 0, + 每周 = 1, + 每月 = 2, + 每年 = 5, + 工作日 = 7 + } + /// + /// 日程信息 + /// + public class Schedule + { + /// + /// 组织者 + /// + public string organizer { get; set; } + /// + /// 日程开始时间,Unix时间戳 + /// + public int start_time { get; set; } + /// + /// 日程结束时间,Unix时间戳 + /// + public int end_time { get; set; } + /// + /// 日程参与者列表。最多支持2000人 + /// + public IEnumerable attendees { get; set; } + /// + /// 日程标题。0 ~ 128 字符。不填会默认显示为“新建事件” + /// + public string summary { get; set; } + /// + /// 日程描述。0 ~ 512 字符 + /// + public string description { get; set; } + /// + /// 提醒相关信息 + /// + public Reminders reminders { get; set; } + /// + /// 日程地址。0 ~ 128 字符 + /// + public string location { get; set; } + } + + public class Reminders + { + /// + /// 是否需要提醒。0-否;1-是 + /// + public int is_remind { get; set; } + /// + /// 日程开始(start_time)前多少秒提醒,当is_remind为1时有效。例如: 300表示日程开始前5分钟提醒。 + /// + public Remind_Before_Event_Secs remind_before_event_secs { get; set; } + /// + /// 是否重复日程。0-否;1-是 + /// + public int is_repeat { get; set; } + /// + /// 重复类型,当is_repeat为1时有效。 + /// + public Repeat_Type repeat_type { get; set; } + } + + public class Attendee + { + /// + /// 日程参与者ID + /// + public string userid { get; set; } + } + /// + /// 注意,更新日程,不可变更组织者 + /// + public class ScheduleUpdate : Schedule + { + /// + /// 日程ID + /// + public string schedule_id { get; set; } + } +} diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Entities/Request/Event/RequestMessageEvent_ExternalContact.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Entities/Request/Event/RequestMessageEvent_ExternalContact.cs new file mode 100644 index 0000000000..9e4dca8780 --- /dev/null +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Entities/Request/Event/RequestMessageEvent_ExternalContact.cs @@ -0,0 +1,159 @@ +/*---------------------------------------------------------------- + Copyright (C) 2020 Senparc + + 文件名:RequestMessageEvent_Change_ExternalContact.cs + 文件功能描述:上报企业客户变更事件 + + + 创建标识:OrchesAdam - 2019119 + + 修改标识:Senparc - 20191226 + 修改描述:整理格式,添加注释,分配版本号:v3.7.104.2 添加“上报企业客户变更事件” + + 修改标识:OrchesAdam - 20200430 + 修改描述:v3.7.502 添加编辑企业客户事件 + +----------------------------------------------------------------*/ + +namespace Senparc.Weixin.Work.Entities.Request.Event +{ + /// + /// 上报企业客户变更事件 + /// + public interface IRequestMessageEvent_Change_ExternalContact_Base : IRequestMessageEventBase + { + ExternalContactChangeType ChangeType + { + get; + } + } + + public class RequestMessageEvent_Change_ExternalContact_Base : RequestMessageEventBase, IRequestMessageEvent_Change_ExternalContact_Base + { + public override Work.Event Event + { + get { return Work.Event.CHANGE_EXTERNAL_CONTACT; } + } + public virtual ExternalContactChangeType ChangeType + { + get { return ExternalContactChangeType.add_external_contact; } + } + } + + /// + /// 添加企业客户事件 + /// + public class RequestMessageEvent_Change_ExternalContact_Add : RequestMessageEvent_Change_ExternalContact_Base + { + /// + /// 企业服务人员的UserID + /// + public string UserID { get; set; } + /// + /// 外部联系人的userid + /// + public string ExternalUserID { get; set; } + /// + /// 添加此用户的「联系我」方式配置的state参数,可用于识别添加此用户的渠道 + /// + public string State { get; set; } + /// + /// 欢迎语code,可用于发送欢迎语 + /// + public string WelcomeCode { get; set; } + } + + /// + /// 编辑企业客户事件 + /// + public class RequestMessageEvent_Change_ExternalContact_Modified : RequestMessageEvent_Change_ExternalContact_Base + { + public override ExternalContactChangeType ChangeType => ExternalContactChangeType.edit_external_contact; + + /// + /// 企业服务人员的UserID + /// + public string UserID { get; set; } + /// + /// 外部联系人的userid,注意不是企业成员的帐号 + /// + public string ExternalUserID { get; set; } + /// + /// 添加此用户的「联系我」方式配置的state参数,可用于识别添加此用户的渠道 + /// + public string State { get; set; } + } + + /// + /// 外部联系人免验证添加成员事件 + /// + public class RequestMessageEvent_Change_ExternalContact_Add_Half : RequestMessageEvent_Change_ExternalContact_Add + { + public override ExternalContactChangeType ChangeType => ExternalContactChangeType.add_half_external_contact; + } + + /// + /// 删除跟进成员事件 + /// + public class RequestMessageEvent_Change_ExternalContact_Del : RequestMessageEvent_Change_ExternalContact_Base + { + public override ExternalContactChangeType ChangeType => ExternalContactChangeType.del_external_contact; + + /// + /// 企业服务人员的UserID + /// + public string UserID { get; set; } + /// + /// 外部联系人的userid + /// + public string ExternalUserID { get; set; } + } + + /// + /// 删除跟进成员事件 + /// + public class RequestMessageEvent_Change_ExternalContact_Del_FollowUser : RequestMessageEvent_Change_ExternalContact_Del + { + public override ExternalContactChangeType ChangeType => ExternalContactChangeType.del_follow_user; + } + + /// + /// 客户同意进行聊天内容存档(灰度) + /// + public class RequestMessageEvent_Change_ExternalContact_MsgAudit : RequestMessageEvent_Change_ExternalContact_Add + { + public override ExternalContactChangeType ChangeType => ExternalContactChangeType.msg_audit_approved; + } + + + /// + /// 企业客户(外部联系人)变更事件 + /// + public enum ExternalContactChangeType + { + /// + /// 添加企业客户事件 + /// + add_external_contact, + /// + /// 外部联系人免验证添加成员事件 + /// + add_half_external_contact, + /// + /// 编辑企业客户事件 + /// + edit_external_contact, + /// + /// 删除企业客户事件 + /// + del_external_contact, + /// + /// 删除跟进成员事件 + /// + del_follow_user, + /// + /// 客户同意进行聊天内容存档事件回调(此功能仍在灰度) + /// + msg_audit_approved + } +} diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Entities/Request/Event/RequestMessageEvent_External_Chat.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Entities/Request/Event/RequestMessageEvent_External_Chat.cs new file mode 100644 index 0000000000..366b88e318 --- /dev/null +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Entities/Request/Event/RequestMessageEvent_External_Chat.cs @@ -0,0 +1,31 @@ +/*---------------------------------------------------------------- + Copyright (C) 2020 Senparc + + 文件名:RequestMessageEvent_Location.cs + 文件功能描述:事件之上报地理位置事件 + + + 创建标识:Senparc - 20150313 + + 修改标识:Senparc - 20150313 + 修改描述:整理接口 +----------------------------------------------------------------*/ + +namespace Senparc.Weixin.Work.Entities +{ + /// + /// 客户群变更事件 + /// + public class RequestMessageEvent_Change_External_Chat : RequestMessageEventBase, IRequestMessageEventBase + { + public override Event Event + { + get { return Event.CHANGE_EXTERNAL_CHAT; } + } + + /// + /// 群ID + /// + public string ChatId { get; set; } + } +} diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Entities/Response/WorkResponseMessageUnknownType.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Entities/Response/WorkResponseMessageUnknownType.cs new file mode 100644 index 0000000000..1aac76ffc3 --- /dev/null +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Entities/Response/WorkResponseMessageUnknownType.cs @@ -0,0 +1,59 @@ +#region Apache License Version 2.0 +/*---------------------------------------------------------------- + +Copyright 2018 Suzhou Senparc Network Technology Co.,Ltd. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the +License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +either express or implied. See the License for the specific language governing permissions +and limitations under the License. + +Detail: https://github.com/JeffreySu/WeiXinMPSDK/blob/master/license.md + +----------------------------------------------------------------*/ +#endregion Apache License Version 2.0 + +/*---------------------------------------------------------------- + Copyright (C) 2018 Senparc + + 文件名:WorkResponseMessageUnknownType.cs + 文件功能描述:企业号未知响应类型 + + + 创建标识:Senparc - 20190916 + +----------------------------------------------------------------*/ + + +using Senparc.NeuChar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace Senparc.Weixin.Work.Entities.Response +{ + /// + /// 企业号未知响应类型 + /// + public class WorkResponseMessageUnknownType : WorkResponseMessageBase, IWorkResponseMessageBase + { + public override ResponseMsgType MsgType + { + get { return ResponseMsgType.Unknown; } + } + + /// + /// 响应消息的XML对象(明文) + /// + public XDocument ResponseDocument { get; set; } + + } +} diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Entities/Response/WorkSuccessResponseMessage.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Entities/Response/WorkSuccessResponseMessage.cs new file mode 100644 index 0000000000..2508e7570d --- /dev/null +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Entities/Response/WorkSuccessResponseMessage.cs @@ -0,0 +1,17 @@ +using Senparc.NeuChar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Senparc.Weixin.Work.Entities +{ + public class WorkSuccessResponseMessage : WorkResponseMessageBase + { + public override ResponseMsgType MsgType + { + get { return ResponseMsgType.SuccessResponse; } + } + } +} diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/MessageContext/DefaultWorkMessageContext.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/MessageContext/DefaultWorkMessageContext.cs new file mode 100644 index 0000000000..c8a47c33d4 --- /dev/null +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/MessageContext/DefaultWorkMessageContext.cs @@ -0,0 +1,243 @@ +/*---------------------------------------------------------------- + Copyright (C) 2020 Senparc + + 文件名:DefaultWorkMessageContext.cs + 文件功能描述:企业微信上下文的默认实现 + + + 创建标识:Senparc - 20190915 + + 修改标识:OrchesAdam - 2019119 + 修改描述:v3.7.104.2 添加“上报企业客户变更事件” + + 修改标识:OrchesAdam - 20200430 + 修改描述:v3.7.502 添加企业内部开发外部联系人 + + 修改标识:jiehanlin - 20200430 + 修改描述:v3.7.502 添加客户群变更事件推送(CHANGE_EXTERNAL_CHAT) + +----------------------------------------------------------------*/ + +using Senparc.NeuChar; +using Senparc.NeuChar.Context; +using Senparc.NeuChar.Entities; +using Senparc.NeuChar.Exceptions; +using Senparc.Weixin.Work.Entities; +using Senparc.Weixin.Work.Entities.Response; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; +using Senparc.Weixin.Work.Entities.Request.Event; + +namespace Senparc.Weixin.Work.MessageContexts +{ + /// + /// 企业号上下文消息的默认实现 + /// + public class DefaultWorkMessageContext + : MessageContext, IMessageContext + { + + /// + /// 获取请求消息和实体之间的映射结果 + /// + /// + /// + public override IWorkRequestMessageBase GetRequestEntityMappingResult(RequestMsgType requestMsgType, XDocument doc = null) + { + IWorkRequestMessageBase requestMessage; + switch (requestMsgType) + { + case RequestMsgType.Text: + requestMessage = new RequestMessageText(); + break; + case RequestMsgType.Location: + requestMessage = new RequestMessageLocation(); + break; + case RequestMsgType.Image: + requestMessage = new RequestMessageImage(); + break; + case RequestMsgType.Voice: + requestMessage = new RequestMessageVoice(); + break; + case RequestMsgType.Video: + requestMessage = new RequestMessageVideo(); + break; + case RequestMsgType.ShortVideo: + requestMessage = new RequestMessageShortVideo(); + break; + case RequestMsgType.File: + requestMessage = new RequestMessageFile(); + break; + case RequestMsgType.Event: + //判断Event类型 + switch (doc.Root.Element("Event").Value.ToUpper()) + { + case "CLICK"://菜单点击 + requestMessage = new RequestMessageEvent_Click(); + break; + case "VIEW"://URL跳转 + requestMessage = new RequestMessageEvent_View(); + break; + case "SUBSCRIBE"://订阅(关注) + requestMessage = new RequestMessageEvent_Subscribe(); + break; + case "UNSUBSCRIBE"://取消订阅(关注) + requestMessage = new RequestMessageEvent_UnSubscribe(); + break; + case "SCANCODE_PUSH"://扫码推事件(scancode_push) + requestMessage = new RequestMessageEvent_Scancode_Push(); + break; + case "SCANCODE_WAITMSG"://扫码推事件且弹出“消息接收中”提示框(scancode_waitmsg) + requestMessage = new RequestMessageEvent_Scancode_Waitmsg(); + break; + case "PIC_SYSPHOTO"://弹出系统拍照发图(pic_sysphoto) + requestMessage = new RequestMessageEvent_Pic_Sysphoto(); + break; + case "PIC_PHOTO_OR_ALBUM"://弹出拍照或者相册发图(pic_photo_or_album) + requestMessage = new RequestMessageEvent_Pic_Photo_Or_Album(); + break; + case "PIC_WEIXIN"://弹出微信相册发图器(pic_weixin) + requestMessage = new RequestMessageEvent_Pic_Weixin(); + break; + case "LOCATION_SELECT"://弹出地理位置选择器(location_select) + requestMessage = new RequestMessageEvent_Location_Select(); + break; + case "LOCATION"://上报地理位置事件(location) + requestMessage = new RequestMessageEvent_Location(); + break; + case "ENTER_AGENT"://用户进入应用的事件推送(enter_agent) + requestMessage = new RequestMessageEvent_Enter_Agent(); + break; + case "BATCH_JOB_RESULT"://异步任务完成事件推送(batch_job_result) + requestMessage = new RequestMessageEvent_Batch_Job_Result(); + break; + case "CHANGE_CONTACT"://通讯录更改推送(change_contact) + switch (doc.Root.Element("ChangeType").Value.ToUpper()) + { + case "CREATE_USER": + requestMessage = new RequestMessageEvent_Change_Contact_User_Create(); + break; + case "UPDATE_USER": + requestMessage = new RequestMessageEvent_Change_Contact_User_Update(); + break; + case "DELETE_USER": + requestMessage = new RequestMessageEvent_Change_Contact_User_Base(); + break; + case "CREATE_PARTY": + requestMessage = new RequestMessageEvent_Change_Contact_Party_Create(); + break; + case "UPDATE_PARTY": + requestMessage = new RequestMessageEvent_Change_Contact_Party_Update(); + break; + case "DELETE_PARTY": + requestMessage = new RequestMessageEvent_Change_Contact_Party_Base(); + break; + case "UPDATE_TAG": + requestMessage = new RequestMessageEvent_Change_Contact_Tag_Update(); + break; + default://其他意外类型(也可以选择抛出异常) + requestMessage = new RequestMessageEventBase(); + break; + } + break; + case "CHANGE_EXTERNAL_CONTACT"://客户变更回调 + switch (doc.Root.Element("ChangeType").Value.ToUpper()) + { + case "ADD_EXTERNAL_CONTACT": + requestMessage = new RequestMessageEvent_Change_ExternalContact_Add(); + break; + case "ADD_HALF_EXTERNAL_CONTACT": + requestMessage = new RequestMessageEvent_Change_ExternalContact_Add_Half(); + break; + case "EDIT_EXTERNAL_CONTACT": + requestMessage = new RequestMessageEvent_Change_ExternalContact_Modified(); + break; + case "DEL_EXTERNAL_CONTACT": + requestMessage = new RequestMessageEvent_Change_ExternalContact_Del(); + break; + case "DEL_FOLLOW_USER": + requestMessage = new RequestMessageEvent_Change_ExternalContact_Del_FollowUser(); + break; + case "MSG_AUDIT_APPROVED": + requestMessage = new RequestMessageEvent_Change_ExternalContact_MsgAudit(); + break; + default: + requestMessage = new RequestMessageEventBase(); + break; + } + break; + case "CHANGE_EXTERNAL_CHAT"://客户群变更事件推送 + requestMessage = new RequestMessageEvent_Change_External_Chat(); + break; + default://其他意外类型(也可以选择抛出异常) + requestMessage = new RequestMessageEventBase(); + break; + } + break; + default: + throw new UnknownRequestMsgTypeException(string.Format("MsgType:{0} 在RequestMessageFactory中没有对应的处理程序!", requestMsgType), new ArgumentOutOfRangeException());//为了能够对类型变动最大程度容错(如微信目前还可以对公众账号suscribe等未知类型,但API没有开放),建议在使用的时候catch这个异常 + } + return requestMessage; + } + + /// + /// 获取响应消息和实体之间的映射结果 + /// + /// + /// + public override IWorkResponseMessageBase GetResponseEntityMappingResult(ResponseMsgType responseMsgType, XDocument doc = null) + { + IWorkResponseMessageBase responseMessage; + switch (responseMsgType) + { + case ResponseMsgType.Text: + responseMessage = new ResponseMessageText(); + break; + case ResponseMsgType.News: + responseMessage = new ResponseMessageNews(); + break; + case ResponseMsgType.Image: + responseMessage = new ResponseMessageImage(); + break; + case ResponseMsgType.Voice: + responseMessage = new ResponseMessageVoice(); + break; + case ResponseMsgType.Video: + responseMessage = new ResponseMessageVideo(); + break; + case ResponseMsgType.NoResponse: + responseMessage = new WorkResponseMessageNoResponse(); + break; + case ResponseMsgType.SuccessResponse: + responseMessage = new WorkSuccessResponseMessage(); + break; + + #region 不支持 + case ResponseMsgType.Transfer_Customer_Service: + case ResponseMsgType.Music: + #endregion + + #region 扩展类型 + case ResponseMsgType.MultipleNews: + case ResponseMsgType.LocationMessage: + case ResponseMsgType.UseApi: + #endregion + + case ResponseMsgType.Other: + case ResponseMsgType.Unknown: + default: + responseMessage = new WorkResponseMessageUnknownType() + { + ResponseDocument = doc + }; + break; + } + return responseMessage; + + } + } +} diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/MessageHandlers/Async/WorkMessageHandler.Async.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/MessageHandlers/Async/WorkMessageHandler.Async.cs new file mode 100644 index 0000000000..3fa0b3532c --- /dev/null +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/MessageHandlers/Async/WorkMessageHandler.Async.cs @@ -0,0 +1,79 @@ +using System; +using System.IO; +using System.Xml.Linq; +using Senparc.NeuChar.Context; +using Senparc.Weixin.Exceptions; +using Senparc.NeuChar.MessageHandlers; +using Senparc.Weixin.Work.Entities; +using Senparc.Weixin.Work.Helpers; +using Senparc.Weixin.Work.Tencent; +using Senparc.NeuChar; +using Senparc.NeuChar.ApiHandlers; +using Senparc.Weixin.Work.AdvancedAPIs; +using System.Threading.Tasks; +using System.Threading; + +namespace Senparc.Weixin.Work.MessageHandlers +{ + public abstract partial class WorkMessageHandler + : MessageHandler, IWorkMessageHandler + where TMC : class, IMessageContext, new() + { + + public override async Task BuildResponseMessageAsync(CancellationToken cancellationToken) + { + //TODO:改写为调用异步方法 + + switch (RequestMessage.MsgType) + { + case RequestMsgType.Unknown://第三方回调 + { + if (RequestMessage is IThirdPartyInfoBase) + { + var thirdPartyInfo = RequestMessage as IThirdPartyInfoBase; + TextResponseMessage = OnThirdPartyEvent(thirdPartyInfo); + } + else + { + throw new WeixinException("没有找到合适的消息类型。"); + } + } + break; + //以下是普通信息 + case RequestMsgType.Text: + { + var requestMessage = RequestMessage as RequestMessageText; + ResponseMessage = OnTextOrEventRequest(requestMessage) ?? OnTextRequest(requestMessage); + } + break; + case RequestMsgType.Location: + ResponseMessage = OnLocationRequest(RequestMessage as RequestMessageLocation); + break; + case RequestMsgType.Image: + ResponseMessage = OnImageRequest(RequestMessage as RequestMessageImage); + break; + case RequestMsgType.Voice: + ResponseMessage = OnVoiceRequest(RequestMessage as RequestMessageVoice); + break; + case RequestMsgType.Video: + ResponseMessage = OnVideoRequest(RequestMessage as RequestMessageVideo); + break; + case RequestMsgType.ShortVideo: + ResponseMessage = OnShortVideoRequest(RequestMessage as RequestMessageShortVideo); + break; + case RequestMsgType.File: + ResponseMessage = OnFileRequest(RequestMessage as RequestMessageFile); + break; + case RequestMsgType.Event: + { + var requestMessageText = (RequestMessage as IRequestMessageEventBase).ConvertToRequestMessageText(); + ResponseMessage = OnTextOrEventRequest(requestMessageText) ?? OnEventRequest(RequestMessage as IRequestMessageEventBase); + } + break; + default: + throw new UnknownRequestMsgTypeException("未知的MsgType请求类型", null); + } + } + + } +} diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Senparc.Weixin.Work.netcore3.csproj b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Senparc.Weixin.Work.netcore3.csproj new file mode 100644 index 0000000000..a85f4193c6 --- /dev/null +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Senparc.Weixin.Work.netcore3.csproj @@ -0,0 +1,240 @@ + + + net45;netstandard2.0;netstandard2.1 + $(Net35FrameworkPathOverride) + 3.7.603 + Senparc.Weixin.Work + Senparc.Weixin.Work + true + + 微信公众账号 - 企业微信 模块 + + Senparc.Weixin SDK 开源项目: + https://github.com/JeffreySu/WeiXinMPSDK + + Senparc Copyright © 2004~2020 + 微信,weixin,公众号,企业微信,WeChat,Senparc,盛派,SDK,C#,JSSDK,微信支付,分布式,小程序,企业号 + Jeffrey Su + Senparc + https://github.com/JeffreySu/WeiXinMPSDK/blob/master/license.md + https://github.com/JeffreySu/WeiXinMPSDK + Senparc.Weixin.Work.dll + 微信公众号SDK for C# + https://github.com/JeffreySu/WeiXinMPSDK + http://sdk.weixin.senparc.com/Images/Logo.jpg + + v0.1.0 完成从Senparc.Weixin.Work.dll的初步移植,添加Work(企业微信)中的新接口 + + v0.2.0 1、整理类名,MessageHandler跑通 + 2、整理类名,MessageHandler跑通 + + v0.3.0 AccessTokenResult 加入 IAccessTokenResult 接口 + v0.3.1 修复OaDataOpenApi接口AccessToken传递问题 + v0.3.2 修复Senparc.Weixin.QY.AdvancedAPIs.MassApi中,因为accessToken为null而导致消息发送失败的问题 + v0.3.3 为Tencent命名空间添加Senparc.Weixin.Work前缀 + + v0.4.0 支持 .NET Core 2.0 + v0.4.1 更新MailListApi.GetDepartmentMemberInfo()参数 + v0.4.2 添加 GetMemberResult.order 属性 + + v1.0.0 发布正式版 + v1.0.1 完善GetUserInfoResult属性 + v1.1.0 添加 OAuth2Api.GetUserDetail()方法 + v1.1.1 GetCheckinDataJsonResult_Result 添加 mediaids 属性(打卡的附件media_id,可使用media/get获取附件) + v1.1.2 GetCheckinDataJsonResult 修改 checkindata 属性名称 + v1.1.3 添加发送textcard消息方法:MassApi.SendTextCard() + + v1.2.0-beta1 支持 .NET 3.5/4.0 + v1.2.0-beta2 部门id改为long类型 + v1.2.2 支持Senparc.Weixin v4.18.0,支持Ajax模拟请求 + v1.2.3 GetDepartmentListResult.order改为long类型 + v1.2.4 支持Senparc.Weixin v4.18.5 可自定义API域名 + v1.2.5 支持Senparc.Weixin v4.18.6 修复自定义API域名问题 + v1.2.6 修复 AccessTokenResult 请求地址路径不完整的问题 + v1.2.7 修正GetMenu()方法返回菜单内容为始终为NULL的问题 + v1.2.8 还原“修复 AccessTokenResult 请求地址路径不完整的问题” + v1.2.9 为OAuth Url添加agendId参数(可选) + v1.2.10 修改 AddTagMemberResult.invalidparty 为 long 类型 + v1.2.11 更改OAuth Url添加agendId参数为小写:agentid + v1.2.12 添加【获取打卡规则】接口 + v1.2.13 调整“获取应用”接口,重新释放allow_tags属性。 + v1.2.14 MessageHandler添加对文件类型消息的处理 + + v1.3.0 停止对 .net core 1.1 生成的独立版本 + v1.3.1 提供 RegisterServices 进行快捷注册 + + v1.4.0 新增企业微信群聊会话功能支持 + v1.4.1 增加“接收通讯录变更事件” + v1.4.2 修改 AsynchronousReplaceUserResult 参数类型 + + v1.5.0-rc1 支持 .NET Core 2.1.0-rc1-final + + v1.6.0-rc1 + 1、支持 Senparc.Weixin v4.22.0-rc1 + 2、修复 MediaApi.UploadimgMedia() 方法文件上传问题 + + v1.6.0 发布支持 .net core 2.1 的正式版 + + v2.0.0 引入 Senparc.CO2NET,支持 Senparc.Weixin v5.0 + v2.0.3 支持 Senparc.Weixin v5.0.3,EntityHelper支持更多 + v2.0.6.1 持 CO3NET v0.1.6.1 解决 XXE 漏洞 + v2.0.9 Container 的 Register() 的微信参数自动添加到 Config.SenparcWeixinSetting.Items 下 + v2.0.10 支持 Senparc.Weixin v5.0.10 + v2.0.11 支持 Senparc.Weixin v5.0.11 + v2.1.0 支持 Senparc.Weixin v5.1.0,重构 Container,提供新的缓存过期策略 + v2.1.2 + 1、支持 Senparc.Weixin v5.1.4 + 2、整理高级接口命名空间及定义 + 3、更新 MailListApi.CreateMember() 和 UpdateMember() 接口输入参数,增加官方新增的 to_invite 参数 + v2.2.0 实现 SenparcWeixinSetting 自动注册 + v2.4.1 添加 GetUserInfoResult.CorpId 属性 + v2.4.2 支持 Senparc.Weixin.MP v15.2.4 + + v3.0.0 支持 NeuChar 标准 + v3.0.1 支持 Senparc.Weixin v6.0.1 + v3.1.0 支持 Senparc.NeuChar v0.0.5 + v3.1.2 RequestMessageInfo_Contact_Sync 改名为 RequestMessageInfo_Change_Contact;枚举 ThirdPartyInfo.CONTACT_SYNC 改名为 ThirdPartyInfo.CHANGE_CONTACT + v3.1.5 添加 MemberUpdateRequest.new_userid 属性 + v3.1.6 支持 Senparc.NeuChar v0.1.2 + v3.1.8 支持 Senparc.NeuChar v0.1.4 + v3.1.9 支持 Senparc.NeuChar v0.2.1 + v3.1.10 支持 Senparc.Weixin 6.1.4 + v3.1.11 菜单按钮类型(ButtonType)改为使用 Senparc.NeuChar.MenuButtonType + v3.1.12 Senparc.NeuChar v0.2.7 + v3.1.14 Senparc.NeuChar v0.2.11,升级 MessageHandler + v3.1.16 fix bug:RequestMessageEvent_Change_Contact_User_Create.Department 属性类型错误,添加 DepartmentList 自动转成 long[] + v3.1.18 移除微信支付相关类(已经迁移到 Senparc.Weixin.TenPay.dll 中) + v3.2.0 使用 Senparc.CO2NET.APM + v3.2.1 支持 Senparc.NeuChar v0.4.4 + v3.3.0 支持最新基础库,使用 .NETStandard2.0 统一支持 .NET Core,放弃对 .NET Core 1.x 的单独适配 + v3.3.7 + 1、添加 MemberCreateRequest.alias 属性 + 2、MailListApi.UpdateDepartment() 方法中 parendId 参数设为可为 null 类型 + 3、修复 IsLeader 参数大小写问题 + v3.3.8.1 添加“让成员成功加入企业”接口 + v3.3.9 支持最新版本 Senparc.Weixin + v3.3.10 修改 Copr 错别字,修正为 Corp + v3.4.0 + 1、支持异步 Container + 2、停止对 .NET 3.5 和 .NET 4.0 的支持 + v3.5.0 发送Markdown消息和任务卡片消息 + v3.5.2 完善 Container 注册委托的储存类型,解决多账户下的注册冲突问题 + v3.5.6 添加 GetPermanentCodeResult.auth_user_info 属性 + v3.5.7 添加 Webhook 群机器人相关 Api + v3.5.8 丰富 Webhook 接口:SendImage + v3.5.9 添加接口:手机号获取 userid + v3.5.10 优化 Container,修复在未注册的情况下直接尝试注册时可能造成线程死锁的情况 + v3.5.11 完善同步方法的 xxContainer.Register() 对异步方法的调用,避免可能的线程锁死问题 + v3.5.12 MailListApi.InviteMember() 已被官方弃用,标记为过期 + v3.5.13 优化 xxContainer.Register() 方法 + v3.5.14 引用最新版本 CO2NET 和 Senparc.Weixin + v3.6.0 + 1、消息上下文支持分布式缓存,支持最新版本 Senparc.Weixin + 2、提供带符号的 nuget 包(.snupkg) + v3.7.0 使用最新版本 Senparc.Weixin,支持 .NET Core 3.0 + v3.7.0.1 修复消息请求出现 null 异常的问题 + v3.7.101 + 1、提供 .Net Core 3.0 独立版本 + 2、优化 Container 异步注册方法 + v3.7.103.1 新增“获取打卡数据”接口返回值新增经纬度信息 + v3.7.104 引用新版本 NeuChar,优化 MessageHandler 同步方法兼容策略 + v3.7.104.1 CommonApi.Token() 方法设置异常抛出机制 + v3.7.104.2 + 1、添加“上报企业客户变更事件” + 2、添加日程相关API + v3.7.401 新增“获取客户群列表”“获取客户群详情” 接口 + v3.7.402 fix bug:ChatApi.CreateChat() 接口传入AccessToken有错误 + v3.7.502 + 1、GetMemberResult 补充二维码属性 + 2、添加“企业内部开发外部联系人- 编辑企业客户事件” + 3、添加“企业内部开发外部联系人- 回调事件” + v3.7.502.1 “更新任务卡片”接口更新返回类型 + v3.7.510.1 GetMemberResult 补充 open_userid、main_department(主部门)属性 + v3.7.601 修改“删除标签成员”接口返回参数 + v3.7.603 + 1、企业微信通讯录模块下 成员 实体 更新实体新增别名、MemberBase移除isleader + 2、新增is_leader_in_dept + + https://github.com/JeffreySu/WeiXinMPSDK + False + + + ..\..\Senparc.Weixin.MP.BuildOutPut + $(DefineConstants);RELEASE + + + ..\..\Senparc.Weixin.MP.BuildOutPut + $(DefineConstants);RELEASE + ..\..\Senparc.Weixin.MP.BuildOutPut\Senparc.Weixin.Work.XML + true + pdbonly + prompt + MinimumRecommendedRules.ruleset + + + ..\..\Senparc.Weixin.MP.BuildOutPut\ + ..\..\Senparc.Weixin.MP.BuildOutPut\net45\Senparc.Weixin.Work.xml + + + ..\..\Senparc.Weixin.MP.BuildOutPut\ + ..\..\Senparc.Weixin.MP.BuildOutPut\netstandard2.0\Senparc.Weixin.Work.xml + + + ..\..\Senparc.Weixin.MP.BuildOutPut\ + ..\..\Senparc.Weixin.MP.BuildOutPut\netstandard2.1\Senparc.Weixin.Work.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Tencent/WXBizMsgCrypt.cs.bak.txt b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Tencent/WXBizMsgCrypt.cs.bak.txt new file mode 100644 index 0000000000..e88cacbca8 --- /dev/null +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Tencent/WXBizMsgCrypt.cs.bak.txt @@ -0,0 +1,280 @@ +/*---------------------------------------------------------------- + 文件名:WXBizMsgCrypt.cs + 文件功能描述:加解密算法 + + + 创建标识:Senparc - 20150313 + + 修改标识:Senparc - 20150313 + 修改描述:整理接口 + + 修改标识:Senparc - 20191005 + 修改描述:合并更新官方最新示例(没有实质变化):https://work.weixin.qq.com/api/doc#90000/90138/90307/c#%E5%BA%93 + +----------------------------------------------------------------*/ + +using Senparc.CO2NET.Trace; +using System; +using System.Collections; +using System.Security.Cryptography; +using System.Text; +using System.Xml; +//using System.Web; + +//-40001 : 签名验证错误 +//-40002 : xml解析失败 +//-40003 : sha加密生成签名失败 +//-40004 : AESKey 非法 +//-40005 : corpid 校验错误 +//-40006 : AES 加密失败 +//-40007 : AES 解密失败 +//-40008 : 解密后得到的buffer非法 +//-40009 : base64加密异常 +//-40010 : base64解密异常 +namespace Senparc.Weixin.Work.Tencent +{ + public class WXBizMsgCrypt + { + string m_sToken; + string m_sEncodingAESKey; + string m_sReceiveId; + enum WXBizMsgCryptErrorCode + { + WXBizMsgCrypt_OK = 0, + WXBizMsgCrypt_ValidateSignature_Error = -40001, + WXBizMsgCrypt_ParseXml_Error = -40002, + WXBizMsgCrypt_ComputeSignature_Error = -40003, + WXBizMsgCrypt_IllegalAesKey = -40004, + WXBizMsgCrypt_ValidateCorpid_Error = -40005, + WXBizMsgCrypt_EncryptAES_Error = -40006, + WXBizMsgCrypt_DecryptAES_Error = -40007, + WXBizMsgCrypt_IllegalBuffer = -40008, + WXBizMsgCrypt_EncodeBase64_Error = -40009, + WXBizMsgCrypt_DecodeBase64_Error = -40010 + }; + + //构造函数 + // @param sToken: 企业微信后台,开发者设置的Token + // @param sEncodingAESKey: 企业微信后台,开发者设置的EncodingAESKey + // @param sReceiveId: 不同场景含义不同,详见文档说明(消息加密时为 CorpId) + public WXBizMsgCrypt(string sToken, string sEncodingAESKey, string sReceiveId) + { + m_sToken = sToken; + m_sReceiveId = sReceiveId; + m_sEncodingAESKey = sEncodingAESKey; + } + + //验证URL + // @param sMsgSignature: 签名串,对应URL参数的msg_signature + // @param sTimeStamp: 时间戳,对应URL参数的timestamp + // @param sNonce: 随机串,对应URL参数的nonce + // @param sEchoStr: 随机串,对应URL参数的echostr + // @param sReplyEchoStr: 解密之后的echostr,当return返回0时有效 + // @return:成功0,失败返回对应的错误码 + public int VerifyURL(string sMsgSignature, string sTimeStamp, string sNonce, string sEchoStr, ref string sReplyEchoStr) + { + int ret = 0; + if (m_sEncodingAESKey.Length != 43) + { + return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_IllegalAesKey; + } + ret = VerifySignature(m_sToken, sTimeStamp, sNonce, sEchoStr, sMsgSignature); + if (0 != ret) + { + return ret; + } + sReplyEchoStr = ""; + string cpid = ""; + try + { + sReplyEchoStr = Cryptography.AES_decrypt(sEchoStr, m_sEncodingAESKey, ref cpid); //m_sReceiveId); + } + catch (Exception) + { + sReplyEchoStr = ""; + return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_DecryptAES_Error; + } + if (cpid != m_sReceiveId) + { + sReplyEchoStr = ""; + return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_ValidateCorpid_Error; + } + return 0; + } + + // 检验消息的真实性,并且获取解密后的明文 + // @param sMsgSignature: 签名串,对应URL参数的msg_signature + // @param sTimeStamp: 时间戳,对应URL参数的timestamp + // @param sNonce: 随机串,对应URL参数的nonce + // @param sPostData: 密文,对应POST请求的数据 + // @param sMsg: 解密后的原文,当return返回0时有效 + // @return: 成功0,失败返回对应的错误码 + public int DecryptMsg(string sMsgSignature, string sTimeStamp, string sNonce, string sPostData, ref string sMsg) + { + if (m_sEncodingAESKey.Length != 43) + { + return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_IllegalAesKey; + } + XmlDocument doc = new Senparc.CO2NET.ExtensionEntities.XmlDocument_XxeFixed(); + XmlNode root; + string sEncryptMsg; + try + { + doc.LoadXml(sPostData); + root = doc.FirstChild; + sEncryptMsg = root["Encrypt"].InnerText; + } + catch (Exception) + { + return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_ParseXml_Error; + } + //verify signature + int ret = 0; + ret = VerifySignature(m_sToken, sTimeStamp, sNonce, sEncryptMsg, sMsgSignature); + if (ret != 0) + return ret; + //decrypt + string cpid = ""; + try + { + sMsg = Cryptography.AES_decrypt(sEncryptMsg, m_sEncodingAESKey, ref cpid); + } + catch (FormatException) + { + sMsg = ""; + return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_DecodeBase64_Error; + } + catch (Exception) + { + sMsg = ""; + return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_DecryptAES_Error; + } + if (cpid != m_sReceiveId) + return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_ValidateCorpid_Error; + return 0; + } + + //将企业号回复用户的消息加密打包 + // @param sReplyMsg: 企业号待回复用户的消息,xml格式的字符串 + // @param sTimeStamp: 时间戳,可以自己生成,也可以用URL参数的timestamp + // @param sNonce: 随机串,可以自己生成,也可以用URL参数的nonce + // @param sEncryptMsg: 加密后的可以直接回复用户的密文,包括msg_signature, timestamp, nonce, encrypt的xml格式的字符串, + // 当return返回0时有效 + // return:成功0,失败返回对应的错误码 + public int EncryptMsg(string sReplyMsg, string sTimeStamp, string sNonce, ref string sEncryptMsg) + { + if (m_sEncodingAESKey.Length != 43) + { + return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_IllegalAesKey; + } + string raw = ""; + try + { + raw = Cryptography.AES_encrypt(sReplyMsg, m_sEncodingAESKey, m_sReceiveId); + } + catch (Exception) + { + return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_EncryptAES_Error; + } + string MsgSigature = ""; + int ret = 0; + ret = GenarateSinature(m_sToken, sTimeStamp, sNonce, raw, ref MsgSigature); + if (0 != ret) + return ret; + sEncryptMsg = ""; + + string EncryptLabelHead = ""; + string MsgSigLabelHead = ""; + string TimeStampLabelHead = ""; + string NonceLabelHead = ""; + sEncryptMsg = sEncryptMsg + "" + EncryptLabelHead + raw + EncryptLabelTail; + sEncryptMsg = sEncryptMsg + MsgSigLabelHead + MsgSigature + MsgSigLabelTail; + sEncryptMsg = sEncryptMsg + TimeStampLabelHead + sTimeStamp + TimeStampLabelTail; + sEncryptMsg = sEncryptMsg + NonceLabelHead + sNonce + NonceLabelTail; + sEncryptMsg += ""; + return 0; + } + + public class DictionarySort : System.Collections.IComparer + { + public int Compare(object oLeft, object oRight) + { + string sLeft = oLeft as string; + string sRight = oRight as string; + int iLeftLength = sLeft.Length; + int iRightLength = sRight.Length; + int index = 0; + while (index < iLeftLength && index < iRightLength) + { + if (sLeft[index] < sRight[index]) + return -1; + else if (sLeft[index] > sRight[index]) + return 1; + else + index++; + } + return iLeftLength - iRightLength; + + } + } + //Verify Signature + private static int VerifySignature(string sToken, string sTimeStamp, string sNonce, string sMsgEncrypt, string sSigture) + { + string hash = ""; + int ret = 0; + ret = GenarateSinature(sToken, sTimeStamp, sNonce, sMsgEncrypt, ref hash); + if (ret != 0) + return ret; + if (hash == sSigture) + return 0; + else + { + return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_ValidateSignature_Error; + } + } + + public static int GenarateSinature(string sToken, string sTimeStamp, string sNonce, string sMsgEncrypt, ref string sMsgSignature) + { + SenparcTrace.SendCustomLog("Work GenarateSinature", $"Token:{sToken},ts:{sTimeStamp},snonce:{sNonce},msgEnc:{sMsgEncrypt},sMsgSignature:{sMsgSignature}"); + + ArrayList AL = new ArrayList(); + AL.Add(sToken); + AL.Add(sTimeStamp); + AL.Add(sNonce); + AL.Add(sMsgEncrypt); + AL.Sort(new DictionarySort()); + string raw = ""; + for (int i = 0; i < AL.Count; ++i) + { + raw += AL[i]; + } + + SHA1 sha; + ASCIIEncoding enc; + string hash = ""; + try + { +#if NET45 + sha = new SHA1CryptoServiceProvider(); +#else + sha = SHA1.Create(); +#endif + enc = new ASCIIEncoding(); + byte[] dataToHash = enc.GetBytes(raw); + byte[] dataHashed = sha.ComputeHash(dataToHash); + hash = BitConverter.ToString(dataHashed).Replace("-", ""); + hash = hash.ToLower(); + } + catch (Exception) + { + return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_ComputeSignature_Error; + } + sMsgSignature = hash; + return 0; + } + } +} From 02d519ebdae72c11944e64de1d6087877b2a5a3f Mon Sep 17 00:00:00 2001 From: Jimmy Wu Date: Fri, 9 Oct 2020 15:43:55 +0800 Subject: [PATCH 3/9] change --- .../Senparc.Weixin.Work/Senparc.Weixin.Work.csproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Senparc.Weixin.Work.csproj b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Senparc.Weixin.Work.csproj index 6c7e6a06c4..47d1162b73 100644 --- a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Senparc.Weixin.Work.csproj +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Senparc.Weixin.Work.csproj @@ -86,6 +86,9 @@ + + + From 1d163f2bf793eb7016b7c1cd39cc678d3a3db528 Mon Sep 17 00:00:00 2001 From: Jimmy Wu Date: Fri, 9 Oct 2020 15:47:04 +0800 Subject: [PATCH 4/9] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86=E5=A4=96?= =?UTF-8?q?=E9=83=A8=E8=81=94=E7=B3=BB=E4=BA=BA=E7=AE=A1=E7=90=86--?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AE=A1=E7=90=86=E7=9B=B8=E5=85=B3=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AdvancedAPIs/External/ExternalApi.cs | 171 ++++++++++++++++++ 1 file changed, 171 insertions(+) diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalApi.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalApi.cs index a78e9795ac..b24c4fd2ea 100644 --- a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalApi.cs +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalApi.cs @@ -20,6 +20,7 @@ using Senparc.Weixin.CommonAPIs; using Senparc.Weixin.Entities; using Senparc.Weixin.Work.AdvancedAPIs.External; +using Senparc.Weixin.Work.AdvancedAPIs.External.ExternalJson; using System.Threading.Tasks; namespace Senparc.Weixin.Work.AdvancedAPIs @@ -119,6 +120,91 @@ public static GroupChatGetResult GroupChatGet(string accessTokenOrAppKey, string }, accessTokenOrAppKey); } + + #region 客户管理 + + /// + /// 获取客户列表 + /// + /// 调用接口凭证 + /// 企业成员的userid + /// + /// + [ApiBind(NeuChar.PlatformType.WeChat_Work, "ExternalApi.GetExternalContactList", true)] + public static GetExternalContactListResult GetExternalContactList(string accessTokenOrAppKey, string userid, int timeOut = Config.TIME_OUT) + { + return ApiHandlerWapper.TryCommonApi(accessToken => + { + var url = $"{Config.ApiWorkHost}/cgi-bin/externalcontact/list?access_token={accessToken}&userid={userid}"; + + return CommonJsonSend.Send(null, url, null, CommonJsonSendType.GET, timeOut); + }, accessTokenOrAppKey); + } + + /// + /// 获取客户详情 + /// + /// 调用接口凭证 + /// 外部联系人的userid,注意不是企业成员的帐号 + /// + /// + [ApiBind(NeuChar.PlatformType.WeChat_Work, "ExternalApi.GetExternalContactInfo", true)] + public static GetExternalContactResultJson GetExternalContactInfo(string accessTokenOrAppKey, string externalUserId, int timeOut = Config.TIME_OUT) + { + return ApiHandlerWapper.TryCommonApi(accessToken => + { + var url = $"{Config.ApiWorkHost}/cgi-bin/externalcontact/get?access_token={accessToken}&external_userid={externalUserId}"; + + return CommonJsonSend.Send(null, url, null, CommonJsonSendType.GET, timeOut); + }, accessTokenOrAppKey); + } + + /// + /// 批量获取客户详情 + /// + /// + /// + /// + /// + /// + [ApiBind(NeuChar.PlatformType.WeChat_Work, "ExternalApi.GetExternalContactInfoBatch", true)] + public static GetExternalContactInfoBatchResult GetExternalContactInfoBatch(string accessTokenOrAppKey, string userid, string cursor = "", int limit = 50, int timeOut = Config.TIME_OUT) + { + return ApiHandlerWapper.TryCommonApi(accessToken => + { + var url = $"{Config.ApiWorkHost}/cgi-bin/externalcontact/batch/get_by_user?access_token={accessToken}"; + + var data = new + { + userid, + cursor, + limit + }; + + return CommonJsonSend.Send(null, url, data, CommonJsonSendType.POST, timeOut); + }, accessTokenOrAppKey); + } + + /// + /// 修改客户备注信息 + /// + /// 调用接口凭证 + /// 请求报文 + /// + /// + [ApiBind(NeuChar.PlatformType.WeChat_Work, "ExternalApi.UpdateExternalContactRemark", true)] + public static WorkJsonResult UpdateExternalContactRemark(string accessTokenOrAppKey, UpdateExternalContactRemarkRequest rquest, int timeOut = Config.TIME_OUT) + { + return ApiHandlerWapper.TryCommonApi(accessToken => + { + var url = $"{Config.ApiWorkHost}/cgi-bin/externalcontact/remark?access_token={accessToken}"; + + return CommonJsonSend.Send(null, url, rquest, CommonJsonSendType.POST, timeOut); + }, accessTokenOrAppKey); + } + + #endregion + #endregion @@ -212,6 +298,91 @@ public static async Task GroupChatGetAsync(string accessToke }, accessTokenOrAppKey).ConfigureAwait(false); } + + #region 客户管理 + + /// + /// 【异步方法】获取客户列表 + /// + /// 调用接口凭证 + /// 企业成员的userid + /// + /// + [ApiBind(NeuChar.PlatformType.WeChat_Work, "ExternalApi.GetExternalContactListAsync", true)] + public static async Task GetExternalContactListAsync(string accessTokenOrAppKey, string userid, int timeOut = Config.TIME_OUT) + { + return await ApiHandlerWapper.TryCommonApiAsync(async accessToken => + { + var url = $"{Config.ApiWorkHost}/cgi-bin/externalcontact/list?access_token={accessToken}&userid={userid}"; + + return await CommonJsonSend.SendAsync(null, url, null, CommonJsonSendType.GET, timeOut).ConfigureAwait(false); + }, accessTokenOrAppKey).ConfigureAwait(false); + } + + /// + /// 【异步方法】获取客户详情 + /// + /// 调用接口凭证 + /// 外部联系人的userid,注意不是企业成员的帐号 + /// + /// + [ApiBind(NeuChar.PlatformType.WeChat_Work, "ExternalApi.GetExternalContactInfoAsync", true)] + public static async Task GetExternalContactInfoAsync(string accessTokenOrAppKey, string externalUserId, int timeOut = Config.TIME_OUT) + { + return await ApiHandlerWapper.TryCommonApiAsync(async accessToken => + { + var url = $"{Config.ApiWorkHost}/cgi-bin/externalcontact/get?access_token={accessToken}&external_userid={externalUserId}"; + + return await CommonJsonSend.SendAsync(null, url, null, CommonJsonSendType.GET, timeOut).ConfigureAwait(false); + }, accessTokenOrAppKey).ConfigureAwait(false); + } + + /// + /// 【异步方法】批量获取客户详情 + /// + /// + /// + /// + /// + /// + [ApiBind(NeuChar.PlatformType.WeChat_Work, "ExternalApi.GetExternalContactInfoBatchAsync", true)] + public static async Task GetExternalContactInfoBatchAsync(string accessTokenOrAppKey, string userid, string cursor = "", int limit = 50, int timeOut = Config.TIME_OUT) + { + return await ApiHandlerWapper.TryCommonApiAsync(async accessToken => + { + var url = $"{Config.ApiWorkHost}/cgi-bin/externalcontact/batch/get_by_user?access_token={accessToken}"; + + var data = new + { + userid, + cursor, + limit + }; + + return await CommonJsonSend.SendAsync(null, url, data, CommonJsonSendType.POST, timeOut).ConfigureAwait(false); + }, accessTokenOrAppKey).ConfigureAwait(false); + } + + /// + /// 修改客户备注信息 + /// + /// 调用接口凭证 + /// 请求报文 + /// + /// + [ApiBind(NeuChar.PlatformType.WeChat_Work, "ExternalApi.UpdateExternalContactRemarkAsync", true)] + public static async Task UpdateExternalContactRemarkAsync(string accessTokenOrAppKey, UpdateExternalContactRemarkRequest rquest, int timeOut = Config.TIME_OUT) + { + return await ApiHandlerWapper.TryCommonApiAsync(async accessToken => + { + var url = $"{Config.ApiWorkHost}/cgi-bin/externalcontact/remark?access_token={accessToken}"; + + return await CommonJsonSend.SendAsync(null, url, rquest, CommonJsonSendType.POST, timeOut).ConfigureAwait(false); + }, accessTokenOrAppKey).ConfigureAwait(false); + } + + #endregion + #endregion } } From 5444f4099b595e6d4ee4b73edb0da2483c65ed2a Mon Sep 17 00:00:00 2001 From: Jimmy Wu Date: Mon, 12 Oct 2020 14:46:11 +0800 Subject: [PATCH 5/9] =?UTF-8?q?=E7=AC=AC=E4=B8=89=E6=96=B9=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E5=9B=9E=E8=B0=83=E6=97=B6=EF=BC=8CInfoType=E4=B8=BA?= =?UTF-8?q?=E5=A4=96=E9=83=A8=E8=81=94=E7=B3=BB=E4=BA=BA=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E6=8A=A5=E9=94=99=20=E5=8E=9F=E5=9B=A0=EF=BC=9AThirdPartyInfo?= =?UTF-8?q?=E6=9E=9A=E4=B8=BE=E4=B8=AD=E6=9C=AA=E5=AE=9A=E4=B9=89CHANGE=5F?= =?UTF-8?q?EXTERNAL=5FCONTACT=20=E8=A7=A3=E5=86=B3=EF=BC=9A=E5=9C=A8ThirdP?= =?UTF-8?q?artyInfo=E6=9E=9A=E4=B8=BE=E4=B8=AD=E5=AE=9A=E4=B9=89CHANGE=5FE?= =?UTF-8?q?XTERNAL=5FCONTACT=EF=BC=8C=E5=90=8C=E6=97=B6=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=AF=B9=E5=BA=94=E7=AC=AC=E4=B8=89=E6=96=B9=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E5=A4=84=E7=90=86=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RequestMessageEvent_ExternalContact.cs | 4 ++ .../Senparc.Weixin.Work/Enums.cs | 7 ++- .../MessageHandlers/WorkMessageHandler.cs | 61 +++++++++++++++++++ 3 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Entities/Request/Event/RequestMessageEvent_ExternalContact.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Entities/Request/Event/RequestMessageEvent_ExternalContact.cs index 9e4dca8780..dea48edb55 100644 --- a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Entities/Request/Event/RequestMessageEvent_ExternalContact.cs +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Entities/Request/Event/RequestMessageEvent_ExternalContact.cs @@ -22,6 +22,8 @@ namespace Senparc.Weixin.Work.Entities.Request.Event /// public interface IRequestMessageEvent_Change_ExternalContact_Base : IRequestMessageEventBase { + string SuiteId { get; set; } + string AuthCorpId { get; set; } ExternalContactChangeType ChangeType { get; @@ -30,6 +32,8 @@ ExternalContactChangeType ChangeType public class RequestMessageEvent_Change_ExternalContact_Base : RequestMessageEventBase, IRequestMessageEvent_Change_ExternalContact_Base { + public string SuiteId { get; set; } + public string AuthCorpId { get; set; } public override Work.Event Event { get { return Work.Event.CHANGE_EXTERNAL_CONTACT; } diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Enums.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Enums.cs index b3297451d6..e2af54aced 100644 --- a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Enums.cs +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Enums.cs @@ -183,7 +183,12 @@ public enum ThirdPartyInfo /// /// 通讯录变更通知 /// - CHANGE_CONTACT//更新前字符串:CONTACT_SYNC + CHANGE_CONTACT,//更新前字符串:CONTACT_SYNC + + /// + /// 外部联系人变更通知 + /// + CHANGE_EXTERNAL_CONTACT } diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/MessageHandlers/WorkMessageHandler.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/MessageHandlers/WorkMessageHandler.cs index 6cb53c8c76..17e2eef9f8 100644 --- a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/MessageHandlers/WorkMessageHandler.cs +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/MessageHandlers/WorkMessageHandler.cs @@ -739,6 +739,33 @@ private string OnThirdPartyEvent(IThirdPartyInfoBase thirdPartyInfo) return OnThirdPartyEvent_Create_Auth((RequestMessageInfo_Create_Auth)thirdPartyInfo); case ThirdPartyInfo.CHANGE_CONTACT: return OnThirdPartyEvent_Change_Contact((RequestMessageInfo_Change_Contact)thirdPartyInfo); + case ThirdPartyInfo.CHANGE_EXTERNAL_CONTACT: + { + var cecRequestMessage = RequestMessage as IRequestMessageEvent_Change_ExternalContact_Base; + switch (cecRequestMessage.ChangeType) + { + case ExternalContactChangeType.add_external_contact: + return OnThirdPartyEvent_ChangeExternalContactAddRequest( + RequestMessage as RequestMessageEvent_Change_ExternalContact_Add); + case ExternalContactChangeType.edit_external_contact: + return OnThirdPartyEvent_ChangeExternalContactUpdateRequest( + RequestMessage as RequestMessageEvent_Change_ExternalContact_Modified); + case ExternalContactChangeType.add_half_external_contact: + return OnThirdPartyEvent_ChangeExternalContactAddHalfRequest( + RequestMessage as RequestMessageEvent_Change_ExternalContact_Add_Half); + case ExternalContactChangeType.del_external_contact: + return OnThirdPartyEvent_ChangeExternalContactDelRequest( + RequestMessage as RequestMessageEvent_Change_ExternalContact_Del); + case ExternalContactChangeType.del_follow_user: + return OnThirdPartyEvent_ChangeExternalContactDelFollowUserRequest( + RequestMessage as RequestMessageEvent_Change_ExternalContact_Del_FollowUser); + case ExternalContactChangeType.msg_audit_approved: + return OnThirdPartyEvent_ChangeExternalContactMsgAudit( + RequestMessage as RequestMessageEvent_Change_ExternalContact_MsgAudit); + default: + throw new UnknownRequestMsgTypeException("未知的外部联系人事件Event.CHANGE_EXTERNAL_CONTACT下属请求信息", null); + } + } default: throw new UnknownRequestMsgTypeException("未知的InfoType请求类型", null); } @@ -769,6 +796,40 @@ protected virtual string OnThirdPartyEvent_Suite_Ticket(RequestMessageInfo_Suite return ThirdPartyEventSuccessResult; } + #region 外部联系人 + + protected virtual string OnThirdPartyEvent_ChangeExternalContactAddRequest(RequestMessageEvent_Change_ExternalContact_Add requestMessage) + { + return ThirdPartyEventSuccessResult; + } + + protected virtual string OnThirdPartyEvent_ChangeExternalContactUpdateRequest(RequestMessageEvent_Change_ExternalContact_Modified requestMessage) + { + return ThirdPartyEventSuccessResult; + } + + protected virtual string OnThirdPartyEvent_ChangeExternalContactAddHalfRequest(RequestMessageEvent_Change_ExternalContact_Add_Half requestMessage) + { + return ThirdPartyEventSuccessResult; + } + + protected virtual string OnThirdPartyEvent_ChangeExternalContactDelRequest(RequestMessageEvent_Change_ExternalContact_Del requestMessage) + { + return ThirdPartyEventSuccessResult; + } + + protected virtual string OnThirdPartyEvent_ChangeExternalContactDelFollowUserRequest(RequestMessageEvent_Change_ExternalContact_Del_FollowUser requestMessage) + { + return ThirdPartyEventSuccessResult; + } + + protected virtual string OnThirdPartyEvent_ChangeExternalContactMsgAudit(RequestMessageEvent_Change_ExternalContact_MsgAudit requestMessage) + { + return ThirdPartyEventSuccessResult; + } + + #endregion + #endregion } } From 7bd2674dd94ba185c7509f523ac1a3d27111ae10 Mon Sep 17 00:00:00 2001 From: Jimmy Wu Date: Mon, 12 Oct 2020 16:03:30 +0800 Subject: [PATCH 6/9] Modify --- .../Senparc.Weixin.Work/RequestMessageFactory.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/RequestMessageFactory.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/RequestMessageFactory.cs index 18e6facb52..1eca58eeb9 100644 --- a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/RequestMessageFactory.cs +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/RequestMessageFactory.cs @@ -23,6 +23,7 @@ using System.Xml.Linq; using Senparc.Weixin.Exceptions; using Senparc.Weixin.Work.Entities; +using Senparc.Weixin.Work.Entities.Request.Event; using Senparc.NeuChar; using Senparc.NeuChar.Helpers; using Senparc.NeuChar.Context; @@ -84,6 +85,9 @@ public static IWorkRequestMessageBase GetRequestEntity(TMC messageContext, case ThirdPartyInfo.CHANGE_CONTACT://通讯录变更通知 requestMessage = new RequestMessageInfo_Change_Contact(); break; + case ThirdPartyInfo.CHANGE_EXTERNAL_CONTACT: + requestMessage = new RequestMessageEvent_Change_ExternalContact_Base(); + break; default: throw new UnknownRequestMsgTypeException(string.Format("InfoType:{0} 在RequestMessageFactory中没有对应的处理程序!", infoType), new ArgumentOutOfRangeException());//为了能够对类型变动最大程度容错(如微信目前还可以对公众账号suscribe等未知类型,但API没有开放),建议在使用的时候catch这个异常 } From a977de33dbab3b39f503a59d9c37fdf21ee4bd46 Mon Sep 17 00:00:00 2001 From: Jimmy Wu Date: Mon, 12 Oct 2020 17:45:07 +0800 Subject: [PATCH 7/9] =?UTF-8?q?=E5=AE=9E=E4=BD=93=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GetExternalContactInfoBatchResult.cs | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/GetExternalContactInfoBatchResult.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/GetExternalContactInfoBatchResult.cs index 98311bffca..9db1738e7e 100644 --- a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/GetExternalContactInfoBatchResult.cs +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/GetExternalContactInfoBatchResult.cs @@ -22,6 +22,28 @@ public class GetExternalContactInfoBatchResult : WorkJsonResult public class ExternalContactList { - public GetExternalContactResultJson external_contact { get; set; } + public ExternalContact external_contact { get; set; } + public FollowUser follow_info { get; set; } + } + + + public class ExternalContact + { + public string external_userid { get; set; } + public string name { get; set; } + public int type { get; set; } + public string avatar { get; set; } + public int gender { get; set; } + public string unionid { get; set; } + } + + public class FollowUser + { + public string remark { get; set; } + public string description { get; set; } + public long creattime { get; set; } + public string[] tag_id { get; set; } + public string[] remark_mobiles { get; set; } + public int add_way { get; set; } } } From 43b59a8c9d7935364530b377146a5aba540fc87e Mon Sep 17 00:00:00 2001 From: JeffreySu Date: Tue, 13 Oct 2020 21:58:44 +0800 Subject: [PATCH 8/9] =?UTF-8?q?WxOpen=20v3.8.601=20#2247=20=E6=84=9F?= =?UTF-8?q?=E8=B0=A2@=20likui0623?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Senparc.Weixin.WxOpen/Helpers/EncryptHelper.cs | 3 +++ .../Senparc.Weixin.WxOpen.netcore3.csproj | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Senparc.Weixin.WxOpen/src/Senparc.Weixin.WxOpen/Senparc.Weixin.WxOpen/Helpers/EncryptHelper.cs b/src/Senparc.Weixin.WxOpen/src/Senparc.Weixin.WxOpen/Senparc.Weixin.WxOpen/Helpers/EncryptHelper.cs index 288cd4a206..7f12c37dc8 100644 --- a/src/Senparc.Weixin.WxOpen/src/Senparc.Weixin.WxOpen/Senparc.Weixin.WxOpen/Helpers/EncryptHelper.cs +++ b/src/Senparc.Weixin.WxOpen/src/Senparc.Weixin.WxOpen/Senparc.Weixin.WxOpen/Helpers/EncryptHelper.cs @@ -33,6 +33,9 @@ and limitations under the License. 修改标识:Senparc - 20190727 修改描述:完善 AES_Decrypt,处理偶然出现的 adding is invalid and cannot be removed 问题(未发现规律) + 修改标识:likui0623 - 20201013 + 修改描述:添加解密到实例信息方法 + ----------------------------------------------------------------*/ using System; diff --git a/src/Senparc.Weixin.WxOpen/src/Senparc.Weixin.WxOpen/Senparc.Weixin.WxOpen/Senparc.Weixin.WxOpen.netcore3.csproj b/src/Senparc.Weixin.WxOpen/src/Senparc.Weixin.WxOpen/Senparc.Weixin.WxOpen/Senparc.Weixin.WxOpen.netcore3.csproj index 3fca6b7307..e8efe38221 100644 --- a/src/Senparc.Weixin.WxOpen/src/Senparc.Weixin.WxOpen/Senparc.Weixin.WxOpen/Senparc.Weixin.WxOpen.netcore3.csproj +++ b/src/Senparc.Weixin.WxOpen/src/Senparc.Weixin.WxOpen/Senparc.Weixin.WxOpen/Senparc.Weixin.WxOpen.netcore3.csproj @@ -1,7 +1,7 @@ net45;netstandard2.0;netstandard2.1 - 3.8.600 + 3.8.601 Senparc.Weixin.WxOpen Senparc.Weixin.WxOpen true @@ -147,7 +147,7 @@ v3.8.511 1、小程序 WxOpenMessageHandler 增加 OnImageRequestAsync 和 OnTextRequestAsync 2、调整 MessageHandler 异步方法执行代码 - v3.8.512 修复普通链接二维码与小程序码-获取校验文件名称及内容 + v3.8.512 添加解密到实例信息方法 https://github.com/JeffreySu/WeiXinMPSDK From 95d7443d055e4fa026630f9845f402eeff918ab6 Mon Sep 17 00:00:00 2001 From: JeffreySu Date: Tue, 13 Oct 2020 22:09:18 +0800 Subject: [PATCH 9/9] =?UTF-8?q?Work=20v3.7.604=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=A4=96=E9=83=A8=E8=81=94=E7=B3=BB=E4=BA=BA=E7=AE=A1=E7=90=86?= =?UTF-8?q?>=E5=AE=A2=E6=88=B7=E7=AE=A1=E7=90=86=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=20#2252=20=E6=84=9F=E8=B0=A2=20@gokeiyou?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AdvancedAPIs/External/ExternalApi.cs | 3 +++ .../GetExternalContactInfoBatchResult.cs | 16 +++++++++++++++- .../ExternalJson/GetExternalContactListResult.cs | 13 ++++++++++++- .../UpdateExternalContactRemarkRequest.cs | 13 ++++++++++++- .../Event/RequestMessageEvent_ExternalContact.cs | 3 +++ .../Senparc.Weixin.Work/Enums.cs | 3 +++ .../MessageHandlers/WorkMessageHandler.cs | 3 +++ .../Senparc.Weixin.Work/RequestMessageFactory.cs | 4 ++++ .../Senparc.Weixin.Work.netcore3.csproj | 5 +++-- 9 files changed, 58 insertions(+), 5 deletions(-) diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalApi.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalApi.cs index b24c4fd2ea..6eba16033c 100644 --- a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalApi.cs +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalApi.cs @@ -10,6 +10,9 @@ 修改标识:lishewen - 20200318 修改描述:v3.7.401 新增“获取客户群列表”“获取客户群详情” API + 修改标识:gokeiyou - 20201013 + 修改描述:v3.7.604 添加外部联系人管理 > 客户管理相关接口 + ----------------------------------------------------------------*/ /* diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/GetExternalContactInfoBatchResult.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/GetExternalContactInfoBatchResult.cs index 9db1738e7e..a268df2109 100644 --- a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/GetExternalContactInfoBatchResult.cs +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/GetExternalContactInfoBatchResult.cs @@ -1,4 +1,15 @@ -using System; +/*---------------------------------------------------------------- + Copyright (C) 2020 Senparc + + 文件名:GetExternalContactInfoBatchResult.cs + 文件功能描述:批量获取客户详情 返回结果 + + + 创建标识:gokeiyou - 20201013 + +----------------------------------------------------------------*/ + +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -7,6 +18,9 @@ namespace Senparc.Weixin.Work.AdvancedAPIs.External.ExternalJson { + /// + /// 批量获取客户详情 返回结果 + /// public class GetExternalContactInfoBatchResult : WorkJsonResult { /// diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/GetExternalContactListResult.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/GetExternalContactListResult.cs index 359874ac5e..6a96c79503 100644 --- a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/GetExternalContactListResult.cs +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/GetExternalContactListResult.cs @@ -1,4 +1,15 @@ -using System; +/*---------------------------------------------------------------- + Copyright (C) 2020 Senparc + + 文件名:GetExternalContactInfoBatchResult.cs + 文件功能描述:批量获取客户详情 返回结果 + + + 创建标识:gokeiyou - 20201013 + +----------------------------------------------------------------*/ + +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/UpdateExternalContactRemarkRequest.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/UpdateExternalContactRemarkRequest.cs index 17fdcff8e3..b8884c3ec3 100644 --- a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/UpdateExternalContactRemarkRequest.cs +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/External/ExternalJson/UpdateExternalContactRemarkRequest.cs @@ -1,4 +1,15 @@ -using System; +/*---------------------------------------------------------------- + Copyright (C) 2020 Senparc + + 文件名:GetExternalContactInfoBatchResult.cs + 文件功能描述:批量获取客户详情 返回结果 + + + 创建标识:gokeiyou - 20201013 + +----------------------------------------------------------------*/ + +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Entities/Request/Event/RequestMessageEvent_ExternalContact.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Entities/Request/Event/RequestMessageEvent_ExternalContact.cs index dea48edb55..894a4e6135 100644 --- a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Entities/Request/Event/RequestMessageEvent_ExternalContact.cs +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Entities/Request/Event/RequestMessageEvent_ExternalContact.cs @@ -13,6 +13,9 @@ 修改标识:OrchesAdam - 20200430 修改描述:v3.7.502 添加编辑企业客户事件 + 修改标识:gokeiyou - 20201013 + 修改描述:v3.7.604 添加外部联系人管理 > 客户管理相关接口 + ----------------------------------------------------------------*/ namespace Senparc.Weixin.Work.Entities.Request.Event diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Enums.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Enums.cs index e2af54aced..a81c10581f 100644 --- a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Enums.cs +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Enums.cs @@ -29,6 +29,9 @@ v1.4.1 增加“接收通讯录变更事件” 修改标识:jiehanlin - 20200430 修改描述:v3.7.502 添加枚举“客户群变更事件”(CHANGE_EXTERNAL_CHAT) + 修改标识:gokeiyou - 20201013 + 修改描述:v3.7.604 添加外部联系人管理 > 客户管理相关接口 + ----------------------------------------------------------------*/ namespace Senparc.Weixin.Work diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/MessageHandlers/WorkMessageHandler.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/MessageHandlers/WorkMessageHandler.cs index 17e2eef9f8..68601f233c 100644 --- a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/MessageHandlers/WorkMessageHandler.cs +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/MessageHandlers/WorkMessageHandler.cs @@ -48,6 +48,9 @@ OnThirdPartyEvent_Contact_Sync 改名为 OnThirdPartyEvent_Change_Contact() 修改标识:OrchesAdam - 20200430 修改描述:添加“客户群变更事件”(OnEvent_ChangeExternalChatRequest) + 修改标识:gokeiyou - 20201013 + 修改描述:v3.7.604 添加外部联系人管理 > 客户管理相关接口 + ----------------------------------------------------------------*/ using System; diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/RequestMessageFactory.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/RequestMessageFactory.cs index 1eca58eeb9..e4ae0d3862 100644 --- a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/RequestMessageFactory.cs +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/RequestMessageFactory.cs @@ -15,6 +15,10 @@ 修改标识:Senparc - 20180909 修改描述:v3.1.2 RequestMessageInfo_Contact_Sync 改名为 RequestMessageInfo_Change_Contact + + 修改标识:gokeiyou - 20201013 + 修改描述:v3.7.604 添加外部联系人管理 > 客户管理相关接口 + ----------------------------------------------------------------*/ using System; diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Senparc.Weixin.Work.netcore3.csproj b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Senparc.Weixin.Work.netcore3.csproj index a85f4193c6..5c38face36 100644 --- a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Senparc.Weixin.Work.netcore3.csproj +++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Senparc.Weixin.Work.netcore3.csproj @@ -2,7 +2,7 @@ net45;netstandard2.0;netstandard2.1 $(Net35FrameworkPathOverride) - 3.7.603 + 3.7.604 Senparc.Weixin.Work Senparc.Weixin.Work true @@ -151,9 +151,10 @@ v3.7.502.1 “更新任务卡片”接口更新返回类型 v3.7.510.1 GetMemberResult 补充 open_userid、main_department(主部门)属性 v3.7.601 修改“删除标签成员”接口返回参数 - v3.7.603 + v3.7.603 1、企业微信通讯录模块下 成员 实体 更新实体新增别名、MemberBase移除isleader 2、新增is_leader_in_dept + v3.7.604 添加外部联系人管理 > 客户管理相关接口 https://github.com/JeffreySu/WeiXinMPSDK False