65 changed files with 1199 additions and 567 deletions
@ -1,21 +1,5 @@ |
|||||
using LINGYUN.Abp.WeChat.Work.Token.Models; |
namespace System.Net.Http; |
||||
using System.Text; |
|
||||
using System.Threading; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace System.Net.Http; |
|
||||
|
|
||||
internal static partial class HttpClientWeChatWorkRequestExtensions |
internal static partial class HttpClientWeChatWorkRequestExtensions |
||||
{ |
{ |
||||
public async static Task<HttpResponseMessage> GetTokenAsync(this HttpMessageInvoker client, WeChatWorkTokenRequest request, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
var urlBuilder = new StringBuilder(); |
|
||||
urlBuilder.Append("/cgi-bin/gettoken"); |
|
||||
urlBuilder.AppendFormat("?corpid={0}", request.CorpId); |
|
||||
urlBuilder.AppendFormat("&corpsecret={0}", request.CorpSecret); |
|
||||
|
|
||||
var httpRequest = new HttpRequestMessage(HttpMethod.Get, urlBuilder.ToString()); |
|
||||
|
|
||||
return await client.SendAsync(httpRequest, cancellationToken); |
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -0,0 +1,23 @@ |
|||||
|
using LINGYUN.Abp.WeChat.Common.Messages; |
||||
|
using LINGYUN.Abp.WeChat.Work.Common.Messages; |
||||
|
using System.Xml.Serialization; |
||||
|
using Volo.Abp.EventBus; |
||||
|
|
||||
|
namespace LINGYUN.Abp.WeChat.Work.ExternalContact.Messages.Models; |
||||
|
/// <summary>
|
||||
|
/// 客户同意进行聊天内容存档事件推送
|
||||
|
/// </summary>
|
||||
|
[EventName("external_contact_msg_audit_approved")] |
||||
|
public class ExternalContactMsgAuditApprovedEvent : ExternalContactChangeEvent |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 欢迎语code,可用于发送欢迎语
|
||||
|
/// </summary>
|
||||
|
[XmlElement("WelcomeCode")] |
||||
|
public string WelcomeCode { get; set; } |
||||
|
|
||||
|
public override WeChatMessageEto ToEto() |
||||
|
{ |
||||
|
return new WeChatWorkEventMessageEto<ExternalContactMsgAuditApprovedEvent>(this); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
using LINGYUN.Abp.WeChat.Common.Messages; |
||||
|
using LINGYUN.Abp.WeChat.Work.Common.Messages; |
||||
|
using Volo.Abp.EventBus; |
||||
|
|
||||
|
namespace LINGYUN.Abp.WeChat.Work.ExternalContact.Messages.Models; |
||||
|
/// <summary>
|
||||
|
/// 产生会话回调事件推送
|
||||
|
/// </summary>
|
||||
|
[EventName("external_contact_msgaudit_notify")] |
||||
|
public class ExternalContactMsgAuditNotifyEvent : WeChatWorkEventMessage |
||||
|
{ |
||||
|
public override WeChatMessageEto ToEto() |
||||
|
{ |
||||
|
return new WeChatWorkEventMessageEto<ExternalContactMsgAuditNotifyEvent>(this); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,48 @@ |
|||||
|
using LINGYUN.Abp.WeChat.Work.ExternalContact.MsgAudits.Request; |
||||
|
using LINGYUN.Abp.WeChat.Work.ExternalContact.MsgAudits.Response; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.WeChat.Work.ExternalContact.MsgAudits; |
||||
|
/// <summary>
|
||||
|
/// 会话存档接口
|
||||
|
/// </summary>
|
||||
|
public interface IWeChatWorkMsgAuditProvider |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 获取会话内容存档开启成员列表
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// 详情见: <see href="https://developer.work.weixin.qq.com/document/path/91614" />
|
||||
|
/// </remarks>
|
||||
|
Task<WeChatWorkGetPermitUserListResponse> GetPermitUserListAsync( |
||||
|
WeChatWorkGetPermitUserListRequest request, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
/// <summary>
|
||||
|
/// 获取单聊会话同意情况
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// 详情见: <see href="https://developer.work.weixin.qq.com/document/path/91782" />
|
||||
|
/// </remarks>
|
||||
|
Task<WeChatWorkCheckSingleAgreeResponse> CheckSingleAgreeAsync( |
||||
|
WeChatWorkCheckSingleAgreeRequest request, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
/// <summary>
|
||||
|
/// 获取群聊会话同意情况
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// 详情见: <see href="https://developer.work.weixin.qq.com/document/path/91782" />
|
||||
|
/// </remarks>
|
||||
|
Task<WeChatWorkCheckRoomAgreeResponse> CheckRoomAgreeAsync( |
||||
|
WeChatWorkCheckRoomAgreeRequest request, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
/// <summary>
|
||||
|
/// 获取会话内容存档内部群信息
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// 详情见: <see href="https://developer.work.weixin.qq.com/document/path/92951" />
|
||||
|
/// </remarks>
|
||||
|
Task<WeChatWorkGetGroupChatResponse> GetGroupChatAsync( |
||||
|
WeChatWorkGetGroupChatRequest request, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
} |
||||
@ -0,0 +1,35 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using Newtonsoft.Json; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
using System.Text.Json.Serialization; |
||||
|
|
||||
|
namespace LINGYUN.Abp.WeChat.Work.ExternalContact.MsgAudits.Models; |
||||
|
/// <summary>
|
||||
|
/// 群聊同意情况
|
||||
|
/// </summary>
|
||||
|
public class RoomAgreeInfo |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 外部成员的exteranalopenid
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
[JsonProperty("exteranalopenid")] |
||||
|
[JsonPropertyName("exteranalopenid")] |
||||
|
public string ExteranalOpenId { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 同意:"Agree",不同意:"Disagree"
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
[JsonProperty("agree_status")] |
||||
|
[JsonPropertyName("agree_status")] |
||||
|
public string AgreeStatus { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 同意状态改变的具体时间,utc时间
|
||||
|
/// </summary>
|
||||
|
[CanBeNull] |
||||
|
[JsonProperty("status_change_time")] |
||||
|
[JsonPropertyName("status_change_time")] |
||||
|
public long? StatusChangeTime { get; set; } |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using Newtonsoft.Json; |
||||
|
using System.Text.Json.Serialization; |
||||
|
|
||||
|
namespace LINGYUN.Abp.WeChat.Work.ExternalContact.MsgAudits.Models; |
||||
|
/// <summary>
|
||||
|
/// 群聊成员
|
||||
|
/// </summary>
|
||||
|
public class RoomMember |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// roomid群成员的id,userid
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
[JsonProperty("memberid")] |
||||
|
[JsonPropertyName("memberid")] |
||||
|
public string MemberId { get; set; } |
||||
|
/// <summary>
|
||||
|
/// roomid群成员的入群时间
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
[JsonProperty("jointime")] |
||||
|
[JsonPropertyName("jointime")] |
||||
|
public long JoinTime { get; set; } |
||||
|
} |
||||
@ -0,0 +1,39 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using Newtonsoft.Json; |
||||
|
using System.Text.Json.Serialization; |
||||
|
|
||||
|
namespace LINGYUN.Abp.WeChat.Work.ExternalContact.MsgAudits.Models; |
||||
|
/// <summary>
|
||||
|
/// 单聊同意情况
|
||||
|
/// </summary>
|
||||
|
public class UserAgreeInfo |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 内部成员的userid
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
[JsonProperty("userid")] |
||||
|
[JsonPropertyName("userid")] |
||||
|
public string UserId { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 外部成员的exteranalopenid
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
[JsonProperty("exteranalopenid")] |
||||
|
[JsonPropertyName("exteranalopenid")] |
||||
|
public string ExteranalOpenId { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 同意:"Agree",不同意:"Disagree"
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
[JsonProperty("agree_status")] |
||||
|
[JsonPropertyName("agree_status")] |
||||
|
public string AgreeStatus { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 同意状态改变的具体时间,utc时间
|
||||
|
/// </summary>
|
||||
|
[CanBeNull] |
||||
|
[JsonProperty("status_change_time")] |
||||
|
[JsonPropertyName("status_change_time")] |
||||
|
public long? StatusChangeTime { get; set; } |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using Newtonsoft.Json; |
||||
|
using System.Text.Json.Serialization; |
||||
|
|
||||
|
namespace LINGYUN.Abp.WeChat.Work.ExternalContact.MsgAudits.Request; |
||||
|
/// <summary>
|
||||
|
/// 获取群聊会话同意情况请求参数
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// 详情见: <see href="https://developer.work.weixin.qq.com/document/path/91782" />
|
||||
|
/// </remarks>
|
||||
|
public class WeChatWorkCheckRoomAgreeRequest : WeChatWorkRequest |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 待查询的roomid
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
[JsonProperty("roomid")] |
||||
|
[JsonPropertyName("roomid")] |
||||
|
public string RoomId { get; } |
||||
|
public WeChatWorkCheckRoomAgreeRequest(string roomId) |
||||
|
{ |
||||
|
RoomId = roomId; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using Newtonsoft.Json; |
||||
|
using System.Text.Json.Serialization; |
||||
|
|
||||
|
namespace LINGYUN.Abp.WeChat.Work.ExternalContact.MsgAudits.Request; |
||||
|
/// <summary>
|
||||
|
/// 获取单聊会话同意情况请求参数
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// 详情见: <see href="https://developer.work.weixin.qq.com/document/path/91782" />
|
||||
|
/// </remarks>
|
||||
|
public class WeChatWorkCheckSingleAgreeRequest : WeChatWorkRequest |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 内部成员的userid
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
[JsonProperty("userid")] |
||||
|
[JsonPropertyName("userid")] |
||||
|
public string UserId { get; } |
||||
|
/// <summary>
|
||||
|
/// 外部成员的exteranalopenid
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
[JsonProperty("exteranalopenid")] |
||||
|
[JsonPropertyName("exteranalopenid")] |
||||
|
public string ExteranalOpenId { get; } |
||||
|
public WeChatWorkCheckSingleAgreeRequest(string userId, string exteranalOpenId) |
||||
|
{ |
||||
|
UserId = userId; |
||||
|
ExteranalOpenId = exteranalOpenId; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using Newtonsoft.Json; |
||||
|
using System.Text.Json.Serialization; |
||||
|
|
||||
|
namespace LINGYUN.Abp.WeChat.Work.ExternalContact.MsgAudits.Request; |
||||
|
/// <summary>
|
||||
|
/// 获取会话内容存档内部群信息请求参数
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// 详情见: <see href="https://developer.work.weixin.qq.com/document/path/92951" />
|
||||
|
/// </remarks>
|
||||
|
public class WeChatWorkGetGroupChatRequest : WeChatWorkRequest |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 待查询的roomid
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
[JsonProperty("roomid")] |
||||
|
[JsonPropertyName("roomid")] |
||||
|
public string RoomId { get; } |
||||
|
public WeChatWorkGetGroupChatRequest(string roomId) |
||||
|
{ |
||||
|
RoomId = roomId; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,57 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using Newtonsoft.Json; |
||||
|
using System.Text.Json.Serialization; |
||||
|
|
||||
|
namespace LINGYUN.Abp.WeChat.Work.ExternalContact.MsgAudits.Request; |
||||
|
/// <summary>
|
||||
|
/// 获取会话内容存档开启成员列表请求参数
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// 详情见: <see href="https://developer.work.weixin.qq.com/document/path/91614" />
|
||||
|
/// </remarks>
|
||||
|
public class WeChatWorkGetPermitUserListRequest : WeChatWorkRequest |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 拉取对应版本的开启成员列表。1表示办公版;2表示服务版;3表示企业版。非必填,不填写的时候返回全量成员列表
|
||||
|
/// </summary>
|
||||
|
[CanBeNull] |
||||
|
[JsonProperty("cursor")] |
||||
|
[JsonPropertyName("cursor")] |
||||
|
public int? Type { get; } |
||||
|
private WeChatWorkGetPermitUserListRequest(int? type = null) |
||||
|
{ |
||||
|
Type = type; |
||||
|
} |
||||
|
/// <summary>
|
||||
|
/// 默认
|
||||
|
/// </summary>
|
||||
|
/// <returns></returns>
|
||||
|
public static WeChatWorkGetPermitUserListRequest Default() |
||||
|
{ |
||||
|
return new WeChatWorkGetPermitUserListRequest(); |
||||
|
} |
||||
|
/// <summary>
|
||||
|
/// 办公版
|
||||
|
/// </summary>
|
||||
|
/// <returns></returns>
|
||||
|
public static WeChatWorkGetPermitUserListRequest Office() |
||||
|
{ |
||||
|
return new WeChatWorkGetPermitUserListRequest(1); |
||||
|
} |
||||
|
/// <summary>
|
||||
|
/// 服务版
|
||||
|
/// </summary>
|
||||
|
/// <returns></returns>
|
||||
|
public static WeChatWorkGetPermitUserListRequest Service() |
||||
|
{ |
||||
|
return new WeChatWorkGetPermitUserListRequest(2); |
||||
|
} |
||||
|
/// <summary>
|
||||
|
/// 企业版
|
||||
|
/// </summary>
|
||||
|
/// <returns></returns>
|
||||
|
public static WeChatWorkGetPermitUserListRequest Enterprise() |
||||
|
{ |
||||
|
return new WeChatWorkGetPermitUserListRequest(3); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using LINGYUN.Abp.WeChat.Work.ExternalContact.MsgAudits.Models; |
||||
|
using Newtonsoft.Json; |
||||
|
using System.Text.Json.Serialization; |
||||
|
|
||||
|
namespace LINGYUN.Abp.WeChat.Work.ExternalContact.MsgAudits.Response; |
||||
|
/// <summary>
|
||||
|
/// 获取群聊会话同意情况响应参数
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// 详情见: <see href="https://developer.work.weixin.qq.com/document/path/91782" />
|
||||
|
/// </remarks>
|
||||
|
public class WeChatWorkCheckRoomAgreeResponse : WeChatWorkResponse |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 同意情况
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
[JsonProperty("agreeinfo")] |
||||
|
[JsonPropertyName("agreeinfo")] |
||||
|
public RoomAgreeInfo[] AgreeInfo { get; set; } |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using LINGYUN.Abp.WeChat.Work.ExternalContact.MsgAudits.Models; |
||||
|
using Newtonsoft.Json; |
||||
|
using System.Text.Json.Serialization; |
||||
|
|
||||
|
namespace LINGYUN.Abp.WeChat.Work.ExternalContact.MsgAudits.Response; |
||||
|
/// <summary>
|
||||
|
/// 获取单聊会话同意情况响应参数
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// 详情见: <see href="https://developer.work.weixin.qq.com/document/path/91782" />
|
||||
|
/// </remarks>
|
||||
|
public class WeChatWorkCheckSingleAgreeResponse : WeChatWorkResponse |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 同意情况
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
[JsonProperty("agreeinfo")] |
||||
|
[JsonPropertyName("agreeinfo")] |
||||
|
public UserAgreeInfo[] AgreeInfo { get; set; } |
||||
|
} |
||||
@ -0,0 +1,50 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using LINGYUN.Abp.WeChat.Work.ExternalContact.MsgAudits.Models; |
||||
|
using Newtonsoft.Json; |
||||
|
using System.Text.Json.Serialization; |
||||
|
|
||||
|
namespace LINGYUN.Abp.WeChat.Work.ExternalContact.MsgAudits.Response; |
||||
|
/// <summary>
|
||||
|
/// 获取会话内容存档内部群信息响应参数
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// 详情见: <see href="https://developer.work.weixin.qq.com/document/path/91782" />
|
||||
|
/// </remarks>
|
||||
|
public class WeChatWorkGetGroupChatResponse : WeChatWorkResponse |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// roomid对应的群名称
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
[JsonProperty("roomname")] |
||||
|
[JsonPropertyName("roomname")] |
||||
|
public string RoomName { get; set; } |
||||
|
/// <summary>
|
||||
|
/// roomid对应的群创建者,userid
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
[JsonProperty("creator")] |
||||
|
[JsonPropertyName("creator")] |
||||
|
public string Creator { get; set; } |
||||
|
/// <summary>
|
||||
|
/// roomid对应的群创建时间
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
[JsonProperty("room_create_time")] |
||||
|
[JsonPropertyName("room_create_time")] |
||||
|
public long RoomCreateTime { get; set; } |
||||
|
/// <summary>
|
||||
|
/// roomid对应的群公告
|
||||
|
/// </summary>
|
||||
|
[CanBeNull] |
||||
|
[JsonProperty("notice")] |
||||
|
[JsonPropertyName("notice")] |
||||
|
public string? Notice { get; set; } |
||||
|
/// <summary>
|
||||
|
/// roomid对应的群成员列表
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
[JsonProperty("members")] |
||||
|
[JsonPropertyName("members")] |
||||
|
public RoomMember[] Members { get; set; } |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using Newtonsoft.Json; |
||||
|
using System.Text.Json.Serialization; |
||||
|
|
||||
|
namespace LINGYUN.Abp.WeChat.Work.ExternalContact.MsgAudits.Response; |
||||
|
/// <summary>
|
||||
|
/// 获取会话内容存档开启成员列表响应参数
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// 详情见: <see href="https://developer.work.weixin.qq.com/document/path/91614" />
|
||||
|
/// </remarks>
|
||||
|
public class WeChatWorkGetPermitUserListResponse : WeChatWorkResponse |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 设置在开启范围内的成员的userid列表
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
[JsonProperty("ids")] |
||||
|
[JsonPropertyName("ids")] |
||||
|
public string[] Ids { get; set; } |
||||
|
} |
||||
@ -0,0 +1,76 @@ |
|||||
|
using LINGYUN.Abp.WeChat.Work.ExternalContact.Features; |
||||
|
using LINGYUN.Abp.WeChat.Work.ExternalContact.MsgAudits.Request; |
||||
|
using LINGYUN.Abp.WeChat.Work.ExternalContact.MsgAudits.Response; |
||||
|
using LINGYUN.Abp.WeChat.Work.ExternalContact.Token; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using System.Net.Http; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Features; |
||||
|
|
||||
|
namespace LINGYUN.Abp.WeChat.Work.ExternalContact.MsgAudits; |
||||
|
|
||||
|
[RequiresFeature(WeChatWorkExternalContactFeatureNames.Enable)] |
||||
|
public class WeChatWorkMsgAuditProvider : IWeChatWorkMsgAuditProvider, ISingletonDependency |
||||
|
{ |
||||
|
protected IHttpClientFactory HttpClientFactory { get; } |
||||
|
protected IWeChatWorkExternalContactTokenProvider WeChatWorkExternalContactTokenProvider { get; } |
||||
|
|
||||
|
public WeChatWorkMsgAuditProvider( |
||||
|
IHttpClientFactory httpClientFactory, |
||||
|
IWeChatWorkExternalContactTokenProvider weChatWorkExternalContactTokenProvider) |
||||
|
{ |
||||
|
HttpClientFactory = httpClientFactory; |
||||
|
WeChatWorkExternalContactTokenProvider = weChatWorkExternalContactTokenProvider; |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<WeChatWorkGetPermitUserListResponse> GetPermitUserListAsync( |
||||
|
WeChatWorkGetPermitUserListRequest request, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
Check.NotNull(request, nameof(request)); |
||||
|
|
||||
|
var token = await WeChatWorkExternalContactTokenProvider.GetTokenAsync(cancellationToken); |
||||
|
var client = HttpClientFactory.CreateWeChatWorkApiClient(); |
||||
|
|
||||
|
return await client.GetPermitUserListAsync(token.AccessToken, request, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<WeChatWorkCheckSingleAgreeResponse> CheckSingleAgreeAsync( |
||||
|
WeChatWorkCheckSingleAgreeRequest request, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
Check.NotNull(request, nameof(request)); |
||||
|
|
||||
|
var token = await WeChatWorkExternalContactTokenProvider.GetTokenAsync(cancellationToken); |
||||
|
var client = HttpClientFactory.CreateWeChatWorkApiClient(); |
||||
|
|
||||
|
return await client.CheckSingleAgreeAsync(token.AccessToken, request, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<WeChatWorkCheckRoomAgreeResponse> CheckRoomAgreeAsync( |
||||
|
WeChatWorkCheckRoomAgreeRequest request, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
Check.NotNull(request, nameof(request)); |
||||
|
|
||||
|
var token = await WeChatWorkExternalContactTokenProvider.GetTokenAsync(cancellationToken); |
||||
|
var client = HttpClientFactory.CreateWeChatWorkApiClient(); |
||||
|
|
||||
|
return await client.CheckRoomAgreeAsync(token.AccessToken, request, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<WeChatWorkGetGroupChatResponse> GetGroupChatAsync( |
||||
|
WeChatWorkGetGroupChatRequest request, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
Check.NotNull(request, nameof(request)); |
||||
|
|
||||
|
var token = await WeChatWorkExternalContactTokenProvider.GetTokenAsync(cancellationToken); |
||||
|
var client = HttpClientFactory.CreateWeChatWorkApiClient(); |
||||
|
|
||||
|
return await client.GetGroupChatAsync(token.AccessToken, request, cancellationToken); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
using LINGYUN.Abp.WeChat.Work.Localization; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.Settings; |
||||
|
|
||||
|
namespace LINGYUN.Abp.WeChat.Work.ExternalContact.Settings; |
||||
|
|
||||
|
public class WeChatWorkExternalContactSettingDefinitionProvider : SettingDefinitionProvider |
||||
|
{ |
||||
|
public override void Define(ISettingDefinitionContext context) |
||||
|
{ |
||||
|
context.Add( |
||||
|
new SettingDefinition( |
||||
|
WeChatWorkExternalContactSettingNames.Secret, |
||||
|
displayName: L("DisplayName:WeChatWorkExternalContact.Secret"), |
||||
|
description: L("Description:WeChatWorkExternalContact.Secret"), |
||||
|
isVisibleToClients: false, |
||||
|
isEncrypted: true) |
||||
|
.WithProviders( |
||||
|
DefaultValueSettingValueProvider.ProviderName, |
||||
|
ConfigurationSettingValueProvider.ProviderName, |
||||
|
GlobalSettingValueProvider.ProviderName, |
||||
|
TenantSettingValueProvider.ProviderName) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
private static ILocalizableString L(string name) |
||||
|
{ |
||||
|
return LocalizableString.Create<WeChatWorkResource>(name); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using LINGYUN.Abp.WeChat.Work.Settings; |
||||
|
|
||||
|
namespace LINGYUN.Abp.WeChat.Work.ExternalContact.Settings; |
||||
|
|
||||
|
public static class WeChatWorkExternalContactSettingNames |
||||
|
{ |
||||
|
public const string Prefix = WeChatWorkSettingNames.Prefix + ".ExternalContact"; |
||||
|
/// <summary>
|
||||
|
/// 客户联系应用Srcret
|
||||
|
/// </summary>
|
||||
|
public const string Secret = Prefix + ".Secret"; |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
using LINGYUN.Abp.WeChat.Work.Token.Models; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.WeChat.Work.ExternalContact.Token; |
||||
|
/// <summary>
|
||||
|
/// 客户联系应用Token提供者
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// 企业微信部分接口需要使用客户联系应用Token
|
||||
|
/// </remarks>
|
||||
|
public interface IWeChatWorkExternalContactTokenProvider |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 获取客户联系应用Token
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// 参考:https://developer.work.weixin.qq.com/document/path/91039
|
||||
|
/// </remarks>
|
||||
|
/// <param name="cancellationToken"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task<WeChatWorkToken> GetTokenAsync(CancellationToken cancellationToken = default); |
||||
|
} |
||||
@ -0,0 +1,50 @@ |
|||||
|
using LINGYUN.Abp.WeChat.Work.ExternalContact.Features; |
||||
|
using LINGYUN.Abp.WeChat.Work.ExternalContact.Settings; |
||||
|
using LINGYUN.Abp.WeChat.Work.Settings; |
||||
|
using LINGYUN.Abp.WeChat.Work.Token; |
||||
|
using LINGYUN.Abp.WeChat.Work.Token.Models; |
||||
|
using System.Net.Http; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Caching; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Features; |
||||
|
using Volo.Abp.Settings; |
||||
|
|
||||
|
namespace LINGYUN.Abp.WeChat.Work.ExternalContact.Token; |
||||
|
|
||||
|
[RequiresFeature(WeChatWorkExternalContactFeatureNames.Enable)] |
||||
|
public class WeChatWorkExternalContactTokenProvider : WeChatWorkTokenProviderBase, IWeChatWorkExternalContactTokenProvider, ISingletonDependency |
||||
|
{ |
||||
|
protected override string ProviderName => "WeChatWorkExternalContactToken"; |
||||
|
public WeChatWorkExternalContactTokenProvider( |
||||
|
ISettingProvider settingProvider, |
||||
|
IHttpClientFactory httpClientFactory, |
||||
|
IDistributedCache<WeChatWorkTokenCacheItem> cache) |
||||
|
: base(settingProvider, httpClientFactory, cache) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<WeChatWorkToken> GetTokenAsync(CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
var corpId = await SettingProvider.GetOrNullAsync(WeChatWorkSettingNames.Connection.CorpId); |
||||
|
var agentId = await SettingProvider.GetOrNullAsync(WeChatWorkSettingNames.Connection.AgentId); |
||||
|
var secret = await SettingProvider.GetOrNullAsync(WeChatWorkExternalContactSettingNames.Secret); |
||||
|
|
||||
|
Check.NotNullOrWhiteSpace(corpId, nameof(corpId)); |
||||
|
Check.NotNullOrWhiteSpace(agentId, nameof(agentId)); |
||||
|
Check.NotNullOrWhiteSpace(secret, nameof(secret)); |
||||
|
|
||||
|
return await GetTokenAsync(corpId, agentId, secret, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<WeChatWorkToken> GetTokenAsync( |
||||
|
string corpId, |
||||
|
string agentId, |
||||
|
string secret, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return (await InternalGetTokenAsync(corpId, agentId, secret, cancellationToken)).Token; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,97 @@ |
|||||
|
using LINGYUN.Abp.WeChat.Work.ExternalContact.MsgAudits.Request; |
||||
|
using LINGYUN.Abp.WeChat.Work.ExternalContact.MsgAudits.Response; |
||||
|
using System.Text; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace System.Net.Http; |
||||
|
internal static partial class HttpClientWeChatWorkRequestExtensions |
||||
|
{ |
||||
|
public async static Task<WeChatWorkGetPermitUserListResponse> GetPermitUserListAsync( |
||||
|
this HttpMessageInvoker client, |
||||
|
string accessToken, |
||||
|
WeChatWorkGetPermitUserListRequest request, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
var urlBuilder = new StringBuilder(); |
||||
|
urlBuilder.Append("/cgi-bin/msgaudit/get_permit_user_list"); |
||||
|
urlBuilder.AppendFormat("?access_token={0}", accessToken); |
||||
|
|
||||
|
using var httpRequest = new HttpRequestMessage( |
||||
|
HttpMethod.Post, |
||||
|
urlBuilder.ToString()) |
||||
|
{ |
||||
|
Content = new StringContent(request.SerializeToJson()) |
||||
|
}; |
||||
|
|
||||
|
using var httpResponse = await client.SendAsync(httpRequest, cancellationToken); |
||||
|
|
||||
|
return await httpResponse.DeserializeObjectAsync<WeChatWorkGetPermitUserListResponse>(); |
||||
|
} |
||||
|
|
||||
|
public async static Task<WeChatWorkCheckSingleAgreeResponse> CheckSingleAgreeAsync( |
||||
|
this HttpMessageInvoker client, |
||||
|
string accessToken, |
||||
|
WeChatWorkCheckSingleAgreeRequest request, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
var urlBuilder = new StringBuilder(); |
||||
|
urlBuilder.Append("/cgi-bin/msgaudit/check_single_agree"); |
||||
|
urlBuilder.AppendFormat("?access_token={0}", accessToken); |
||||
|
|
||||
|
var httpRequest = new HttpRequestMessage( |
||||
|
HttpMethod.Post, |
||||
|
urlBuilder.ToString()) |
||||
|
{ |
||||
|
Content = new StringContent(request.SerializeToJson()) |
||||
|
}; |
||||
|
|
||||
|
using var httpResponse = await client.SendAsync(httpRequest, cancellationToken); |
||||
|
|
||||
|
return await httpResponse.DeserializeObjectAsync<WeChatWorkCheckSingleAgreeResponse>(); |
||||
|
} |
||||
|
|
||||
|
public async static Task<WeChatWorkCheckRoomAgreeResponse> CheckRoomAgreeAsync( |
||||
|
this HttpMessageInvoker client, |
||||
|
string accessToken, |
||||
|
WeChatWorkCheckRoomAgreeRequest request, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
var urlBuilder = new StringBuilder(); |
||||
|
urlBuilder.Append("/cgi-bin/msgaudit/check_room_agree"); |
||||
|
urlBuilder.AppendFormat("?access_token={0}", accessToken); |
||||
|
|
||||
|
var httpRequest = new HttpRequestMessage( |
||||
|
HttpMethod.Post, |
||||
|
urlBuilder.ToString()) |
||||
|
{ |
||||
|
Content = new StringContent(request.SerializeToJson()) |
||||
|
}; |
||||
|
|
||||
|
using var httpResponse = await client.SendAsync(httpRequest, cancellationToken); |
||||
|
|
||||
|
return await httpResponse.DeserializeObjectAsync<WeChatWorkCheckRoomAgreeResponse>(); |
||||
|
} |
||||
|
|
||||
|
public async static Task<WeChatWorkGetGroupChatResponse> GetGroupChatAsync( |
||||
|
this HttpMessageInvoker client, |
||||
|
string accessToken, |
||||
|
WeChatWorkGetGroupChatRequest request, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
var urlBuilder = new StringBuilder(); |
||||
|
urlBuilder.Append("/cgi-bin/msgaudit/groupchat/get"); |
||||
|
urlBuilder.AppendFormat("?access_token={0}", accessToken); |
||||
|
|
||||
|
using var httpRequest = new HttpRequestMessage( |
||||
|
HttpMethod.Post, |
||||
|
urlBuilder.ToString()) |
||||
|
{ |
||||
|
Content = new StringContent(request.SerializeToJson()) |
||||
|
}; |
||||
|
|
||||
|
using var httpResponse = await client.SendAsync(httpRequest, cancellationToken); |
||||
|
|
||||
|
return await httpResponse.DeserializeObjectAsync<WeChatWorkGetGroupChatResponse>(); |
||||
|
} |
||||
|
} |
||||
@ -1,5 +1,4 @@ |
|||||
namespace System.Net.Http; |
namespace System.Net.Http; |
||||
internal static partial class HttpClientWeChatWorkRequestExtensions |
internal static partial class HttpClientWeChatWorkRequestExtensions |
||||
{ |
{ |
||||
|
|
||||
} |
} |
||||
|
|||||
@ -0,0 +1,111 @@ |
|||||
|
using LINGYUN.Abp.WeChat.Work.Token.Models; |
||||
|
using Microsoft.Extensions.Caching.Distributed; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Microsoft.Extensions.Logging.Abstractions; |
||||
|
using System; |
||||
|
using System.Net.Http; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Caching; |
||||
|
using Volo.Abp.Settings; |
||||
|
|
||||
|
namespace LINGYUN.Abp.WeChat.Work.Token; |
||||
|
public abstract class WeChatWorkTokenProviderBase |
||||
|
{ |
||||
|
public ILogger<WeChatWorkTokenProviderBase> Logger { get; set; } |
||||
|
|
||||
|
protected abstract string ProviderName { get; } |
||||
|
protected ISettingProvider SettingProvider { get; } |
||||
|
protected IHttpClientFactory HttpClientFactory { get; } |
||||
|
protected IDistributedCache<WeChatWorkTokenCacheItem> WeChatWorkTokenCache { get; } |
||||
|
protected WeChatWorkTokenProviderBase( |
||||
|
ISettingProvider settingProvider, |
||||
|
IHttpClientFactory httpClientFactory, |
||||
|
IDistributedCache<WeChatWorkTokenCacheItem> cache) |
||||
|
{ |
||||
|
HttpClientFactory = httpClientFactory; |
||||
|
SettingProvider = settingProvider; |
||||
|
WeChatWorkTokenCache = cache; |
||||
|
|
||||
|
Logger = NullLogger<WeChatWorkTokenProviderBase>.Instance; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 获取缓存中的Token配置
|
||||
|
/// </summary>
|
||||
|
/// <param name="corpId"></param>
|
||||
|
/// <param name="agentId"></param>
|
||||
|
/// <param name="secret"></param>
|
||||
|
/// <param name="cancellationToken"></param>
|
||||
|
/// <returns></returns>
|
||||
|
protected async virtual Task<WeChatWorkTokenCacheItem> InternalGetTokenAsync( |
||||
|
string corpId, |
||||
|
string agentId, |
||||
|
string secret, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
Check.NotNullOrEmpty(corpId, nameof(corpId)); |
||||
|
Check.NotNullOrEmpty(agentId, nameof(agentId)); |
||||
|
Check.NotNullOrEmpty(secret, nameof(secret)); |
||||
|
|
||||
|
var cacheKey = WeChatWorkTokenCacheItem.CalculateCacheKey(ProviderName, corpId, agentId); |
||||
|
|
||||
|
return await GetCacheItemAsync(cacheKey, ProviderName, corpId, agentId, secret, cancellationToken); |
||||
|
} |
||||
|
/// <summary>
|
||||
|
/// 获取或刷新分布式缓存中的Token配置
|
||||
|
/// </summary>
|
||||
|
/// <param name="cacheKey"></param>
|
||||
|
/// <param name="provider"></param>
|
||||
|
/// <param name="corpId"></param>
|
||||
|
/// <param name="agentId"></param>
|
||||
|
/// <param name="secret"></param>
|
||||
|
/// <param name="cancellationToken"></param>
|
||||
|
/// <returns></returns>
|
||||
|
protected async virtual Task<WeChatWorkTokenCacheItem> GetCacheItemAsync( |
||||
|
string cacheKey, |
||||
|
string provider, |
||||
|
string corpId, |
||||
|
string agentId, |
||||
|
string secret, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
var cacheItem = await WeChatWorkTokenCache.GetAsync(cacheKey, token: cancellationToken); |
||||
|
|
||||
|
if (cacheItem != null) |
||||
|
{ |
||||
|
Logger.LogDebug($"Found WeChatWorkToken in the cache: {cacheKey}"); |
||||
|
return cacheItem; |
||||
|
} |
||||
|
|
||||
|
Logger.LogDebug($"Not found WeChatWorkToken in the cache, getting from the httpClient: {cacheKey}"); |
||||
|
|
||||
|
var client = HttpClientFactory.CreateWeChatWorkApiClient(); |
||||
|
|
||||
|
var request = new WeChatWorkTokenRequest |
||||
|
{ |
||||
|
CorpId = corpId, |
||||
|
CorpSecret = secret, |
||||
|
}; |
||||
|
|
||||
|
var tokenResponse = await client.GetTokenAsync(request, cancellationToken); |
||||
|
var token = tokenResponse.ToWeChatWorkToken(); |
||||
|
cacheItem = new WeChatWorkTokenCacheItem(corpId, agentId, token); |
||||
|
|
||||
|
Logger.LogDebug($"Setting the cache item: {cacheKey}"); |
||||
|
|
||||
|
var cacheOptions = new DistributedCacheEntryOptions |
||||
|
{ |
||||
|
// 设置绝对过期时间为Token有效期剩余的二分钟
|
||||
|
AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(token.ExpiresIn - 100), |
||||
|
}; |
||||
|
|
||||
|
await WeChatWorkTokenCache.SetAsync(cacheKey, cacheItem, cacheOptions, token: cancellationToken); |
||||
|
|
||||
|
Logger.LogDebug($"Finished setting the cache item: {cacheKey}"); |
||||
|
|
||||
|
return cacheItem; |
||||
|
} |
||||
|
} |
||||
@ -1,17 +1,20 @@ |
|||||
using System.Threading; |
using LINGYUN.Abp.WeChat.Work.Security.Models; |
||||
|
using System.Threading; |
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
|
|
||||
namespace System.Net.Http; |
namespace System.Net.Http; |
||||
internal static partial class HttpClientWeChatWorkRequestExtensions |
internal static partial class HttpClientWeChatWorkRequestExtensions |
||||
{ |
{ |
||||
public async static Task<HttpResponseMessage> GetServerDomainIpAsync( |
public async static Task<WeChatServerDomainResponse> GetServerDomainIpAsync( |
||||
this HttpMessageInvoker client, |
this HttpMessageInvoker client, |
||||
string accessToken, |
string accessToken, |
||||
CancellationToken cancellationToken = default) |
CancellationToken cancellationToken = default) |
||||
{ |
{ |
||||
var httpRequest = new HttpRequestMessage(HttpMethod.Get, |
using var httpRequest = new HttpRequestMessage(HttpMethod.Get, |
||||
$"/cgi-bin/security/get_server_domain_ip?access_token={accessToken}"); ; |
$"/cgi-bin/security/get_server_domain_ip?access_token={accessToken}"); ; |
||||
|
|
||||
return await client.SendAsync(httpRequest, cancellationToken); |
using var httpResponse = await client.SendAsync(httpRequest, cancellationToken); |
||||
|
|
||||
|
return await httpResponse.DeserializeObjectAsync<WeChatServerDomainResponse>(); |
||||
} |
} |
||||
} |
} |
||||
|
|||||
Loading…
Reference in new issue