diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Extensions/WechatApiClientExecuteCgibinExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Extensions/WechatApiClientExecuteCgibinExtensions.cs index 517b731b..e6c39a97 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Api/Extensions/WechatApiClientExecuteCgibinExtensions.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Extensions/WechatApiClientExecuteCgibinExtensions.cs @@ -16,6 +16,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api /// REF: https://developers.weixin.qq.com/minigame/dev/api-backend/open-api/access-token/auth.getAccessToken.html /// REF: https://developers.weixin.qq.com/doc/channels/API/basics/getaccesstoken.html /// REF: https://developers.weixin.qq.com/doc/channels/API/windowproduct/getaccesstoken.html + /// REF: https://dev.weixin.qq.com/docs/framework/dev/openapi/getaccesstoken.html /// /// /// diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Extensions/WechatApiClientExecuteDonutExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Extensions/WechatApiClientExecuteDonutExtensions.cs new file mode 100644 index 00000000..ba14600c --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Extensions/WechatApiClientExecuteDonutExtensions.cs @@ -0,0 +1,116 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Flurl; +using Flurl.Http; + +namespace SKIT.FlurlHttpClient.Wechat.Api +{ + public static class WechatApiClientExecuteDonutExtensions + { + /// + /// 异步调用 [GET] /donut/code2verifyinfo 接口。 + /// REF: https://dev.weixin.qq.com/docs/framework/dev/openapi/code2Verifyinfo.html + /// + /// + /// + /// + /// + public static async Task ExecuteDonutCode2VerifyInfoAsync(this WechatApiClient client, Models.DonutCode2VerifyInfoRequest request, CancellationToken cancellationToken = default) + { + if (client is null) throw new ArgumentNullException(nameof(client)); + if (request is null) throw new ArgumentNullException(nameof(request)); + + IFlurlRequest flurlReq = client + .CreateRequest(request, HttpMethod.Get, "donut", "code2verifyinfo") + .SetQueryParam("access_token", request.AccessToken) + .SetQueryParam("appid", client.Credentials.AppId) + .SetQueryParam("appsecret", client.Credentials.AppSecret) + .SetQueryParam("code", request.Code) + .SetQueryParam("grant_type", request.GrantType); + + return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken); + } + + /// + /// 异步调用 [POST] /donut/unbindphone 接口。 + /// REF: https://dev.weixin.qq.com/docs/framework/dev/openapi/unbindphone.html + /// + /// + /// + /// + /// + public static async Task ExecuteDonutUnbindPhoneAsync(this WechatApiClient client, Models.DonutUnbindPhoneRequest request, CancellationToken cancellationToken = default) + { + if (client is null) throw new ArgumentNullException(nameof(client)); + if (request is null) throw new ArgumentNullException(nameof(request)); + + IFlurlRequest flurlReq = client + .CreateRequest(request, HttpMethod.Post, "donut", "unbindphone") + .SetQueryParam("access_token", request.AccessToken); + + return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken); + } + + /// + /// 异步调用 [POST] /donut/unbindweixin 接口。 + /// REF: https://dev.weixin.qq.com/docs/framework/dev/openapi/unbindweixin.html + /// + /// + /// + /// + /// + public static async Task ExecuteDonutUnbindWeixinAsync(this WechatApiClient client, Models.DonutUnbindWeixinRequest request, CancellationToken cancellationToken = default) + { + if (client is null) throw new ArgumentNullException(nameof(client)); + if (request is null) throw new ArgumentNullException(nameof(request)); + + IFlurlRequest flurlReq = client + .CreateRequest(request, HttpMethod.Post, "donut", "unbindweixin") + .SetQueryParam("access_token", request.AccessToken); + + return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken); + } + + /// + /// 异步调用 [POST] /donut/unbindapple 接口。 + /// REF: https://dev.weixin.qq.com/docs/framework/dev/openapi/unbindapple.html + /// + /// + /// + /// + /// + public static async Task ExecuteDonutUnbindAppleAsync(this WechatApiClient client, Models.DonutUnbindAppleRequest request, CancellationToken cancellationToken = default) + { + if (client is null) throw new ArgumentNullException(nameof(client)); + if (request is null) throw new ArgumentNullException(nameof(request)); + + IFlurlRequest flurlReq = client + .CreateRequest(request, HttpMethod.Post, "donut", "unbindapple") + .SetQueryParam("access_token", request.AccessToken); + + return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken); + } + + /// + /// 异步调用 [POST] /donut/unregisteruser 接口。 + /// REF: https://dev.weixin.qq.com/docs/framework/dev/openapi/unregisteruser.html + /// + /// + /// + /// + /// + public static async Task ExecuteDonutUnregisterUserAsync(this WechatApiClient client, Models.DonutUnregisterUserRequest request, CancellationToken cancellationToken = default) + { + if (client is null) throw new ArgumentNullException(nameof(client)); + if (request is null) throw new ArgumentNullException(nameof(request)); + + IFlurlRequest flurlReq = client + .CreateRequest(request, HttpMethod.Post, "donut", "unregisteruser") + .SetQueryParam("access_token", request.AccessToken); + + return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken); + } + } +} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutCode2VerifyInfoRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutCode2VerifyInfoRequest.cs new file mode 100644 index 00000000..b37c82db --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutCode2VerifyInfoRequest.cs @@ -0,0 +1,22 @@ +namespace SKIT.FlurlHttpClient.Wechat.Api.Models +{ + /// + /// 表示 [GET] /donut/code2verifyinfo 接口的请求。 + /// + public class DonutCode2VerifyInfoRequest : WechatApiRequest, IInferable + { + /// + /// 获取或设置临时登录凭证。 + /// + [Newtonsoft.Json.JsonIgnore] + [System.Text.Json.Serialization.JsonIgnore] + public string Code { get; set; } = string.Empty; + + /// + /// (使用默认值即可,无需修改) + /// + [Newtonsoft.Json.JsonIgnore] + [System.Text.Json.Serialization.JsonIgnore] + public string GrantType { get; set; } = "authorization_code"; + } +} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutCode2VerifyInfoResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutCode2VerifyInfoResponse.cs new file mode 100644 index 00000000..30f4d69a --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutCode2VerifyInfoResponse.cs @@ -0,0 +1,179 @@ +namespace SKIT.FlurlHttpClient.Wechat.Api.Models +{ + /// + /// 表示 [GET] /donut/code2verifyinfo 接口的响应。 + /// + public class DonutCode2VerifyInfoResponse : WechatApiResponse + { + public static class Types + { + public class LoginInfo + { + /// + /// 获取或设置登录方式。 + /// + [Newtonsoft.Json.JsonProperty("type")] + [System.Text.Json.Serialization.JsonPropertyName("type")] + public string Type { get; set; } = default!; + + /// + /// 获取或设置登录时间戳。 + /// + [Newtonsoft.Json.JsonProperty("login_time")] + [System.Text.Json.Serialization.JsonPropertyName("login_time")] + public long LoginTimestamp { get; set; } + + /// + /// 获取或设置微信 AppId。 + /// + [Newtonsoft.Json.JsonProperty("appid")] + [System.Text.Json.Serialization.JsonPropertyName("appid")] + public string? AppId { get; set; } + } + + public class UserInfo + { + public static class Types + { + public class OpenAppUserInfo + { + /// + /// 获取或设置微信 AppId。 + /// + [Newtonsoft.Json.JsonProperty("appid")] + [System.Text.Json.Serialization.JsonPropertyName("appid")] + public string AppId { get; set; } = default!; + + /// + /// 获取或设置用户的 OpenId。 + /// + [Newtonsoft.Json.JsonProperty("openid")] + [System.Text.Json.Serialization.JsonPropertyName("openid")] + public string OpenId { get; set; } = default!; + + /// + /// 获取或设置用户的 UnionId。 + /// + [Newtonsoft.Json.JsonProperty("unionid")] + [System.Text.Json.Serialization.JsonPropertyName("unionid")] + public string? UnionId { get; set; } + + /// + /// 获取或设置用户头像 URL。 + /// + [Newtonsoft.Json.JsonProperty("headimgurl")] + [System.Text.Json.Serialization.JsonPropertyName("headimgurl")] + public string? HeadImageUrl { get; set; } + + /// + /// 获取或设置用户昵称。 + /// + [Newtonsoft.Json.JsonProperty("nickname")] + [System.Text.Json.Serialization.JsonPropertyName("nickname")] + public string? Nickname { get; set; } + } + + public class MiniProgramUserInfo + { + /// + /// 获取或设置微信 AppId。 + /// + [Newtonsoft.Json.JsonProperty("appid")] + [System.Text.Json.Serialization.JsonPropertyName("appid")] + public string AppId { get; set; } = default!; + + /// + /// 获取或设置用户的 OpenId。 + /// + [Newtonsoft.Json.JsonProperty("openid")] + [System.Text.Json.Serialization.JsonPropertyName("openid")] + public string OpenId { get; set; } = default!; + + /// + /// 获取或设置用户的 UnionId。 + /// + [Newtonsoft.Json.JsonProperty("unionid")] + [System.Text.Json.Serialization.JsonPropertyName("unionid")] + public string? UnionId { get; set; } + } + + public class PhoneUserInfo + { + /// + /// 获取或设置手机号码。 + /// + [Newtonsoft.Json.JsonProperty("phone")] + [System.Text.Json.Serialization.JsonPropertyName("phone")] + public string MobileNumber { get; set; } = default!; + } + + public class AppleUserInfo + { + /// + /// 获取或设置苹果应用 ID。 + /// + [Newtonsoft.Json.JsonProperty("bundleid")] + [System.Text.Json.Serialization.JsonPropertyName("bundleid")] + public string BundleId { get; set; } = default!; + + /// + /// 获取或设置苹果用户 ID。 + /// + [Newtonsoft.Json.JsonProperty("apple_user_id")] + [System.Text.Json.Serialization.JsonPropertyName("apple_user_id")] + public string AppleUserId { get; set; } = default!; + } + } + + /// + /// 获取或设置多端用户 ID。 + /// + [Newtonsoft.Json.JsonProperty("user_id")] + [System.Text.Json.Serialization.JsonPropertyName("user_id")] + public string UserId { get; set; } = default!; + + /// + /// 获取或设置微信移动应用的用户信息。 + /// + [Newtonsoft.Json.JsonProperty("openapp_info")] + [System.Text.Json.Serialization.JsonPropertyName("openapp_info")] + public Types.OpenAppUserInfo? OpenAppUserInfo { get; set; } + + /// + /// 获取或设置微信小程序的用户信息。 + /// + [Newtonsoft.Json.JsonProperty("miniprogram_info")] + [System.Text.Json.Serialization.JsonPropertyName("miniprogram_info")] + public Types.MiniProgramUserInfo? MiniProgramUserInfo { get; set; } + + /// + /// 获取或设置手机号用户信息。 + /// + [Newtonsoft.Json.JsonProperty("phone_info")] + [System.Text.Json.Serialization.JsonPropertyName("phone_info")] + public Types.PhoneUserInfo? PhoneUserInfo { get; set; } + + /// + /// 获取或设置苹果用户信息。 + /// + [Newtonsoft.Json.JsonProperty("apple_info")] + [System.Text.Json.Serialization.JsonPropertyName("apple_info")] + public Types.AppleUserInfo? AppleUserInfo { get; set; } + } + } + + /// + /// 获取或设置登录信息。 + /// + [Newtonsoft.Json.JsonProperty("login_info")] + [System.Text.Json.Serialization.JsonPropertyName("login_info")] + public Types.LoginInfo LoginInfo { get; set; } = default!; + + /// + /// 获取或设置用户信息。 + /// + [Newtonsoft.Json.JsonProperty("user_info")] + [System.Text.Json.Serialization.JsonPropertyName("user_info")] + public Types.UserInfo UserInfo { get; set; } = default!; + } +} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutUnbindAppleRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutUnbindAppleRequest.cs new file mode 100644 index 00000000..23606516 --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutUnbindAppleRequest.cs @@ -0,0 +1,15 @@ +namespace SKIT.FlurlHttpClient.Wechat.Api.Models +{ + /// + /// 表示 [POST] /donut/unbindapple 接口的请求。 + /// + public class DonutUnbindAppleRequest : WechatApiRequest, IInferable + { + /// + /// 获取或设置多端用户 ID。 + /// + [Newtonsoft.Json.JsonProperty("user_id")] + [System.Text.Json.Serialization.JsonPropertyName("user_id")] + public string UserId { get; set; } = string.Empty; + } +} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutUnbindAppleResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutUnbindAppleResponse.cs new file mode 100644 index 00000000..5d636218 --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutUnbindAppleResponse.cs @@ -0,0 +1,9 @@ +namespace SKIT.FlurlHttpClient.Wechat.Api.Models +{ + /// + /// 表示 [POST] /donut/unbindapple 接口的响应。 + /// + public class DonutUnbindAppleResponse : WechatApiResponse + { + } +} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutUnbindPhoneRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutUnbindPhoneRequest.cs new file mode 100644 index 00000000..826b7d7f --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutUnbindPhoneRequest.cs @@ -0,0 +1,15 @@ +namespace SKIT.FlurlHttpClient.Wechat.Api.Models +{ + /// + /// 表示 [POST] /donut/unbindphone 接口的请求。 + /// + public class DonutUnbindPhoneRequest : WechatApiRequest, IInferable + { + /// + /// 获取或设置多端用户 ID。 + /// + [Newtonsoft.Json.JsonProperty("user_id")] + [System.Text.Json.Serialization.JsonPropertyName("user_id")] + public string UserId { get; set; } = string.Empty; + } +} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutUnbindPhoneResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutUnbindPhoneResponse.cs new file mode 100644 index 00000000..df483edc --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutUnbindPhoneResponse.cs @@ -0,0 +1,9 @@ +namespace SKIT.FlurlHttpClient.Wechat.Api.Models +{ + /// + /// 表示 [POST] /donut/unbindphone 接口的响应。 + /// + public class DonutUnbindPhoneResponse : WechatApiResponse + { + } +} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutUnbindWeixinRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutUnbindWeixinRequest.cs new file mode 100644 index 00000000..9f909cce --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutUnbindWeixinRequest.cs @@ -0,0 +1,15 @@ +namespace SKIT.FlurlHttpClient.Wechat.Api.Models +{ + /// + /// 表示 [POST] /donut/unbindweixin 接口的请求。 + /// + public class DonutUnbindWeixinRequest : WechatApiRequest, IInferable + { + /// + /// 获取或设置多端用户 ID。 + /// + [Newtonsoft.Json.JsonProperty("user_id")] + [System.Text.Json.Serialization.JsonPropertyName("user_id")] + public string UserId { get; set; } = string.Empty; + } +} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutUnbindWeixinResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutUnbindWeixinResponse.cs new file mode 100644 index 00000000..f8d1b39c --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutUnbindWeixinResponse.cs @@ -0,0 +1,9 @@ +namespace SKIT.FlurlHttpClient.Wechat.Api.Models +{ + /// + /// 表示 [POST] /donut/unbindweixin 接口的响应。 + /// + public class DonutUnbindWeixinResponse : WechatApiResponse + { + } +} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutUnregisterUserRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutUnregisterUserRequest.cs new file mode 100644 index 00000000..a42aeefd --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutUnregisterUserRequest.cs @@ -0,0 +1,15 @@ +namespace SKIT.FlurlHttpClient.Wechat.Api.Models +{ + /// + /// 表示 [POST] /donut/unregisteruser 接口的请求。 + /// + public class DonutUnregisterUserRequest : WechatApiRequest, IInferable + { + /// + /// 获取或设置多端用户 ID。 + /// + [Newtonsoft.Json.JsonProperty("user_id")] + [System.Text.Json.Serialization.JsonPropertyName("user_id")] + public string UserId { get; set; } = string.Empty; + } +} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutUnregisterUserResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutUnregisterUserResponse.cs new file mode 100644 index 00000000..8872f851 --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/Donut/DonutUnregisterUserResponse.cs @@ -0,0 +1,9 @@ +namespace SKIT.FlurlHttpClient.Wechat.Api.Models +{ + /// + /// 表示 [POST] /donut/unregisteruser 接口的响应。 + /// + public class DonutUnregisterUserResponse : WechatApiResponse + { + } +} diff --git a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/Donut/DonutCode2VerifyInfoResponse.json b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/Donut/DonutCode2VerifyInfoResponse.json new file mode 100644 index 00000000..68015f67 --- /dev/null +++ b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/Donut/DonutCode2VerifyInfoResponse.json @@ -0,0 +1,30 @@ +{ + "errcode": 0, + "login_info": { + "type": "weixinApp", + "login_time": 12345678, + "appid": "aaa" + }, + "user_info": { + "user_id": "xxx", + "openapp_info": { + "appid": "bbb", + "openid": "ccc", + "unionid": "ddd", + "headimgurl": "HEADIMGURL", + "nickname": "NICKNAME" + }, + "phone_info": { + "phone": "137xxxxxxx" + }, + "apple_info": { + "bundleid": "eee", + "apple_user_id": "fff" + }, + "miniprogram_info": { + "appid": "bbb", + "openid": "ccc", + "unionid": "ddd" + } + } +} diff --git a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/Donut/DonutUnbindAppleRequest.json b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/Donut/DonutUnbindAppleRequest.json new file mode 100644 index 00000000..d69dd37c --- /dev/null +++ b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/Donut/DonutUnbindAppleRequest.json @@ -0,0 +1,3 @@ +{ + "user_id": "bbb" +} diff --git a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/Donut/DonutUnbindPhoneRequest.json b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/Donut/DonutUnbindPhoneRequest.json new file mode 100644 index 00000000..d69dd37c --- /dev/null +++ b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/Donut/DonutUnbindPhoneRequest.json @@ -0,0 +1,3 @@ +{ + "user_id": "bbb" +} diff --git a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/Donut/DonutUnbindWeixinRequest.json b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/Donut/DonutUnbindWeixinRequest.json new file mode 100644 index 00000000..d69dd37c --- /dev/null +++ b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/Donut/DonutUnbindWeixinRequest.json @@ -0,0 +1,3 @@ +{ + "user_id": "bbb" +} diff --git a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/Donut/DonutUnregisterUserRequest.json b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/Donut/DonutUnregisterUserRequest.json new file mode 100644 index 00000000..d69dd37c --- /dev/null +++ b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/Donut/DonutUnregisterUserRequest.json @@ -0,0 +1,3 @@ +{ + "user_id": "bbb" +}