using HTEXLib.COMM.Helpers; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; using OpenXmlPowerTools; using System; using System.Collections.Generic; using System.Dynamic; using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Json; using System.Security.Policy; using System.Text; using System.Text.Json; using System.Threading.Tasks; using TEAMModelOS.Models; using TEAMModelOS.SDK.DI; using TEAMModelOS.SDK.DI.CoreAPI; using TEAMModelOS.SDK.Extension; using TEAMModelOS.SDK.Models; namespace TEAMModelOS.SDK { public static class CoreAPIHttpServiceExtensions { public static IServiceCollection AddCoreAPIHttpService(this IServiceCollection services, IConfiguration _configuration,string name = "Default") { if (services == null) throw new ArgumentNullException(nameof(services)); string location = _configuration.GetValue("Option:Location"); string url = _configuration.GetValue("HaBookAuth:CoreAPI"); var clientID = _configuration.GetValue("HaBookAuth:CoreService:clientID"); var clientSecret = _configuration.GetValue("HaBookAuth:CoreService:clientSecret"); services.AddSingleton(); services.Configure(name , o => { o.location = location;o.url =url;o.clientID = clientID; o.clientSecret = clientSecret; }); return services; } } public class CoreAPIHttpServiceOptions { public string location { get; set; } public string url { get; set; } public string clientID { get; set; } public string clientSecret { get; set; } } public class CoreAPIHttpService { //private readonly IWebHostEnvironment _environment; public bool check=true; private SnowflakeId _snowflakeId; private readonly HttpClient _httpClient; public readonly IOptionsMonitor options; //private readonly IConfiguration _configuration; // private readonly DI.DingDing _dingDing; //public readonly Option _option; public CoreAPIHttpService(HttpClient httpClient, IOptionsMonitor optionsMonitor, SnowflakeId snowflakeId) { _httpClient = httpClient; options = optionsMonitor; //_environment = environment; _snowflakeId= snowflakeId; //_option = option?.Value; //_configuration = configuration; //_dingDing = dingDing; } public class CoreAPIToken { public string id_token { get; set; } public string access_token { get; set; } public string expires_in { get; set; } public string token_type { get; set; } } public async Task<(HttpStatusCode code , CoreAPIToken token )> GetCoreAPIoAuth2Token(Dictionary data, string location, IConfiguration _configuration, DI.DingDing _dingDing) { try { var url = _configuration.GetValue("HaBookAuth:CoreAPI"); //url = "https://api2-rc.teammodel.cn"; url = $"{url}/oauth2/token"; var clientID = _configuration.GetValue("HaBookAuth:CoreService:clientID"); var clientSecret = _configuration.GetValue("HaBookAuth:CoreService:clientSecret"); if (location.Contains("China")) { location = "China"; } else if (location.Contains("Global")) { location = "Global"; } var client = _httpClient ; var token = await CoreTokenExtensions.CreateAccessToken(clientID, clientSecret, location); if (client.DefaultRequestHeaders.Contains("Authorization")) { client.DefaultRequestHeaders.Remove("Authorization"); } client.DefaultRequestHeaders.Add("Authorization", $"Bearer {token.AccessToken}"); HttpResponseMessage responseMessage = await client.PostAsJsonAsync(url, data); if (responseMessage.Content != null) { string content = await responseMessage.Content.ReadAsStringAsync(); if (!string.IsNullOrWhiteSpace(content)) { CoreAPIToken coreAPI = content.ToObject(); return (responseMessage.StatusCode, coreAPI); } else { return (responseMessage.StatusCode, null); } } else { return (responseMessage.StatusCode, null); } } catch (Exception ex) { await _dingDing.SendBotMsg($"{location}验证码发送异常:\n{ex.Message}\n{ex.StackTrace}", DI.GroupNames.醍摩豆服務運維群組); return (HttpStatusCode.InternalServerError, null); } } /* hubName string Optional 指定要傳送到哪個訊息中樞,若沒給則不傳送端外通知,只會發送端內通知。(目前只有"hita"及"hita5"能使用) sender string Optional 發送訊息的來源端 tags string array Required 接收對象或手機註冊的tag,ID或服務等... title string Optional 標題,會"直接"顯示於端外通知的title位置 body string Optional 正文,會"直接"顯示於端外通知的body位置 eventId string Optional 事件ID eventName string Optional 事件名稱 data string Optional 額外資料 'request_school': vm.$t('notice.type1'), // 管理员收到他人申请加入的通知 'invite_school': vm.$t('notice.type2'), // 你收到学校邀请你的通知 'remove_school': vm.$t('notice.type3'), // 学校将你移除的通知 'request-join_school': vm.$t('notice.type1'), // 学校同意你的加入请求 'invite-join_school': vm.$t('notice.type2'), // 某人已同意你对他的邀请 'coedit_syllabus': vm.$t('notice.type4'), // 邀请课纲共编的通知 'share_syllabus': vm.$t('notice.type4'), // 个人课纲分享的通知 'transfer-admin_school': vm.$t('notice.type5'), // 管理员转移的通知 'scoring-arb_school': vm.$t('notice.type6'), // 仲裁卷阅卷任务分配通知 'scoring-err_school': vm.$t('notice.type6'), // 异常卷阅卷任务分配通知 'scoring-mark_school': vm.$t('notice.type6'), // 普通阅卷任务分配通知 'scan-join_groupList': vm.$t('notice.type7'), // 扫码加入名单通知 'scan-join_school': vm.$t('notice.type7'), // 扫码加入学校通知 'submitanswer_homework': vm.$t('notice.type8'), // 作业提交通知 'expire_lessonRecord': vm.$t('notice.type9'), // 课例过期通知 */ /// /// /// 發送端內外通知 /// /// id: 教师id,name 教师名称,code 语系 /// /// /// /// /// /// /// /// public void PushNotify(List toTeachers , string notifyCode,string notifyType,Dictionary replaceData, string location, IConfiguration _configuration, DI.DingDing _dingDing,string rootPath) { /* * IES5_Management shift-assist_school DelBeforeCopyAbility-mark_start copyAbility-mark_finish copyAbility-mark_start * transfer-admin_school invite-join_school invite_school request_school request-join_school remove_school scan-join_school * IES5_Course submitanswer_homework scan-join_groupList expire-school_lessonRecord * IES5_Task scoring-mark_school scoring-arb_school scoring-err_school * IES5_Contect coedit_syllabus share_syllabus { "hubName":"hita5", "sender":"ies5", "tags":["1595321354_IES5_Management"] "title":"", "body":"", "eventId":"", "eventName":"", "data":""action":{"type":"click\link","tokenbindtype":1,"url":"http://xxxx"}" } { "action":[ //陣列, 可以包含多個按鈕 { "type":"click", //按鈕 "label":"Ok", //按鈕的字 "url":"https://www.teammodel.net?code=", // POST API "tokenbindtype":1 //附掛 code token到 utl 後面 } ] } { "action": [ { "type": "click", "label": "\\u67e5\\u770b", "url": "https:\\/\\/sokrates.teammodel.org\\/exhibition\\/tbavideo\\/check-with-habook\\/?to=aHR0cHM6Ly9zb2tyYXRlcy50ZWFtbW9kZWwub3JnL2V4aGliaXRpb24vdGJhdmlkZW8jL2NvbnRlbnQvMTM5MzU\\/Z3JvdXBJZHM9MTQxJmNoYW5uZWxJZD0xMzA=&ticket=", "tokenbindtype": 1 } ] } */ try { string lang = location.Contains("China") ? "zh-cn" : "en-us"; toTeachers.FindAll(x => string.IsNullOrWhiteSpace(x.code) || (!x.code.Equals("zh-cn") && !x.code.Equals("zh-tw") && !x.code.Equals("en-us"))).ForEach(x => { x.code = lang; }); var groups = toTeachers.GroupBy(x => x.code).Select(x => new { x.Key, list = x.ToList() }); var clientID = _configuration.GetValue("HaBookAuth:CoreService:clientID"); var clientSecret = _configuration.GetValue("HaBookAuth:CoreService:clientSecret"); var url = _configuration.GetValue("HaBookAuth:CoreAPI"); string site = location; if (location.Contains("China")) { location = "China"; } else if (location.Contains("Global")) { location = "Global"; } replaceData.Add("notifyCode", notifyCode); replaceData.Add("location", site); if (replaceData.ContainsKey("schoolId")) { replaceData.Add("scope", "school"); } else { replaceData.Add("scope", "private"); } var client = _httpClient; var token = CoreTokenExtensions.CreateAccessToken(clientID, clientSecret, location).Result; if (client.DefaultRequestHeaders.Contains("Authorization")) { client.DefaultRequestHeaders.Remove("Authorization"); client.DefaultRequestHeaders.Add("Authorization", $"Bearer {token.AccessToken}"); } else { client.DefaultRequestHeaders.Add("Authorization", $"Bearer {token.AccessToken}"); } foreach (var group in groups) { string path =Path.Combine(rootPath, $"Lang/{group.Key}.json"); var sampleJson = File.ReadAllBytes(path).AsSpan(); Utf8JsonReader reader = new Utf8JsonReader(sampleJson); if (JsonDocument.TryParseValue(ref reader, out JsonDocument jsonDoc) && jsonDoc.RootElement.TryGetProperty(notifyCode, out JsonElement json)) { List msgs = json.ToObject>(); List actions = new List(); if (msgs.IsNotEmpty()) { dynamic action = new ExpandoObject(); //处理action string urlAction = ""; if (notifyCode.Equals("request_school") || notifyCode.Equals("invite_school")) { if (site.Equals("Global")) { urlAction = "https://www.teammodel.net/core/process-notify"; } if (site.Equals("Global-Test")|| site.Equals("Global-Dep")) { urlAction = "https://test.teammodel.net/core/process-notify"; } if (site.Equals("China")) { urlAction = "https://www.teammodel.cn/core/process-notify"; } if (site.Equals("China-Test")|| site.Equals("China-Dep")) { urlAction = "https://test.teammodel.cn/core/process-notify"; } byte[] byts = Encoding.Unicode.GetBytes(replaceData.ToJsonString()); var rdata=Convert.ToBase64String(byts); byte[] bs= Convert.FromBase64String(rdata); string data1 = Encoding.Unicode.GetString(bs); urlAction = $"{urlAction}?notifyCode={notifyCode}&data={rdata}"; if (msgs.Count == 3) { string urlA = $"{urlAction}¬ifyEvent=1&ticket="; actions.Add(new { type = "click", label = msgs[2], url = urlA, tokenbindtype = 1 }); } if (msgs.Count == 4) { string urlA = $"{urlAction}¬ifyEvent=1&ticket="; string urlB = $"{urlAction}¬ifyEvent=2&ticket="; actions.Add(new { type = "click", label = msgs[2], url = urlA, tokenbindtype = 1 }); actions.Add(new { type = "click", label = msgs[3], url = urlB, tokenbindtype = 1 }); } } var tags = group.list.Select(x => $"{x.id}_{notifyType}"); string data = new { value = replaceData }.ToJsonString(); if (actions.Any()) { data=new { value = replaceData ,action=actions}.ToJsonString(); } NotifyData notifyData = new NotifyData { hubName = "hita5", sender = "IES", tags = tags.ToList(), title = msgs[0], eventId = $"{notifyCode}-{_snowflakeId.NextId()}", eventName = $"{msgs[0]}", data = data }; if (msgs.Count == 1) { notifyData.body = msgs[0]; } else { replaceData.Keys.ToList().ForEach(x => { msgs[1] = msgs[1].Replace("{" + x + "}", $"{replaceData[x]}"); }); notifyData.body = msgs[1]; } string result = ""; HttpResponseMessage responseMessage = _httpClient.PostAsJsonAsync($"{url}/service/PushNotify", notifyData).Result; if (responseMessage.StatusCode == HttpStatusCode.OK) { string content = responseMessage.Content.ReadAsStringAsync().Result; result = content; } else { result = $"{responseMessage.StatusCode},推送返回的状态码。"; } // _dingDing.SendBotMsg($"{location}站点发送消息:\n{url}/service/PushNotify \nheader: {token.AccessToken} \nresult:{result}\n params:{notifyData.ToJsonString()}", GroupNames.成都开发測試群組).GetAwaiter().GetResult(); } } } } catch (Exception ex) { _ = _dingDing.SendBotMsg($"{location},通知V2发送异常\n{ex.Message}\n{ex.StackTrace}\n{replaceData.ToJsonString()}\n{toTeachers.ToJsonString()}\n{notifyCode}", GroupNames.醍摩豆服務運維群組); } } public class NotifyData { public string hubName { get; set; } public string sender { get; set; } public List tags { get; set; } = new List(); public string title { get; set; } public string body { get; set; } public string eventId { get; set; } public string eventName { get; set; } public string data { get; set; } } /// /// 发送短信验证码 /// /// /// /// /// /// /// public async Task<(HttpStatusCode code ,string content)> SendSmsPin(Dictionary data, string location, IConfiguration _configuration, DI.DingDing _dingDing) { try { var url = _configuration.GetValue("HaBookAuth:CoreAPI"); //url = "https://api2-rc.teammodel.cn"; url = $"{url}/service/sandsms/pin"; var clientID = _configuration.GetValue("HaBookAuth:CoreService:clientID"); var clientSecret = _configuration.GetValue("HaBookAuth:CoreService:clientSecret"); if (location.Contains("China")) { location = "China"; } else if (location.Contains("Global")) { location = "Global"; } var client = _httpClient; var token = await CoreTokenExtensions.CreateAccessToken(clientID, clientSecret, location); if (client.DefaultRequestHeaders.Contains("Authorization")) { client.DefaultRequestHeaders.Remove("Authorization"); } client.DefaultRequestHeaders.Add("Authorization", $"Bearer {token.AccessToken}"); HttpResponseMessage responseMessage = await client.PostAsJsonAsync(url, data); if (responseMessage.Content != null) { string content = await responseMessage.Content.ReadAsStringAsync(); if (!string.IsNullOrWhiteSpace(content)) { return (responseMessage.StatusCode, content); } else { return (responseMessage.StatusCode, null); } } else { return (responseMessage.StatusCode, null); } } catch (Exception ex) { await _dingDing.SendBotMsg($"{location}验证码发送异常:\n{ex.Message}\n{ex.StackTrace}", DI.GroupNames.醍摩豆服務運維群組); return (HttpStatusCode.InternalServerError,null); } } /// /// 隐式登录 /// /// /// /// /// /// /// public async Task Implicit( Dictionary data,string location, IConfiguration _configuration) { var url = _configuration.GetValue("HaBookAuth:CoreAPI"); //url = "https://api2-rc.teammodel.cn"; url = $"{url}/oauth2/implicit"; var clientID = _configuration.GetValue("HaBookAuth:CoreService:clientID"); var clientSecret = _configuration.GetValue("HaBookAuth:CoreService:clientSecret"); if (location.Contains("China")) { location = "China"; } else if (location.Contains("Global")) { location = "Global"; } var client = _httpClient; var token = await CoreTokenExtensions.CreateAccessToken(clientID, clientSecret, location); if (client.DefaultRequestHeaders.Contains("Authorization")) { client.DefaultRequestHeaders.Remove("Authorization"); } client.DefaultRequestHeaders.Add("Authorization", $"Bearer {token.AccessToken}"); HttpResponseMessage responseMessage = await client.PostAsJsonAsync(url, data); if (responseMessage.StatusCode == HttpStatusCode.OK) { string content=await responseMessage.Content.ReadAsStringAsync(); if (!string.IsNullOrEmpty(content)) { TmdidImplicit tmdidImplicit = content.ToObject(); return tmdidImplicit; } else { return null; } } else if (responseMessage.StatusCode == HttpStatusCode.Unauthorized) { return null; } else { return null; } } /// /// 获取多个用户信息 /// /// /// /// /// /// /// public async Task GetUserInfos(StringContent scontent, string name = "Default") { var clientID = options.Get(name).clientID; var clientSecret = options.Get(name).clientSecret; var location = options.Get(name).location; var url = options.Get(name).url; if (location.Contains("China")) { url =string.IsNullOrWhiteSpace(url)? "https://api2.teammodel.cn":url; location = "China"; } else if (location.Contains("Global")) { url = string.IsNullOrWhiteSpace(url) ? "https://api2.teammodel.net" : url; location = "Global"; } url = $"{url}/oauth2/getuserinfos"; var client = _httpClient; var token = await CoreTokenExtensions.CreateAccessToken(clientID, clientSecret, location); if (client.DefaultRequestHeaders.Contains("Authorization")) { client.DefaultRequestHeaders.Remove("Authorization"); } client.DefaultRequestHeaders.Add("Authorization", $"Bearer {token.AccessToken}"); HttpResponseMessage responseMessage = await client.PostAsync(url, scontent); if (responseMessage.StatusCode == HttpStatusCode.OK) { string content = await responseMessage.Content.ReadAsStringAsync(); if (!string.IsNullOrEmpty(content)) { return content; } else { return null; } } else if (responseMessage.StatusCode == HttpStatusCode.Unauthorized) { return null; } else { return null; } } /// /// 获取单个用户信息 /// /// /// /// /// /// /// public async Task GetUserInfo(Dictionary data, string location, IConfiguration _configuration) { var url = _configuration.GetValue("HaBookAuth:CoreAPI"); //url = "https://api2-rc.teammodel.cn"; url = $"{url}/oauth2/getuserinfo"; var clientID = _configuration.GetValue("HaBookAuth:CoreService:clientID"); var clientSecret = _configuration.GetValue("HaBookAuth:CoreService:clientSecret"); if (location.Contains("China")) { location = "China"; } else if (location.Contains("Global")) { location = "Global"; } var client = _httpClient; var token = await CoreTokenExtensions.CreateAccessToken(clientID, clientSecret, location); if (client.DefaultRequestHeaders.Contains("Authorization")) { client.DefaultRequestHeaders.Remove("Authorization"); } client.DefaultRequestHeaders.Add("Authorization", $"Bearer {token.AccessToken}"); HttpResponseMessage responseMessage = await client.PostAsJsonAsync(url, data); if (responseMessage.StatusCode == HttpStatusCode.OK) { string content = await responseMessage.Content.ReadAsStringAsync(); if (!string.IsNullOrEmpty(content)) { CoreUserInfo coreUserInfo = content.ToObject(); if (coreUserInfo != null) { bool isActivate = !string.IsNullOrWhiteSpace(coreUserInfo.password) || !string.IsNullOrWhiteSpace(coreUserInfo.passwordOld); CoreUser coreUser = new CoreUser { isActivate = isActivate, id = coreUserInfo.id, vid = coreUserInfo.vid, mail = coreUserInfo.mail, mobile = coreUserInfo.mobile, name = coreUserInfo.name, picture = coreUserInfo.picture, habook = coreUserInfo.habook, wechat = coreUserInfo.wechat, facebook = coreUserInfo.facebook, google = coreUserInfo.google, ding = coreUserInfo.ding, apple = coreUserInfo.apple, }; return coreUser; } else { return null; } } else { return null; } } else if (responseMessage.StatusCode == HttpStatusCode.Unauthorized) { return null; } else { return null; } } } public class TmdidImplicit { public string id_token { get; set; } public string access_token { get; set; } public string expires_in { get; set; } public string token_type { get; set; } } public class CoreUser { public string searchKey { get; set; } public string id { get; set; } public string vid { get; set; } public string mail { get; set; } public string mobile { get; set; } public string name { get; set; } public string picture { get; set; } public string habook { get; set; } public string wechat { get; set; } public string facebook { get; set; } public string google { get; set; } public string ding { get; set; } public string apple { get; set; } public bool isActivate { get; set; } } public class CoreUserInfo : CoreUser { public string area { get; set; } public string country { get; set; } public string type { get; set; } public string password { get; set; } public string salt { get; set; } public string passwordOld { get; set; } public string saltOld { get; set; } } }