添加项目文件。

This commit is contained in:
2023-03-13 15:00:34 +08:00
parent 42bf06ca3e
commit 1d73df3235
1205 changed files with 185078 additions and 0 deletions

View File

@@ -0,0 +1,455 @@
using DingTalk.Api;
using DingTalk.Api.Request;
using DingTalk.Api.Response;
using Mapster;
using static DingTalk.Api.Request.OapiRobotSendRequest;
using static DingTalk.Api.Response.OapiV2DepartmentListsubResponse;
using static DingTalk.Api.Response.OapiV2UserListResponse;
namespace JNPF.Extras.Thirdparty.DingDing;
/// <summary>
/// 钉钉.
/// </summary>
public class DingUtil
{
/// <summary>
/// 访问令牌.
/// </summary>
public string token { get; private set; }
/// <summary>
/// 构造函数.
/// </summary>
/// <param name="appKey">企业号ID.</param>
/// <param name="appSecret">凭证密钥.</param>
public DingUtil(string appKey, string appSecret)
{
token = GetDingToken(appKey, appSecret);
}
/// <summary>
/// 构造函数.
/// </summary>
/// <param name="appKey">企业号ID.</param>
/// <param name="appSecret">凭证密钥.</param>
public DingUtil()
{
}
/// <summary>
/// 钉钉token.
/// </summary>
/// <param name="appKey">企业号ID.</param>
/// <param name="appSecret">凭证密钥.</param>
/// <returns></returns>
public string GetDingToken(string appKey, string appSecret)
{
try
{
var tokenurl = "https://oapi.dingtalk.com/gettoken";
DefaultDingTalkClient client = new DefaultDingTalkClient(tokenurl);
OapiGettokenRequest req = new OapiGettokenRequest();
req.SetHttpMethod("GET");
req.Appkey = appKey;
req.Appsecret = appSecret;
OapiGettokenResponse response = client.Execute(req);
if (response.Errcode == 0)
{
// 过期时间
var timeout = DateTime.Now.Subtract(DateTime.Now.AddSeconds(response.ExpiresIn));
return response.AccessToken;
}
else
{
throw new Exception("获取钉钉Token失败,失败原因:" + response.Errmsg);
}
}
catch (Exception ex)
{
return string.Empty;
}
}
/// <summary>
/// 钉钉登录.
/// </summary>
/// <param name="code"></param>
/// <returns></returns>
public object DingLogin(string code)
{
var url = "https://oapi.dingtalk.com/user/getuserinfo";
DefaultDingTalkClient client = new DefaultDingTalkClient(url);
OapiUserGetuserinfoRequest req = new OapiUserGetuserinfoRequest();
req.Code = code;
req.SetHttpMethod("GET");
OapiUserGetuserinfoResponse rsp = client.Execute(req, token);
if (rsp.IsError)
throw new Exception(rsp.ErrMsg);
return rsp.Body;
}
#region
/// <summary>
/// 添加钉钉用户.
/// </summary>
/// <param name="dingModel"></param>
/// <returns></returns>
public string CreateUser(DingUserParameter dingModel, ref string msg)
{
try
{
var userId = GetUserIdByMobile(dingModel.Mobile);
if (!string.IsNullOrEmpty(userId))
return userId;
var url = "https://oapi.dingtalk.com/topapi/v2/user/create";
DefaultDingTalkClient client = new DefaultDingTalkClient(url);
OapiV2UserCreateRequest req = dingModel.Adapt<OapiV2UserCreateRequest>();
OapiV2UserCreateResponse rsp = client.Execute(req, token);
if (!rsp.IsError && rsp.Result != null)
{
return rsp.Result.Userid;
}
else
{
msg = rsp.Errmsg;
return string.Empty;
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
/// <summary>
/// 修改钉钉用户.
/// </summary>
/// <param name="dingModel">钉钉用户参数.</param>
/// <param name="msg">返回信息.</param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public bool UpdateUser(DingUserParameter dingModel, ref string msg)
{
try
{
var url = "https://oapi.dingtalk.com/topapi/v2/user/update";
DefaultDingTalkClient client = new DefaultDingTalkClient(url);
OapiV2UserUpdateRequest req = dingModel.Adapt<OapiV2UserUpdateRequest>();
OapiV2UserUpdateResponse rsp = client.Execute(req, token);
if (rsp.IsError)
msg = rsp.Errmsg;
return rsp.Errcode == 0;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
/// <summary>
/// 修改钉钉用户.
/// </summary>
/// <param name="dingModel"></param>
/// <param name="msg">返回信息.</param>
public void DeleteUser(DingUserParameter dingModel, ref string msg)
{
try
{
var url = "https://oapi.dingtalk.com/topapi/v2/user/delete";
DefaultDingTalkClient client = new DefaultDingTalkClient(url);
OapiV2UserDeleteRequest req = dingModel.Adapt<OapiV2UserDeleteRequest>();
OapiV2UserDeleteResponse rsp = client.Execute(req, token);
if (rsp.IsError)
{
msg = rsp.Errmsg;
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
/// <summary>
/// 根据手机号查询用户
/// 员工离职后无法再通过手机号获取userId.
/// </summary>
/// <param name="mobile"></param>
/// <returns></returns>
public string GetUserIdByMobile(string mobile)
{
try
{
var url = "https://oapi.dingtalk.com/topapi/v2/user/getbymobile";
DefaultDingTalkClient client = new DefaultDingTalkClient(url);
OapiV2UserGetbymobileRequest req = new OapiV2UserGetbymobileRequest() { Mobile = mobile };
OapiV2UserGetbymobileResponse rsp = client.Execute(req, token);
if (!rsp.IsError && rsp.Result != null)
{
return rsp.Result.Userid;
}
else
{
return string.Empty;
}
}
catch (Exception ex)
{
return string.Empty;
}
}
/// <summary>
/// 获取所有用户详情.
/// </summary>
/// <returns></returns>
public List<ListUserResponseDomain> GetUserList()
{
try
{
var url = "https://oapi.dingtalk.com/topapi/v2/user/list";
DefaultDingTalkClient client = new DefaultDingTalkClient(url);
var userList = new List<ListUserResponseDomain>();
var depList = new List<long>();
depList.Add(1);
GetDepIdList(1, ref depList);
if (depList.Count > 0)
{
foreach (var item in depList)
{
OapiV2UserListRequest req = new OapiV2UserListRequest() { DeptId = item, Cursor = 0, Size = 10 };
OapiV2UserListResponse rsp = client.Execute(req, token);
if (rsp.Errcode == 0 && rsp.Errmsg == "ok" && rsp.Result != null && rsp.Result.List != null)
{
userList = userList.Union(rsp.Result.List).ToList();
}
}
}
return userList;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
#endregion
#region
/// <summary>
/// 添加钉钉部门.
/// </summary>
/// <param name="dingModel"></param>
/// <param name="msg">返回信息.</param>
/// <returns></returns>
public string CreateDep(DingDepartmentParameter dingModel, ref string msg)
{
try
{
var url = "https://oapi.dingtalk.com/topapi/v2/department/create";
DefaultDingTalkClient client = new DefaultDingTalkClient(url);
OapiV2DepartmentCreateRequest req = dingModel.Adapt<OapiV2DepartmentCreateRequest>();
OapiV2DepartmentCreateResponse rsp = client.Execute(req, token);
if (rsp.Errcode == 0)
{
if (!rsp.IsError && rsp.Result != null)
{
return rsp.Result.DeptId.ToString();
}
else
{
msg = string.Format("【组织{0}创建失败】{1}", dingModel.Name, rsp.Errmsg);
return string.Empty;
}
}
else
{
msg = string.Format("【组织{0}创建失败】{1}", dingModel.Name, rsp.Errmsg);
return string.Empty;
}
}
catch (Exception ex)
{
msg = string.Format("【组织{0}创建失败】{1}", dingModel.Name, ex.Message);
throw new Exception(ex.Message);
}
}
/// <summary>
/// 修改钉钉部门.
/// </summary>
/// <param name="dingModel"></param>
/// <param name="msg">返回信息.</param>
public bool UpdateDep(DingDepartmentParameter dingModel, ref string msg)
{
try
{
var url = "https://oapi.dingtalk.com/topapi/v2/department/update";
DefaultDingTalkClient client = new DefaultDingTalkClient(url);
OapiV2DepartmentUpdateRequest req = dingModel.Adapt<OapiV2DepartmentUpdateRequest>();
OapiV2DepartmentUpdateResponse rsp = client.Execute(req, token);
if (!rsp.IsError)
{
msg = rsp.IsError ? string.Format("【组织{0}修改失败】{1}", dingModel.Name, rsp.Errmsg) : string.Empty;
return !rsp.IsError;
}
else
{
msg = string.Format("【组织{0}修改失败】{1}", dingModel.Name, rsp.Errmsg);
return false;
}
}
catch (Exception ex)
{
msg = string.Format("【组织{0}修改失败】{1}", dingModel.Name, ex.Message);
return false;
}
}
/// <summary>
/// 删除钉钉部门.
/// </summary>
/// <param name="dingModel"></param>
/// <param name="msg">返回信息.</param>
public bool DeleteDep(DingDepartmentParameter dingModel, ref string msg)
{
try
{
var url = "https://oapi.dingtalk.com/topapi/v2/department/delete";
DefaultDingTalkClient client = new DefaultDingTalkClient(url);
OapiV2DepartmentDeleteRequest req = dingModel.Adapt<OapiV2DepartmentDeleteRequest>();
OapiV2DepartmentDeleteResponse rsp = client.Execute(req, token);
if (!rsp.IsError)
{
msg = rsp.IsError ? rsp.Errmsg : string.Empty;
return !rsp.IsError;
}
else
{
msg = rsp.Errmsg;
return false;
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
/// <summary>
/// 获取部门列表.
/// </summary>
/// <returns></returns>
public List<DeptBaseResponseDomain> GetDepList()
{
try
{
var depId = new List<long>();
depId.Add(1);
GetDepIdList(1, ref depId);
var list = new List<DeptBaseResponseDomain>();
if (depId.Count > 0)
{
var url = "https://oapi.dingtalk.com/topapi/v2/department/listsub";
DefaultDingTalkClient client = new DefaultDingTalkClient(url);
OapiV2DepartmentListsubRequest req = new OapiV2DepartmentListsubRequest();
foreach (var item in depId)
{
req.DeptId = item;
OapiV2DepartmentListsubResponse rsp = client.Execute(req, token);
if (rsp.Errcode == 0 && rsp.Errmsg == "ok" && rsp.Result != null)
{
list = list.Union(rsp.Result).ToList();
}
}
}
return list;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
/// <summary>
/// 获取部门id列表.
/// </summary>
/// <returns></returns>
public void GetDepIdList(long depId, ref List<long> ids)
{
try
{
var url = "https://oapi.dingtalk.com/topapi/v2/department/listsubid";
DefaultDingTalkClient client = new DefaultDingTalkClient(url);
OapiV2DepartmentListsubidRequest req = new OapiV2DepartmentListsubidRequest();
req.DeptId = depId;
OapiV2DepartmentListsubidResponse rsp = client.Execute(req, token);
if (rsp.Errcode == 0 && rsp.Errmsg == "ok" && rsp.Result != null)
{
ids = ids.Union(rsp.Result.DeptIdList).ToList();
foreach (var item in rsp.Result.DeptIdList)
{
GetDepIdList(item, ref ids);
}
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
#endregion
/// <summary>
/// 发送工作消息.
/// </summary>
/// <param name="dingModel"></param>
public void SendWorkMsg(DingWorkMessageParameter dingModel)
{
var url = "https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2";
DefaultDingTalkClient client = new DefaultDingTalkClient(url);
OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request()
{
AgentId = long.Parse(dingModel.agentId),
UseridList = dingModel.toUsers,
Msg = dingModel.msg
};
request.SetHttpMethod("POST");
OapiMessageCorpconversationAsyncsendV2Response response = client.Execute(request, token);
if (response.IsError)
{
throw new Exception(response.ErrMsg);
}
}
/// <summary>
/// 发送群聊消息.
/// </summary>
/// <param name="url"></param>
/// <param name="content"></param>
public void SendGroupMsg(string url, string content)
{
DefaultDingTalkClient client = new DefaultDingTalkClient(url);
OapiRobotSendRequest request = new OapiRobotSendRequest();
request.Msgtype = "text";
TextDomain text = new TextDomain();
text.Content = content;
request.Text_ = text;
request.SetHttpMethod("POST");
OapiRobotSendResponse response = client.Execute(request);
if (response.IsError)
{
throw new Exception(response.ErrMsg);
}
}
}

View File

@@ -0,0 +1,112 @@
namespace JNPF.Extras.Thirdparty.DingDing;
/// <summary>
/// 钉钉部门参数.
/// </summary>
public class DingDepartmentParameter
{
/// <summary>
/// 部门群是否包含外包部门.
/// </summary>
public bool? GroupContainOuterDept { get; set; }
/// <summary>
/// 父部门ID.
/// </summary>
public long? ParentId { get; set; }
/// <summary>
/// 部门员工可见员工列表.
/// </summary>
public string OuterPermitUsers { get; set; }
/// <summary>
/// 部门员工可见部门列表.
/// </summary>
public string OuterPermitDepts { get; set; }
/// <summary>
/// 本部门成员是否只能看到所在部门及下级部门通讯录.
/// </summary>
public bool? OuterDeptOnlySelf { get; set; }
/// <summary>
/// 是否限制本部门成员查看通讯录.
/// </summary>
public bool? OuterDept { get; set; }
/// <summary>
/// 企业群群主的userid.
/// </summary>
public string OrgDeptOwner { get; set; }
/// <summary>
/// 在父部门中的排序值.
/// </summary>
public long? Order { get; set; }
/// <summary>
/// 部门名称长度限制为1~64个字符不允许包含字符-’‘,’以及‘,.
/// </summary>
public string Name { get; set; }
/// <summary>
/// 语言.
/// </summary>
public string Language { get; set; }
/// <summary>
/// 是否隐藏本部门.
/// </summary>
public bool? HideDept { get; set; }
/// <summary>
/// 部门群是否包含子部门.
/// </summary>
public bool? GroupContainSubDept { get; set; }
/// <summary>
/// 指定可以查看本部门的用户userid列表.
/// </summary>
public string UserPermits { get; set; }
/// <summary>
/// 部门群是否包含隐藏部门.
/// </summary>
public bool? GroupContainHiddenDept { get; set; }
/// <summary>
/// 扩展.
/// </summary>
public string Extension { get; set; }
/// <summary>
/// 指定可以查看本部门的其他部门列表.
/// </summary>
public string DeptPermits { get; set; }
/// <summary>
/// 部门的主管userid列表.
/// </summary>
public string DeptManagerUseridList { get; set; }
/// <summary>
/// 部门ID.
/// </summary>
public long? DeptId { get; set; }
/// <summary>
/// 是否创建一个关联此部门的企业群.
/// </summary>
public bool? CreateDeptGroup { get; set; }
/// <summary>
/// 当部门群已经创建后,有新人加入部门时是否会自动加入该群.
/// </summary>
public bool? AutoAddUser { get; set; }
/// <summary>
/// 部门标识字段,开发者可用该字段来唯一标识一个部门,并与钉钉外部通讯录里的部门做映射.
/// </summary>
public string SourceIdentifier { get; set; }
}

View File

@@ -0,0 +1,102 @@
namespace JNPF.Extras.Thirdparty.DingDing;
/// <summary>
/// 钉钉用户.
/// </summary>
public class DingUserParameter
{
/// <summary>
/// 入职时间Unix时间戳单位毫秒.
/// </summary>
public long? HiredDate { get; set; }
/// <summary>
/// 备注长度最大2000个字符.
/// </summary>
public string Remark { get; set; }
/// <summary>
/// 员工的企业邮箱.
/// </summary>
public string OrgEmail { get; set; }
/// <summary>
/// 员工名称.
/// </summary>
public string Name { get; set; }
/// <summary>
/// 手机号码,企业内必须唯一,不可重复.
/// </summary>
public string Mobile { get; set; }
/// <summary>
/// 语言.
/// </summary>
public string Language { get; set; }
/// <summary>
/// 员工工号.
/// </summary>
public string JobNumber { get; set; }
/// <summary>
/// 钉钉专属帐号初始密码.
/// </summary>
public string InitPassword { get; set; }
/// <summary>
/// 职位.
/// </summary>
public string Title { get; set; }
/// <summary>
/// 是否号码隐藏.
/// </summary>
public bool? HideMobile { get; set; }
/// <summary>
/// 扩展属性可以设置多种属性最大长度2000个字符.
/// </summary>
public string Extension { get; set; }
/// <summary>
/// 员工邮箱长度最大50个字符。企业内必须唯一不可重复.
/// </summary>
public string Email { get; set; }
/// <summary>
/// 员工在对应的部门中的职位.
/// </summary>
public string DeptTitleList { get; set; }
/// <summary>
/// 员工在对应的部门中的排序.
/// </summary>
public string DeptOrderList { get; set; }
/// <summary>
/// 所属部门id列表.
/// </summary>
public string DeptIdList { get; set; }
/// <summary>
/// 员工唯一标识ID不可修改企业内必须唯一.
/// </summary>
public string Userid { get; set; }
/// <summary>
/// 办公地点.
/// </summary>
public string WorkPlace { get; set; }
/// <summary>
/// 是否开启高管模式.
/// </summary>
public bool? SeniorMode { get; set; }
/// <summary>
/// 分机号.
/// </summary>
public string Telephone { get; set; }
}

View File

@@ -0,0 +1,22 @@
namespace JNPF.Extras.Thirdparty.DingDing;
/// <summary>
/// 钉钉消息.
/// </summary>
public class DingWorkMessageParameter
{
/// <summary>
/// 接收人.
/// </summary>
public string toUsers { get; set; }
/// <summary>
/// 消息内容.
/// </summary>
public string msg { get; set; }
/// <summary>
/// 微应用的AgentID.
/// </summary>
public string agentId { get; set; }
}

View File

@@ -0,0 +1,37 @@
namespace JNPF.Extras.Thirdparty.Email;
/// <summary>
/// 邮件文件参数信息.
/// </summary>
public class MailFileParameterInfo
{
/// <summary>
/// 文件id.
/// </summary>
public string fileId { get; set; }
/// <summary>
/// 文件名.
/// </summary>
public string fileName { get; set; }
/// <summary>
/// 文件大小.
/// </summary>
public string fileSize { get; set; }
/// <summary>
/// 文件时间.
/// </summary>
public DateTime fileTime { get; set; }
/// <summary>
/// 文件状态.
/// </summary>
public string fileState { get; set; }
/// <summary>
/// 文件名.
/// </summary>
public string name { get; set; }
}

View File

@@ -0,0 +1,62 @@
namespace JNPF.Extras.Thirdparty.Email;
/// <summary>
/// 邮件信息.
/// </summary>
public class MailInfo
{
/// <summary>
/// 消息标识符.
/// </summary>
public string UID { get; set; }
/// <summary>
/// 收件人邮箱.
/// </summary>
public string To { get; set; }
/// <summary>
/// 收件人名称
/// </summary>
public string ToName { get; set; }
/// <summary>
/// 抄送人.
/// </summary>
public string CC { get; set; }
/// <summary>
/// 抄送人名称.
/// </summary>
public string CCName { get; set; }
/// <summary>
/// 密送人.
/// </summary>
public string Bcc { get; set; }
/// <summary>
/// 密送人名称.
/// </summary>
public string BccName { get; set; }
/// <summary>
/// 消息主题.
/// </summary>
public string Subject { get; set; }
/// <summary>
/// 文本格式.
/// </summary>
public string BodyText { get; set; }
/// <summary>
/// 附件.
/// </summary>
public List<MailFileParameterInfo> Attachment { get; set; }
/// <summary>
/// 收件时间.
/// </summary>
public DateTime Date { get; set; }
}

View File

@@ -0,0 +1,47 @@
namespace JNPF.Extras.Thirdparty.Email;
/// <summary>
/// 邮箱参数信息.
/// </summary>
public class MailParameterInfo
{
/// <summary>
/// POP3服务.
/// </summary>
public string POP3Host { get; set; }
/// <summary>
/// POP3端口.
/// </summary>
public int POP3Port { get; set; }
/// <summary>
/// SMTP服务.
/// </summary>
public string SMTPHost { get; set; }
/// <summary>
/// SMTP端口.
/// </summary>
public int SMTPPort { get; set; }
/// <summary>
/// 账户.
/// </summary>
public string Account { get; set; }
/// <summary>
/// 账户名称.
/// </summary>
public string AccountName { get; set; }
/// <summary>
/// 密码.
/// </summary>
public string Password { get; set; }
/// <summary>
/// SSL.
/// </summary>
public bool Ssl { get; set; } = false;
}

276
common/Tnb.Thirdparty/Email/MailUtil.cs vendored Normal file
View File

@@ -0,0 +1,276 @@
using System.Text;
using JNPF.Common.Configuration;
using JNPF.Common.Extension;
using JNPF.Common.Security;
using MailKit.Net.Pop3;
using MailKit.Net.Smtp;
using MimeKit;
using MimeKit.Text;
using Yitter.IdGenerator;
namespace JNPF.Extras.Thirdparty.Email;
/// <summary>
/// 邮箱帮助类.
/// </summary>
public class MailUtil
{
private static string mailFilePath = FileVariable.EmailFilePath;
/// <summary>
/// 发送协议Smtp.
/// </summary>
/// <param name="mailConfig">配置</param>
/// <param name="mailModel">信息</param>
public static void Send(MailParameterInfo mailConfig, MailInfo mailModel)
{
MimeMessage message = new MimeMessage();
// 发送方信息
message.From.AddRange(new MailboxAddress[] { new MailboxAddress(mailConfig.AccountName, mailConfig.Account) });
// 发件人
if (!string.IsNullOrEmpty(mailModel.To))
{
List<MailboxAddress> toAddress = new List<MailboxAddress>();
foreach (var item in mailModel.To.Split(','))
{
toAddress.Add(new MailboxAddress(item));
}
message.To.AddRange(toAddress.ToArray());
}
// 抄送人
if (!string.IsNullOrEmpty(mailModel.CC))
{
List<MailboxAddress> ccAddress = new List<MailboxAddress>();
foreach (var item in mailModel.CC.Split(','))
{
ccAddress.Add(new MailboxAddress(item));
}
message.Cc.AddRange(ccAddress.ToArray());
}
// 密送人
if (!string.IsNullOrEmpty(mailModel.Bcc))
{
List<MailboxAddress> bccAddress = new List<MailboxAddress>();
foreach (var item in mailModel.Bcc.Split(','))
{
bccAddress.Add(new MailboxAddress(item));
}
message.Bcc.AddRange(bccAddress.ToArray());
}
message.Subject = mailModel.Subject;
TextPart body = new TextPart(TextFormat.Html) { Text = mailModel.BodyText };
MimeEntity entity = body;
// 附件
if (mailModel.Attachment != null)
{
var mult = new Multipart("mixed") { body };
foreach (var attachment in mailModel.Attachment)
{
var file = new FileInfo(Path.Combine(mailFilePath , attachment.fileId));
if (file.Exists)
{
var mimePart = new MimePart();
mimePart.Content = new MimeContent(file.OpenRead());
mimePart.ContentDisposition = new ContentDisposition(ContentDisposition.Attachment);
mimePart.ContentTransferEncoding = ContentEncoding.Base64;
mimePart.FileName = attachment.fileName;
mult.Add(mimePart);
}
}
entity = mult;
}
message.Body = entity;
message.Date = DateTime.Now;
using (var client = new SmtpClient())
{
client.ServerCertificateValidationCallback = (s, c, h, e) => true;
client.Connect(mailConfig.SMTPHost, mailConfig.SMTPPort, mailConfig.Ssl);
client.Authenticate(mailConfig.Account, mailConfig.Password);
client.Send(message);
client.Disconnect(true);
}
}
/// <summary>
/// 获取协议Pop3.
/// </summary>
/// <param name="mailConfig">配置.</param>
/// <param name="receiveCount">已收邮件数、注意:如果已收邮件数和邮件数量一致则不获取.</param>
/// <returns></returns>
public static List<MailInfo> Get(MailParameterInfo mailConfig, int receiveCount)
{
var resultList = new List<MailInfo>();
using (var client = new Pop3Client())
{
client.ServerCertificateValidationCallback = (s, c, h, e) => true;
client.Connect(mailConfig.POP3Host, mailConfig.POP3Port, mailConfig.Ssl);
client.Authenticate(mailConfig.Account, mailConfig.Password);
if (receiveCount == client.Count)
return resultList;
for (int i = client.Count - 1; receiveCount <= i; i--)
{
var message = client.GetMessage(i);
var from = (MailboxAddress)message.From[0];
var attachment = message.Attachments;
resultList.Add(new MailInfo()
{
UID = message.MessageId,
To = from.Address,
ToName = from.Name,
Subject = message.Subject,
BodyText = message.HtmlBody,
Attachment = GetEmailAttachments(attachment, message.MessageId),
Date = message.Date.ToString().ParseToDateTime(),
});
}
client.Disconnect(true);
}
return resultList;
}
/// <summary>
/// 删除协议Pop3.
/// </summary>
/// <param name="mailConfig">配置.</param>
/// <param name="messageId">messageId.</param>
public static void Delete(MailParameterInfo mailConfig, string messageId)
{
using (var client = new Pop3Client())
{
client.ServerCertificateValidationCallback = (s, c, h, e) => true;
client.Connect(mailConfig.POP3Host, mailConfig.POP3Port, mailConfig.Ssl);
client.Authenticate(mailConfig.Account, mailConfig.Password);
for (int i = 0; i < client.Count; i++)
{
if (client.GetMessage(i).MessageId == messageId)
{
client.DeleteMessage(i);
}
}
}
}
/// <summary>
/// 验证连接协议Smtp、Pop3.
/// </summary>
/// <param name="mailConfig">配置.</param>
/// <returns></returns>
public static bool CheckConnected(MailParameterInfo mailConfig)
{
try
{
if (!string.IsNullOrEmpty(mailConfig.SMTPHost))
{
using (var client = new SmtpClient())
{
client.ServerCertificateValidationCallback = (s, c, h, e) => true;
client.Connect(mailConfig.SMTPHost, mailConfig.SMTPPort, mailConfig.Ssl);
client.Authenticate(mailConfig.Account, mailConfig.Password);
client.Disconnect(true);
return true;
}
}
if (!string.IsNullOrEmpty(mailConfig.POP3Host))
{
using (var client = new Pop3Client())
{
client.ServerCertificateValidationCallback = (s, c, h, e) => true;
client.Connect(mailConfig.POP3Host, mailConfig.POP3Port, mailConfig.Ssl);
client.Authenticate(mailConfig.Account, mailConfig.Password);
client.Disconnect(true);
return true;
}
}
return false;
}
catch (Exception ex)
{
Console.Write("邮箱验证失败原因:" + ex + ",失败详情:" + ex.StackTrace);
return false;
}
}
#region Method
/// <summary>
/// 获取邮件附件.
/// </summary>
/// <param name="attachments"></param>
/// <param name="messageId"></param>
/// <returns></returns>
private static List<MailFileParameterInfo> GetEmailAttachments(IEnumerable<MimeEntity> attachments, string messageId)
{
var resultList = new List<MailFileParameterInfo>();
foreach (var attachment in attachments)
{
if (attachment.IsAttachment)
{
var fileName = attachment.ContentDisposition?.FileName ?? attachment.ContentType.Name;
var fileId = YitIdHelper.NextId().ToString() + "_" + fileName;
var filePath = Path.Combine(mailFilePath, fileId);
using (var stream = File.Create(filePath))
{
if (attachment is MessagePart rfc822)
{
rfc822.Message.WriteTo(stream);
}
else
{
var part = (MimePart)attachment;
part.Content.DecodeTo(stream);
}
}
var mailFileInfo = new FileInfo(filePath);
resultList.Add(new MailFileParameterInfo { fileId = fileId, fileName = fileName, fileSize = FileHelper.ToFileSize(mailFileInfo.Length) });
}
}
return resultList;
}
/// <summary>
/// 转换为Base64.
/// </summary>
/// <param name="inputStr"></param>
/// <param name="encoding"></param>
/// <returns></returns>
private static string ConvertToBase64(string inputStr, Encoding encoding)
{
return Convert.ToBase64String(encoding.GetBytes(inputStr));
}
/// <summary>
/// 转换报头为Base64.
/// </summary>
/// <param name="inputStr"></param>
/// <param name="encoding"></param>
/// <returns></returns>
private static string ConvertHeaderToBase64(string inputStr, Encoding encoding)
{
var encode = !string.IsNullOrEmpty(inputStr) && inputStr.Any(c => c > 127);
if (encode)
{
return "=?" + encoding.WebName + "?B?" + ConvertToBase64(inputStr, encoding) + "?=";
}
return inputStr;
}
#endregion
}

View File

@@ -0,0 +1,84 @@
using JavaScriptEngineSwitcher.V8;
namespace JNPF.Extras.Thirdparty.JSEngine;
/// <summary>
/// js处理引擎.
/// </summary>
public class JsEngineUtil
{
/// <summary>
/// 执行Js(返回结果请用result).
/// 如var result = function(a,b){}.
/// </summary>
/// <param name="jsContent">js内容.</param>
/// <param name="args">参数.</param>
/// <returns></returns>
public static object CallFunction(string jsContent, params object[] args)
{
try
{
V8JsEngine engine = new V8JsEngine();
engine.Execute(jsContent);
return engine.CallFunction("result", args);
}
catch (Exception e)
{
throw new Exception("不支持的JS数据");
}
}
/// <summary>
/// 执行聚合函数Js(返回结果请用result).
/// 如var result = function(a,b){}.
/// </summary>
/// <param name="jsContent">js内容.</param>
/// <param name="args">参数.</param>
/// <returns></returns>
public static object AggreFunction(string jsContent, params object[] args)
{
try
{
var aggreFunc = "function getNum(val) {\n" +
" return isNaN(val) ? 0 : Number(val)\n" +
"};\n" +
"// 求和\n" +
"function SUM() {\n" +
" var value = 0\n" +
" for (var i = 0; i < arguments.length; i++) {\n" +
" value += getNum(arguments[i])\n" +
" }\n" +
" return value\n" +
"};\n" +
"// 求差\n" +
"function SUBTRACT(num1, num2) {\n" +
" return getNum(num1) - getNum(num2)\n" +
"};\n" +
"// 相乘\n" +
"function PRODUCT() {\n" +
" var value = 1\n" +
" for (var i = 0; i < arguments.length; i++) {\n" +
" value = value * getNum(arguments[i])\n" +
" }\n" +
" return value\n" +
"};\n" +
"// 相除\n" +
"function DIVIDE(num1, num2) {\n" +
" return getNum(num1) / (getNum(num2) === 0 ? 1 : getNum(num2))\n" +
"};\n" +
"// 获取参数的数量\n" +
"function COUNT() {\n" +
" return arguments.length\n" +
"};\n";
aggreFunc = aggreFunc + "var result =function(){ return " + jsContent + "}";
V8JsEngine engine = new V8JsEngine();
engine.Execute(aggreFunc);
return engine.CallFunction("result", args);
}
catch (Exception e)
{
return "";
}
}
}

View File

@@ -0,0 +1,22 @@
namespace JNPF.Extras.Thirdparty.Sms;
/// <summary>
/// 短信消息.
/// </summary>
public class SmsMessage
{
/// <summary>
/// 请求标识.
/// </summary>
public string RequestId { get; set; }
/// <summary>
/// 验证码.
/// </summary>
public string Code { get; set; }
/// <summary>
/// 消息.
/// </summary>
public string Message { get; set; }
}

View File

@@ -0,0 +1,68 @@
namespace JNPF.Extras.Thirdparty.Sms;
/// <summary>
/// 短信参数信息.
/// </summary>
public class SmsParameterInfo
{
/// <summary>
/// 第三方id.
/// </summary>
public string keyId { get; set; }
/// <summary>
/// 第三方秘钥.
/// </summary>
public string keySecret { get; set; }
/// <summary>
/// 签名.
/// </summary>
public string signName { get; set; }
/// <summary>
/// 访问域名.
/// </summary>
public string domain { get; set; }
/// <summary>
/// 短信版本.
/// </summary>
public string version { get; set; }
/// <summary>
/// 手机号(阿里云).
/// </summary>
public string mobileAli { get; set; }
/// <summary>
/// 手机号(腾讯云,国内+86).
/// </summary>
public string[] mobileTx { get; set; }
/// <summary>
/// 模板id.
/// </summary>
public string templateId { get; set; }
/// <summary>
/// 模板参数(阿里云).
/// </summary>
public string templateParamAli { get; set; }
/// <summary>
/// 模板参数(腾讯云).
/// </summary>
public string[] templateParamTx { get; set; }
/// <summary>
/// 地域(腾讯云)
/// 华北地区:ap-beijing,华南地区:ap-guangzhou,华东地区:ap-nanjing.
/// </summary>
public string region { get; set; }
/// <summary>
/// 应用id(腾讯云).
/// </summary>
public string appId { get; set; }
}

187
common/Tnb.Thirdparty/Sms/SmsUtil.cs vendored Normal file
View File

@@ -0,0 +1,187 @@
using System.Text.RegularExpressions;
using AlibabaCloud.OpenApiClient.Models;
using JNPF.Common.Security;
using TencentCloud.Common;
using TencentCloud.Common.Profile;
using TencentCloud.Sms.V20210111;
using TencentCloud.Sms.V20210111.Models;
namespace JNPF.Extras.Thirdparty.Sms;
public class SmsUtil
{
#region
/// <summary>
/// 发送(阿里云短信).
/// </summary>
/// <param name="smsModel"></param>
/// <returns></returns>
public static string SendSmsByAli(SmsParameterInfo smsModel)
{
var config = new Config
{
// 您的AccessKey ID
AccessKeyId = smsModel.keyId,
// 您的AccessKey Secret
AccessKeySecret = smsModel.keySecret,
};
config.Endpoint = smsModel.domain;
AlibabaCloud.SDK.Dysmsapi20170525.Client client = new AlibabaCloud.SDK.Dysmsapi20170525.Client(config);
AlibabaCloud.SDK.Dysmsapi20170525.Models.SendSmsRequest sendSmsRequest = new AlibabaCloud.SDK.Dysmsapi20170525.Models.SendSmsRequest();
sendSmsRequest.PhoneNumbers = smsModel.mobileAli;
sendSmsRequest.SignName = smsModel.signName;
sendSmsRequest.TemplateCode = smsModel.templateId;
sendSmsRequest.TemplateParam = smsModel.templateParamAli;
AlibabaCloud.SDK.Dysmsapi20170525.Models.SendSmsResponse sendSmsResponse = client.SendSms(sendSmsRequest);
if (sendSmsResponse.Body.Code.Equals("OK") && sendSmsResponse.Body.Message.Equals("OK"))
{
return sendSmsResponse.Body.RequestId;
}
else
{
throw new Exception(sendSmsResponse.Body.Message);
}
}
/// <summary>
/// 获取模板配置字段.
/// </summary>
/// <param name="smsModel"></param>
/// <returns></returns>
public static List<string> GetTemplateByAli(SmsParameterInfo smsModel)
{
try
{
var config = new Config
{
// 您的AccessKey ID
AccessKeyId = smsModel.keyId,
// 您的AccessKey Secret
AccessKeySecret = smsModel.keySecret,
};
config.Endpoint = smsModel.domain;
AlibabaCloud.SDK.Dysmsapi20170525.Client client = new AlibabaCloud.SDK.Dysmsapi20170525.Client(config);
AlibabaCloud.SDK.Dysmsapi20170525.Models.QuerySmsTemplateRequest querySmsTemplateRequest = new AlibabaCloud.SDK.Dysmsapi20170525.Models.QuerySmsTemplateRequest();
querySmsTemplateRequest.TemplateCode = smsModel.templateId;
AlibabaCloud.SDK.Dysmsapi20170525.Models.QuerySmsTemplateResponse querySmsTemplateResponse = client.QuerySmsTemplate(querySmsTemplateRequest);
if (querySmsTemplateResponse.Body.Code.Equals("OK"))
{
return GetFields(querySmsTemplateResponse.Body.TemplateContent);
}
else
{
throw new Exception("获取模板失败");
}
}
catch (Exception)
{
throw new Exception("获取模板失败");
}
}
#endregion
#region
/// <summary>
/// 腾讯云短信.
/// </summary>
/// <param name="smsModel"></param>
/// <returns></returns>
public static string SendSmsByTencent(SmsParameterInfo smsModel)
{
try
{
Credential cred = new Credential
{
SecretId = smsModel.keyId,
SecretKey = smsModel.keySecret
};
ClientProfile clientProfile = new ClientProfile();
HttpProfile httpProfile = new HttpProfile();
httpProfile.Endpoint = smsModel.domain;
clientProfile.HttpProfile = httpProfile;
SmsClient client = new SmsClient(cred, smsModel.region, clientProfile);
SendSmsRequest req = new SendSmsRequest();
req.PhoneNumberSet = smsModel.mobileTx;
req.SmsSdkAppId = smsModel.appId;
req.SignName = smsModel.signName;
req.TemplateId = smsModel.templateId;
req.TemplateParamSet = smsModel.templateParamTx;
SendSmsResponse resp = client.SendSmsSync(req);
if (!resp.SendStatusSet.FirstOrDefault().Code.Equals("Ok"))
{
throw new Exception("短信发送失败");
}
return resp.RequestId;
}
catch (Exception ex)
{
return "短信发送失败";
}
}
/// <summary>
/// 获取模板配置字段.
/// </summary>
/// <param name="smsModel"></param>
/// <returns></returns>
public static List<string> GetTemplateByTencent(SmsParameterInfo smsModel)
{
try
{
Credential cred = new Credential
{
SecretId = smsModel.keyId,
SecretKey = smsModel.keySecret
};
ClientProfile clientProfile = new ClientProfile();
HttpProfile httpProfile = new HttpProfile();
httpProfile.Endpoint = smsModel.domain;
clientProfile.HttpProfile = httpProfile;
SmsClient client = new SmsClient(cred, smsModel.region, clientProfile);
DescribeSmsTemplateListRequest req = new DescribeSmsTemplateListRequest();
req.International = 0;
req.TemplateIdSet = new ulong?[] { ulong.Parse(smsModel.templateId) };
DescribeSmsTemplateListResponse resp = client.DescribeSmsTemplateListSync(req);
if (resp.DescribeTemplateStatusSet.Count() > 0 && !string.IsNullOrEmpty(resp.RequestId))
{
var data = resp.DescribeTemplateStatusSet.FirstOrDefault().ToObject<Dictionary<string, object>>();
var templateContent = data["TemplateContent"].ToString();
return GetFields(templateContent);
}
else
{
throw new Exception("获取模板失败");
}
}
catch (Exception ex)
{
throw new Exception("获取模板失败");
}
}
#endregion
/// <summary>
/// 截取{}中的字符串.
/// </summary>
/// <param name="templateContent"></param>
/// <returns></returns>
private static List<string> GetFields(string templateContent)
{
MatchCollection mc = Regex.Matches(templateContent, "(?i){.*?}");
return mc.Cast<Match>().Select(m => m.Value.TrimStart('{').TrimEnd('}')).ToList();
}
}

View File

@@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="$(SolutionDir)\common.props" />
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Description>JNPF 第三方组件拓展插件。</Description>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateDocumentationFile>False</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AlibabaCloud.SDK.Dysmsapi20170525" Version="2.0.8" />
<PackageReference Include="DingDing.SDK.NetCore" Version="2021.1.7.1" />
<PackageReference Include="JavaScriptEngineSwitcher.ChakraCore" Version="3.18.2" />
<PackageReference Include="JavaScriptEngineSwitcher.ChakraCore.Native.win-x64" Version="3.18.2" />
<PackageReference Include="JavaScriptEngineSwitcher.V8" Version="3.18.1" />
<PackageReference Include="JavaScriptEngineSwitcher.V8.Native.linux-x64" Version="3.18.1" />
<PackageReference Include="JavaScriptEngineSwitcher.V8.Native.win-x64" Version="3.18.1" />
<PackageReference Include="MailKit" Version="2.15.0" />
<PackageReference Include="OnceMi.AspNetCore.OSS" Version="1.1.9" />
<PackageReference Include="Senparc.Weixin.MP" Version="16.18.9" />
<PackageReference Include="Senparc.Weixin.Work" Version="3.15.12" />
<PackageReference Include="TencentCloudSDK.Sms" Version="3.0.368" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Tnb.Common\Tnb.Common.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,97 @@
namespace JNPF.Extras.Thirdparty.WeChat;
/// <summary>
/// 企业用户.
/// </summary>
public sealed class QYMember
{
/// <summary>
/// 摘要:
/// [创建、更新 必填]成员UserID。对应管理端的帐号企业内必须唯一。不区分大小写长度为1~64个字节.
/// </summary>
public string userid { get; set; }
/// <summary>
/// 摘要:
/// [创建必填]成员名称。长度为1~64个字符.
/// </summary>
public string name { get; set; }
/// <summary>
/// 摘要:
/// 英文名。长度为1-64个字节由字母、数字、点(.)、减号(-)、空格或下划线(_)组成.
/// </summary>
public string english_name { get; set; }
/// <summary>
/// 摘要:
/// 手机号码。企业内必须唯一mobile/email二者不能同时为空.
/// </summary>
public string mobile { get; set; }
/// <summary>
/// 摘要:
/// [创建必填]成员所属部门id列表,不超过20个.
/// </summary>
public long[] department { get; set; }
/// <summary>
/// 摘要:
/// 部门内的排序值默认为0成员次序以创建时间从小到大排列。数量必须和department一致数值越大排序越前面。有效的值范围是[0, 2^32).
/// </summary>
public long[] order { get; set; }
/// <summary>
/// 摘要:
/// 职位信息。长度为0~128个字符.
/// </summary>
public string position { get; set; }
/// <summary>
/// 摘要:
/// 性别。1表示男性2表示女性.
/// </summary>
public string gender { get; set; }
/// <summary>
/// 摘要:
/// 邮箱。长度不超过64个字节且为有效的email格式。企业内必须唯一mobile/email二者不能同时为空.
/// </summary>
public string email { get; set; }
/// <summary>
/// 摘要:
/// 上级字段,标识是否为上级。在审批等应用里可以用来标识上级审批人.
/// </summary>
public int isleader { get; set; }
/// <summary>
/// 摘要:
/// 启用/禁用成员。1表示启用成员0表示禁用成员.
/// </summary>
public int enable { get; set; }
/// <summary>
/// 摘要:
/// 成员头像的mediaid通过素材管理接口上传图片获得的mediaid.
/// </summary>
public string avatar_mediaid { get; set; }
/// <summary>
/// 摘要:
/// 座机。由1-32位的纯数字或-‘号组成.
/// </summary>
public string telephone { get; set; }
/// <summary>
/// 摘要:
/// 自定义字段。自定义字段需要先在WEB管理端添加见扩展属性添加方法否则忽略未知属性的赋值。自定义字段长度为0~32个字符超过将被截断.
/// </summary>
public object extattr { get; set; }
/// <summary>
/// 摘要:
/// 成员对外属性,字段详情见对外属性: http://work.weixin.qq.com/api/doc#13450.
/// </summary>
public object external_profile { get; set; }
}

View File

@@ -0,0 +1,52 @@
namespace JNPF.Extras.Thirdparty.WeChat.Internal;
/// <summary>
/// 公众号事件.
/// </summary>
public class WechatMPEvent
{
/// <summary>
/// 签名.
/// </summary>
public string signature { get; set; }
/// <summary>
/// 时间戳.
/// </summary>
public string timestamp { get; set; }
/// <summary>
/// nonce.
/// </summary>
public string nonce { get; set; }
/// <summary>
/// 算出的值.
/// </summary>
public string echostr { get; set; }
/// <summary>
/// 开发者微信号.
/// </summary>
public string ToUserName { get; set; }
/// <summary>
/// 发送方帐号一个OpenID.
/// </summary>
public string FromUserName { get; set; }
/// <summary>
/// 消息创建时间 (整型).
/// </summary>
public long CreateTime { get; set; }
/// <summary>
/// 消息类型event.
/// </summary>
public string MsgType { get; set; }
/// <summary>
/// 事件类型subscribe(订阅)、unsubscribe(取消订阅).
/// </summary>
public string Event { get; set; }
}

View File

@@ -0,0 +1,150 @@
using Senparc.Weixin.MP;
using Senparc.Weixin.MP.AdvancedAPIs;
using Senparc.Weixin.MP.AdvancedAPIs.TemplateMessage;
using Senparc.Weixin.MP.AdvancedAPIs.User;
using Senparc.Weixin.MP.Containers;
namespace JNPF.Extras.Thirdparty.WeChat;
/// <summary>
/// 微信公众号.
/// </summary>
public class WeChatMPUtil
{
/// <summary>
/// 访问令牌.
/// </summary>
public string accessToken { get; private set; }
/// <summary>
/// 构造函数.
/// </summary>
public WeChatMPUtil() { }
/// <summary>
/// 构造函数.
/// </summary>
public WeChatMPUtil(string appId, string appSecret)
{
try
{
accessToken = AccessTokenContainer.TryGetAccessToken(appId, appSecret);
}
catch (Exception ex)
{
}
}
/// <summary>
/// 微信后台验证地址.
/// </summary>
/// <param name="signature">签名.</param>
/// <param name="timestamp">时间戳.</param>
/// <param name="nonce">nonce.</param>
/// <param name="echostr">算出的值.</param>
/// <returns></returns>
public bool CheckToken(string signature, string timestamp, string nonce)
{
var token = "WEIXINJNPF";
return CheckSignature.Check(signature, timestamp, nonce, token);
}
/// <summary>
/// 根据OpenId进行群发.
/// </summary>
/// <param name="type">消息类型.</param>
/// <param name="value">群发媒体文件时传入mediaId,群发文本消息时传入content,群发卡券时传入cardId.</param>
/// <param name="clientmsgid">开发者侧群发msgid长度限制64字节如不填则后台默认以群发范围和群发内容的摘要值做为clientmsgid.</param>
/// <param name="openIds"> openId字符串数组.</param>
/// <param name="timeOut">代理请求超时时间(毫秒).</param>
/// <returns></returns>
public bool SendGroupMessageByOpenId(int type, string value, string[] openIds, string clientmsgid = null, int timeOut = 10000)
{
try
{
GroupMessageType messageType = new GroupMessageType();
switch (type)
{
case 1://文本
messageType = GroupMessageType.text;
break;
case 2://图片
messageType = GroupMessageType.image;
break;
case 3://语音
messageType = GroupMessageType.voice;
break;
case 4://视频
messageType = GroupMessageType.video;
break;
case 5://图文
messageType = GroupMessageType.mpnews;
break;
case 6:// 卡券
messageType = GroupMessageType.wxcard;
break;
default:
break;
}
var result = GroupMessageApi.SendGroupMessageByOpenId(accessToken, messageType, value, clientmsgid, timeOut, openIds);
return result.errcode == 0;
}
catch (Exception ex)
{
return false;
}
}
/// <summary>
/// 根据OpenId发送模板消息.
/// </summary>
/// <param name="openId"></param>
/// <param name="templateId"></param>
/// <param name="url"></param>
/// <param name="data"></param>
/// <returns></returns>
public void SendTemplateMessage(string openId, string templateId, string url, object data, TemplateModel_MiniProgram miniProgram = null)
{
var result = TemplateApi.SendTemplateMessage(accessToken, openId, templateId, url, data, miniProgram);
if (result.errcode != 0)
{
throw new Exception(result.errmsg);
}
}
/// <summary>
/// 根据OpenId发送模板消息.
/// </summary>
/// <param name="openId"></param>
/// <param name="templateId"></param>
/// <param name="url"></param>
/// <param name="data"></param>
/// <returns></returns>
public string GetTemplateMp(string templateId)
{
try
{
var result = TemplateApi.GetPrivateTemplate(accessToken);
if (result.errcode == 0)
{
var data = result.template_list.Find(x => x.template_id == templateId);
return data.content;
}
return string.Empty;
}
catch (Exception ex)
{
return string.Empty;
}
}
/// <summary>
/// 通过openId获取用户信息.
/// </summary>
/// <param name="openId"></param>
/// <returns></returns>
public UserInfoJson GetWeChatUserInfo(string openId)
{
return UserApi.Info(accessToken, openId);
}
}

View File

@@ -0,0 +1,450 @@
using System.Text.Json;
using Senparc.Weixin.Work.AdvancedAPIs;
using Senparc.Weixin.Work.AdvancedAPIs.MailList;
using Senparc.Weixin.Work.AdvancedAPIs.MailList.Member;
using Senparc.Weixin.Work.Containers;
namespace JNPF.Extras.Thirdparty.WeChat;
/// <summary>
/// 企业号微信.
/// </summary>
public class WeChatUtil
{
/// <summary>
/// 访问令牌.
/// </summary>
public string accessToken { get; private set; }
/// <summary>
/// 构造函数.
/// </summary>
public WeChatUtil(string corpId, string corpSecret, string appSecret = null)
{
try
{
if (appSecret != null)
corpSecret = appSecret;
accessToken = AccessTokenContainer.TryGetToken(corpId, corpSecret);
}
catch (Exception)
{
}
}
#region
/// <summary>
/// 查询部门.
/// </summary>
public List<DepartmentList> GetDepartmentList()
{
var result = MailListApi.GetDepartmentList(accessToken);
if (result.errcode == 0)
{
return result.department;
}
else
{
throw new Exception(result.errmsg);
}
}
/// <summary>
/// 创建部门.
/// </summary>
/// <param name="name">部门名称.</param>
/// <param name="parentId">父亲部门id.</param>
/// <param name="order">在父部门中的次序.</param>
/// <param name="msg">返回信息.</param>
/// <param name="id">部门id.</param>
/// <param name="timeOut">代理请求超时时间(毫秒).</param>
/// <returns></returns>
public string CreateDepartment(string name, long parentId, int order, ref string msg, int? id = null, int timeOut = 10000)
{
try
{
var result = MailListApi.CreateDepartment(accessToken, name, parentId);
if (result.errcode == 0)
{
return result.id.ToString();
}
else
{
msg = result.errmsg;
return string.Empty;
}
}
catch (Exception ex)
{
msg = string.Format("【组织{0}创建失败】{1}", name, ex.Message);
return string.Empty;
}
}
/// <summary>
/// 编辑部门.
/// </summary>
/// <param name="id">部门Id.</param>
/// <param name="name">部门名称.</param>
/// <param name="parentId">父亲部门id.</param>
/// <param name="order">在父部门中的次序.</param>
/// <param name="msg">返回信息.</param>
/// <param name="timeOut">代理请求超时时间(毫秒).</param>
/// <returns></returns>
public bool UpdateDepartment(int? id, string name, int? parentId, int? order, ref string msg, int timeOut = 10000)
{
try
{
var result = MailListApi.UpdateDepartment(accessToken, Convert.ToInt64(id), name);
if (result.errcode == 0)
{
return true;
}
else
{
msg = result.errmsg;
return false;
}
}
catch (Exception ex)
{
msg = string.Format("【组织{0}修改失败】{1}", name, ex.Message);
return false;
}
}
/// <summary>
/// 删除部门.
/// </summary>
/// <param name="id">部门Id.</param>
/// <param name="msg">返回信息.</param>
/// <returns></returns>
public bool DeleteDepartment(int? id, ref string msg)
{
var result = MailListApi.DeleteDepartment(accessToken, Convert.ToInt64(id));
if (result.errcode == 0)
{
return true;
}
else
{
msg = result.errmsg;
return false;
}
}
/// <summary>
/// 获取部门成员.
/// </summary>
/// <param name="departmentId">获取的部门id.</param>
/// <param name="fetchChild">1/0是否递归获取子部门下面的成员.</param>
/// <returns></returns>
public List<GetMemberResult> GetDepartmentMember()
{
var depList = GetDepartmentList();
var userList = new List<GetMemberResult>();
if (depList.Count > 0)
{
foreach (var item in depList.Select(x => x.id))
{
var result = MailListApi.GetDepartmentMemberInfo(accessToken, item, 1);
if (result.errcode == 0 && result.userlist.Count > 0)
{
userList = userList.Union(result.userlist).ToList();
}
}
}
return userList;
}
#endregion
#region
/// <summary>
/// 获取成员.
/// </summary>
/// <param name="userId">用户Id.</param>
/// <returns></returns>
public string GetMember(string userId)
{
var result = MailListApi.GetMember(accessToken, userId);
if (result.errcode == 0)
{
return JsonSerializer.Serialize(result);
}
else
{
throw new Exception(result.errmsg);
}
}
/// <summary>
/// 创建成员.
/// </summary>
/// <param name="member">企业用户.</param>
/// <param name="msg">返回信息.</param>
/// <param name="timeOut">代理请求超时时间(毫秒).</param>
public bool CreateMember(QYMember member, ref string msg, int timeOut = 10000)
{
try
{
MemberCreateRequest memberCreate = new MemberCreateRequest();
memberCreate.name = member.name;
memberCreate.avatar_mediaid = member.avatar_mediaid;
memberCreate.department = member.department;
memberCreate.email = member.email;
memberCreate.enable = member.enable;
memberCreate.english_name = member.english_name;
memberCreate.extattr = (Extattr)member.extattr;
memberCreate.external_profile = (External_Profile)member.external_profile;
memberCreate.gender = member.gender;
memberCreate.mobile = member.mobile;
memberCreate.order = member.order;
memberCreate.position = member.position;
memberCreate.telephone = member.telephone;
memberCreate.userid = member.userid;
var result = MailListApi.CreateMember(accessToken, memberCreate, timeOut);
if (result.errcode == 0)
return true;
return false;
}
catch (Exception ex)
{
msg = ex.Message;
return false;
}
}
/// <summary>
/// 编辑成员.
/// </summary>
/// <param name="member">企业用户.</param>
/// <param name="msg">返回信息.</param>
/// <param name="timeOut">代理请求超时时间(毫秒).</param>
public bool UpdateMember(QYMember member, ref string msg, int timeOut = 10000)
{
try
{
MemberUpdateRequest memberUpdate = new MemberUpdateRequest();
memberUpdate.name = member.name;
memberUpdate.avatar_mediaid = member.avatar_mediaid;
memberUpdate.department = member.department;
memberUpdate.email = member.email;
memberUpdate.enable = member.enable;
memberUpdate.english_name = member.english_name;
memberUpdate.extattr = (Extattr)member.extattr;
memberUpdate.external_profile = (External_Profile)member.external_profile;
memberUpdate.gender = member.gender;
memberUpdate.mobile = member.mobile;
memberUpdate.order = member.order;
memberUpdate.position = member.position;
memberUpdate.telephone = member.telephone;
memberUpdate.userid = member.userid;
var result = MailListApi.UpdateMember(accessToken, memberUpdate, timeOut);
if (result.errcode == 0)
{
return true;
}
else
{
return false;
}
}
catch (Exception ex)
{
msg = ex.Message;
return false;
}
}
/// <summary>
/// 删除成员.
/// </summary>
/// <param name="userId">成员Id.</param>
/// <param name="msg">返回信息.</param>
/// <returns></returns>
public bool DeleteMember(string userId, string msg = null)
{
try
{
var result = MailListApi.DeleteMember(accessToken, userId);
if (result.errcode == 0)
{
return true;
}
return false;
}
catch (Exception ex)
{
msg = ex.Message;
return false;
}
}
/// <summary>
/// 批量删除成员.
/// </summary>
/// <param name="useridlist">成员UserID列表.</param>
/// <param name="timeOut">代理请求超时时间(毫秒).</param>
/// <returns></returns>
public bool BatchDeleteMember(string[] useridlist, int timeOut = 10000)
{
var result = MailListApi.BatchDeleteMember(accessToken, useridlist, timeOut = 10000);
if (result.errcode == 0)
{
return true;
}
else
{
throw new Exception(result.errmsg);
}
}
/// <summary>
/// 手机号获取成员.
/// </summary>
/// <param name="mobile">手机号码.</param>
public string GetUserid(string mobile)
{
try
{
var result = MailListApi.GetUserid(accessToken, mobile, 10000);
if (result.errcode == 0)
{
return result.userid;
}
else
{
return string.Empty;
}
}
catch (Exception ex)
{
return string.Empty;
}
}
#endregion
#region
/// <summary>
/// 发送消息.
/// </summary>
/// <param name="agentId">企业应用的id.</param>
/// <param name="content">消息内容.</param>
/// <param name="toUser">UserID列表.</param>
/// <param name="toParty">PartyID列表.</param>
/// <param name="toTag">TagID列表.</param>
/// <param name="safe">否是保密消息.</param>
/// <param name="timeOut">代理请求超时时间(毫秒).</param>
/// <returns></returns>
public async Task SendText(string agentId, string content, string toUser, string toParty = null, string toTag = null, int safe = 0, int timeOut = 10000)
{
var result = await MassApi.SendTextAsync(accessToken, agentId, content, toUser, toParty, toTag, safe);
if (result.errcode != 0)
{
throw new Exception(result.errmsg);
}
}
/// <summary>
/// 发送文件消息.
/// </summary>
/// <param name="agentId">企业应用的id.</param>
/// <param name="mediaId">媒体资源文件ID.</param>
/// <param name="toUser">UserID列表.</param>
/// <param name="toParty">PartyID列表.</param>
/// <param name="toTag">TagID列表.</param>
/// <param name="safe">否是保密消息.</param>
/// <param name="timeOut">代理请求超时时间(毫秒).</param>
/// <returns></returns>
public bool SendFile(string agentId, string mediaId, string toUser, string toParty = null, string toTag = null, int safe = 0, int timeOut = 10000)
{
var result = MassApi.SendFile(accessToken, agentId, mediaId, toUser, toParty, toTag, safe);
if (result.errcode == 0)
{
return true;
}
else
{
throw new Exception(result.errmsg);
}
}
/// <summary>
/// 发送图片消息.
/// </summary>
/// <param name="agentId">企业应用的id.</param>
/// <param name="mediaId">媒体资源文件ID.</param>
/// <param name="toUser">UserID列表.</param>
/// <param name="toParty">PartyID列表.</param>
/// <param name="toTag">TagID列表.</param>
/// <param name="safe">否是保密消息.</param>
/// <param name="timeOut">代理请求超时时间(毫秒).</param>
public bool SendImage(string agentId, string mediaId, string toUser, string toParty = null, string toTag = null, int safe = 0, int timeOut = 10000)
{
var result = MassApi.SendImage(accessToken, agentId, mediaId, toUser, toParty, toTag, safe);
if (result.errcode == 0)
{
return true;
}
else
{
throw new Exception(result.errmsg);
}
}
/// <summary>
/// 发送视频消息.
/// </summary>
/// <param name="agentId">企业应用的id.</param>
/// <param name="mediaId">媒体资源文件ID.</param>
/// <param name="toUser">UserID列表.</param>
/// <param name="toParty">PartyID列表.</param>
/// <param name="toTag">TagID列表.</param>
/// <param name="title"> 视频消息的标题.</param>
/// <param name="description">视频消息的描述.</param>
/// <param name="safe">否是保密消息.</param>
/// <param name="timeOut">代理请求超时时间(毫秒).</param>
/// <returns></returns>
public bool SendVideo(string agentId, string mediaId, string toUser, string toParty = null, string toTag = null, string title = null, string description = null, int safe = 0, int timeOut = 10000)
{
var result = MassApi.SendVideo(accessToken, agentId, mediaId, toUser, toParty, toTag, title, description, safe);
if (result.errcode == 0)
{
return true;
}
else
{
throw new Exception(result.errmsg);
}
}
/// <summary>
/// 发送语音消息.
/// </summary>
/// <param name="agentId">企业应用的id.</param>
/// <param name="mediaId">媒体资源文件ID.</param>
/// <param name="toUser">UserID列表.</param>
/// <param name="toParty">PartyID列表.</param>
/// <param name="toTag">TagID列表.</param>
/// <param name="safe">否是保密消息.</param>
/// <param name="timeOut">代理请求超时时间(毫秒).</param>
/// <returns></returns>
public bool SendVoice(string agentId, string mediaId, string toUser, string toParty = null, string toTag = null, int safe = 0, int timeOut = 10000)
{
var result = MassApi.SendVoice(accessToken, agentId, mediaId, toUser, toParty, toTag, safe);
if (result.errcode == 0)
{
return true;
}
else
{
throw new Exception(result.errmsg);
}
}
#endregion
}