Forráskód Böngészése

完成端内通知到端外通知的接口。

CrazyIter_Bin 4 éve
szülő
commit
663bbaa459

+ 77 - 0
TEAMModelOS.SDK/Models/Service/NotificationService.cs

@@ -0,0 +1,77 @@
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.Net.Http;
+using System.Net.Http.Json;
+using System.Text;
+using System.Threading.Tasks;
+using TEAMModelOS.SDK.Extension;
+
+namespace TEAMModelOS.SDK.Models.Service
+{
+    public class NotificationService
+    {
+        private readonly HttpClient _httpClient;
+        public NotificationService(HttpClient httpClient)
+        {
+            _httpClient = httpClient;
+        }
+        public    async Task<int> SendNotification(string clientID, string clientSecret, string location, string url, Notification notification) {
+            if (location.Contains("China")) {
+                location = "China";
+            }
+            else if (location.Contains("Global"))
+            {
+                location = "Global";
+            }
+            var token = await CoreTokenExtensions.CreateAccessToken(clientID, clientSecret, location);
+            _httpClient.DefaultRequestHeaders.Add("Authorization",$"Bearer {token.AccessToken}" );
+            HttpResponseMessage responseMessage = await _httpClient.PostAsJsonAsync(url, notification);
+            if (responseMessage.StatusCode == HttpStatusCode.OK)
+            {
+                return 200;
+            }
+            else if (responseMessage.StatusCode == HttpStatusCode.Unauthorized)
+            {
+                return 401;
+            }
+            else {
+                return 500;
+            }
+        }
+    }
+
+    public class Notification {
+        /// <summary>
+        /// App name (hita) 小寫
+        /// </summary>
+        public string hubName { get; set; }
+        /// <summary>
+        /// 通知訊息種類,分為msg,info及notice。       
+        /// msg : 一般訊息,會存Redis,拿了就刪。
+        /// info : 公告訊息或給多人讀取的訊息,會存Redis,拿了不刪,只能等時間到期或透過API刪除。
+        /// notice : 屬於系統層級訊息,不存Redis,直接裸送訊息。
+        /// </summary>
+        public string type { get; set; }
+        /// <summary>
+        /// 送訊息的來源端 格式為"{服務}:{類別}: ..." 如"ies5:hbrd","ies5:hbrd:hb0901"
+        /// </summary>
+        public string from { get; set; }
+        /// <summary>
+        /// 接收對象或手機註冊的tag,ID或服務等...
+        /// </summary>
+        public List<string> to { get; set; }
+        /// <summary>
+        /// 	標題。
+        /// </summary>
+        public string label { get; set; }
+        /// <summary>
+        /// 正文。
+        /// </summary>
+        public string body { get; set; }
+        /// <summary>
+        /// 該訊息到期時間(UTC),單位為秒,且必須大於現在時間。
+        /// </summary>
+        public long expires { get; set; }
+    }
+}

+ 7 - 2
TEAMModelOS/Controllers/Core/CoreController.cs

@@ -7,6 +7,7 @@ using System.Collections.Generic;
 using System.Drawing.Imaging;
 using System.IO;
 using System.Linq;
+using System.Net.Http;
 using System.Reflection;
 using System.Text.Json;
 using System.Text.RegularExpressions;
@@ -15,6 +16,7 @@ using TEAMModelOS.Models;
 using TEAMModelOS.Models.Request;
 using TEAMModelOS.SDK.DI;
 using TEAMModelOS.SDK.Extension;
+using TEAMModelOS.SDK.Models.Service;
 using TEAMModelOS.SDK.PngQuant;
 
 namespace TEAMModelOS.Controllers.Core
@@ -26,13 +28,16 @@ namespace TEAMModelOS.Controllers.Core
         private readonly AzureStorageFactory _azureStorage;
         private readonly DingDing _dingDing;
         private readonly Option _option;
-
-        public CoreController(AzureStorageFactory azureStorage , DingDing dingDing, IOptionsSnapshot<Option> option)
+        private readonly HttpClient _httpClient;
+        public CoreController(AzureStorageFactory azureStorage , DingDing dingDing, IOptionsSnapshot<Option> option, HttpClient httpClient)
         {
             _azureStorage = azureStorage;
             _dingDing = dingDing;
             _option = option?.Value;
+            _httpClient = httpClient;
         }
+       
+
         [HttpPost("apply-school")]
         public async Task<IActionResult> ApplySchool(ApplySchool request) {
             await _dingDing.SendBotMsg($"有新学校申请。\n申请站点:{_option.Location}\n申请学校:{request.name}\n所在国家\\地区:{request.area}\n申请人:{request.tmdname}({request.tmdid})\n联系电话:{request.cellphone}\n备注:{request.content}", GroupNames.AI智慧學校申請通知群);

+ 83 - 4
TEAMModelOS/Controllers/School/SchoolTeacherController.cs

@@ -19,6 +19,9 @@ using Microsoft.Extensions.Options;
 using System.Net.Http;
 using TEAMModelOS.SDK.Context.Configuration;
 using System.Net;
+using Microsoft.Extensions.Configuration;
+using TEAMModelOS.SDK.Models.Service;
+using TEAMModelOS.Filter;
 
 namespace TEAMModelOS.Controllers
 {
@@ -33,11 +36,15 @@ namespace TEAMModelOS.Controllers
         private readonly AzureCosmosFactory _azureCosmos;
         private readonly AzureStorageFactory _azureStorage;
         private readonly Option _option;
-        public SchoolTeacherController(AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage, IOptionsSnapshot<Option> option)
+        private readonly IConfiguration _configuration;
+        private readonly NotificationService _notificationService;
+        public SchoolTeacherController(AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage, IOptionsSnapshot<Option> option, IConfiguration configuration, NotificationService notificationService)
         {
             _azureCosmos = azureCosmos;
             _azureStorage = azureStorage;
             _option = option?.Value;
+            _configuration = configuration;
+            _notificationService = notificationService;
         }
         /// <summary>
         /// 取得學校所有老師(不論加入狀態)
@@ -194,8 +201,10 @@ namespace TEAMModelOS.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("add-teacher-status")]
+        [AuthToken(Roles = "teacher,admin")]
         public async Task<IActionResult> AddSchoolTeacher(JsonElement request)
         {
+            var (tid, tname, _, tschool) = HttpContext.GetAuthTokenInfo();
             var client = _azureCosmos.GetCosmosClient();
             //參數取得
             if (!request.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
@@ -216,11 +225,13 @@ namespace TEAMModelOS.Controllers
             }
             try
             {
+                List<TmdInfo> ids = new List<TmdInfo>();
                 foreach (var obj in user_list.EnumerateArray())
                 {
                     obj.TryGetProperty("id", out JsonElement id);
                     obj.TryGetProperty("name", out JsonElement name);
                     obj.TryGetProperty("picture", out JsonElement picture);
+                    ids.Add(new TmdInfo { tmdid=$"{id}",tmdname=$"{name}" });
                     //老師個人資料
                     var tresponse = await client.GetContainer("TEAMModelOS", "Teacher").ReadItemStreamAsync(id.ToString(), new PartitionKey("Base"));
                     if(tresponse.Status == 200)
@@ -290,6 +301,26 @@ namespace TEAMModelOS.Controllers
                         await client.GetContainer("TEAMModelOS", "School").CreateItemStreamAsync(stream, new PartitionKey($"Teacher-{school_code}"));
                     }
                 }
+                string bizcode = grant_type.GetString();
+                if (grant_type.GetString() == "join")
+                {
+                    bizcode = "request-join";
+                }
+                Notification notification = new Notification
+                {
+                    hubName = "hita",
+                    type = "msg",
+                    from = $"ies5:{school_code}",
+                    to = ids.Select(x => x.tmdid).ToList(),
+                    label = $"{bizcode}_school",
+                    body = new { biz = bizcode, tmdid = tid, tmdname = tname.ToString(), schoolcode = $"{school_code}", schoolname = $"{schname}", status = 1, time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() }.ToJsonString(),
+                    expires = DateTimeOffset.UtcNow.AddDays(7).ToUnixTimeSeconds()
+                };
+                var url = _configuration.GetValue<string>("HaBookAuth:CoreService:sendnotification");
+                var clientID = _configuration.GetValue<string>("HaBookAuth:CoreService:clientID");
+                var clientSecret = _configuration.GetValue<string>("HaBookAuth:CoreService:clientSecret");
+                var location = _option.Location;
+                var code = await _notificationService.SendNotification(clientID, clientSecret, location, url, notification);
                 return Ok(new { });
             }
             catch(Exception ex)
@@ -304,12 +335,13 @@ namespace TEAMModelOS.Controllers
         /// <param name="request"></param>
         /// <returns></returns>
         [ProducesDefaultResponseType]
-        //[AuthToken(Roles = "admin")]
+        [AuthToken(Roles = "admin")]
         [HttpPost("upd-teacher-status")]
         public async Task<IActionResult> UpdSchoolTeacherStatus(JsonElement request)
         {
             try
             {
+                var (tid, tname, _, tschool) = HttpContext.GetAuthTokenInfo();
                 if (!request.TryGetProperty("grant_type", out JsonElement grant_type)) return BadRequest();
                 if (!request.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
                 if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
@@ -364,7 +396,26 @@ namespace TEAMModelOS.Controllers
                     };
                     var response = await client.GetContainer("TEAMModelOS", "School").CreateItemAsync(st, new PartitionKey($"Teacher-{school_code}"));
                 }
-
+                string bizcode = grant_type.GetString();
+                if (grant_type.GetString() == "join")
+                {
+                    bizcode = "request-join";
+                }
+                Notification notification = new Notification
+                {
+                    hubName = "hita",
+                    type = "msg",
+                    from = $"ies5:{school_code}",
+                    to =new List<string> { teacher.id },
+                    label = $"{bizcode}_school",
+                    body = new { biz = bizcode, tmdid = tid, tmdname =tname, schoolcode = $"{school_code}", schoolname = $"{schname}", status = 1, time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() }.ToJsonString(),
+                    expires = DateTimeOffset.UtcNow.AddDays(7).ToUnixTimeSeconds()
+                };
+                var url = _configuration.GetValue<string>("HaBookAuth:CoreService:sendnotification");
+                var clientID = _configuration.GetValue<string>("HaBookAuth:CoreService:clientID");
+                var clientSecret = _configuration.GetValue<string>("HaBookAuth:CoreService:clientSecret");
+                var location = _option.Location;
+                var code = await _notificationService.SendNotification(clientID, clientSecret, location, url, notification);
                 return Ok(new { });
             }
             catch (Exception ex)
@@ -385,6 +436,7 @@ namespace TEAMModelOS.Controllers
         {
             try
             {
+                var (tid, tname, _, tschool) = HttpContext.GetAuthTokenInfo();
                 if (!request.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
                 if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
 
@@ -395,7 +447,34 @@ namespace TEAMModelOS.Controllers
                 await client.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync<Teacher>(teacher, id.ToString(), new PartitionKey("Base"));
                 //移除學校表中的老師document
                 var sresponse = await client.GetContainer("TEAMModelOS", "School").DeleteItemStreamAsync(id.GetString(), new PartitionKey($"Teacher-{school_code}"));
-
+                //取得學校資訊
+                var schresponse = await client.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync(school_code.ToString(), new PartitionKey("Base"));
+                string schname = string.Empty;
+                if (schresponse.Status == 200)
+                {
+                    using var schjson = await JsonDocument.ParseAsync(schresponse.ContentStream);
+                    schjson.RootElement.TryGetProperty("name", out JsonElement jsonschname);
+                    schname = jsonschname.ToString();
+                }
+                else
+                {
+                    return BadRequest();
+                }
+                Notification notification = new Notification
+                {
+                    hubName = "hita",
+                    type = "msg",
+                    from = $"ies5:{school_code}",
+                    to = new List<string> { teacher.id },
+                    label = $"remove_school",
+                    body = new { biz = "remove", tmdid = tid, tmdname = tname, schoolcode = $"{school_code}", schoolname = $"{schname}", status = 1, time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() }.ToJsonString(),
+                    expires = DateTimeOffset.UtcNow.AddDays(7).ToUnixTimeSeconds()
+                };
+                var url = _configuration.GetValue<string>("HaBookAuth:CoreService:sendnotification");
+                var clientID = _configuration.GetValue<string>("HaBookAuth:CoreService:clientID");
+                var clientSecret = _configuration.GetValue<string>("HaBookAuth:CoreService:clientSecret");
+                var location = _option.Location;
+                var code = await _notificationService.SendNotification(clientID, clientSecret, location, url, notification);
                 return Ok(new { });
             }
             catch (Exception ex)

+ 43 - 3
TEAMModelOS/Controllers/Teacher/InitController.cs

@@ -19,6 +19,9 @@ using TEAMModelOS.SDK.Extension;
 using TEAMModelOS.Filter;
 using TEAMModelOS.SDK.Models.Cosmos;
 using HTEXLib.COMM.Helpers;
+using TEAMModelOS.SDK.Models.Service;
+using Microsoft.Extensions.Configuration;
+using System.Net.Http;
 
 namespace TEAMModelOS.Controllers
 {
@@ -33,13 +36,16 @@ namespace TEAMModelOS.Controllers
         private readonly AzureStorageFactory _azureStorage;
         private readonly DingDing _dingDing;
         private readonly Option _option;
-
-        public InitController(AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage, DingDing dingDing, IOptionsSnapshot<Option> option)
+        private readonly IConfiguration _configuration; 
+        private readonly NotificationService _notificationService;
+        public InitController(AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage, DingDing dingDing, IOptionsSnapshot<Option> option, IConfiguration configuration, NotificationService notificationService)
         {
             _azureCosmos = azureCosmos;
             _azureStorage = azureStorage;
             _dingDing = dingDing;
             _option = option?.Value;
+            _configuration = configuration;
+            _notificationService = notificationService;
         }
 
         //TODO 此API需處理對應前端返回的相關數據
@@ -403,6 +409,8 @@ namespace TEAMModelOS.Controllers
                 if (!requert.TryGetProperty("grant_type", out JsonElement grant_type)) return BadRequest();  //"invite":學校邀請 "request":老師申請 "join":"成為學校老師",leave 离开,cancel 取消。
                 if (!requert.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
                 if (!requert.TryGetProperty("school_name", out JsonElement school_name)) return BadRequest();
+                ///当邀请某个老师加入学校则需要知道是谁邀请的
+                //if (!requert.TryGetProperty("school_admin", out JsonElement school_admin)) return BadRequest();
                 string authtoken = HttpContext.GetXAuth("AuthToken");
                 if (string.IsNullOrEmpty(authtoken)) return BadRequest();
                 var jwt = new JwtSecurityToken(authtoken);
@@ -411,7 +419,6 @@ namespace TEAMModelOS.Controllers
                 var Claims = jwt.Payload.Claims;
                 jwt.Payload.TryGetValue("name", out object name);
                 jwt.Payload.TryGetValue("picture", out object picture);
-
                 var client = _azureCosmos.GetCosmosClient();
                 //在老師表找出老師,處理該學校狀態 (老師基本資料應該要存在)
                 Teacher teacher = await client.GetContainer("TEAMModelOS", "Teacher").ReadItemAsync<Teacher>(id, new PartitionKey("Base"));
@@ -441,6 +448,7 @@ namespace TEAMModelOS.Controllers
                     return Ok(new { stauts = 1 });
                 }
                 else {
+                    
                     await client.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync<Teacher>(teacher, id, new PartitionKey("Base"));
                     //在學校表處理該學校教師帳號的狀態
                     var sresponse = await client.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync(id, new PartitionKey($"Teacher-{school_code}"));
@@ -467,6 +475,38 @@ namespace TEAMModelOS.Controllers
                         };
                         var response = await client.GetContainer("TEAMModelOS", "School").CreateItemAsync(st, new PartitionKey($"Teacher-{school_code}"));
                     }
+                    Notification notification = null;
+                    
+                    List<SchoolTeacher> teachers = new List<SchoolTeacher>();
+                    var queryslt = $"SELECT  value(c)  FROM c join A1 in c.roles   where  A1 in ('admin')";
+                    await foreach (var item in client.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<SchoolTeacher>(queryText: queryslt, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Teacher-{school_code}") }))
+                    {
+                        teachers.Add(item);
+                    }
+                    if (teachers.IsNotEmpty()) {
+                        string code = grant_type.GetString();
+                        if (grant_type.GetString() == "join") {
+                            code = "invite-join";
+                        }
+                            notification = new Notification
+                        {
+                            hubName = "hita",
+                            type = "msg",
+                            from = $"ies5:{school_code}",
+                            to = teachers.Select(x => x.id).ToList(),
+                            label = $"{code}_school",
+                            body = new {biz= code, tmdid= id ,tmdname= name.ToString(), schoolcode=$"{school_code}", schoolname=$"{school_name}", status =1,time= DateTimeOffset.UtcNow .ToUnixTimeMilliseconds()}.ToJsonString(),
+                            expires= DateTimeOffset.UtcNow.AddDays(7).ToUnixTimeSeconds()
+                        };
+                    }
+                    
+                    if (notification != null) {
+                        var url= _configuration.GetValue<string>("HaBookAuth:CoreService:sendnotification");
+                        var clientID= _configuration.GetValue<string>("HaBookAuth:CoreService:clientID");
+                        var clientSecret = _configuration.GetValue<string>("HaBookAuth:CoreService:clientSecret");
+                        var location = _option.Location;
+                        var code = await _notificationService .SendNotification(clientID, clientSecret, location, url, notification);
+                    }
                     return Ok(new { stauts = 1 });
                 }
             }

+ 2 - 2
TEAMModelOS/Startup.cs

@@ -25,6 +25,7 @@ using TEAMModelOS.SDK;
 using TEAMModelOS.SDK.Context.Attributes.Azure;
 using TEAMModelOS.SDK.Context.Configuration;
 using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Models.Service;
 using VueCliMiddleware;
 
 namespace TEAMModelOS
@@ -99,14 +100,13 @@ namespace TEAMModelOS
             services.AddSnowflakeId(Convert.ToInt64(Configuration.GetValue<string>("Option:LocationNum")), 1);
             services.AddHttpClient();
             services.AddHttpClient<DingDing>();
+            services.AddHttpClient<NotificationService>();
             services.AddMemoryCache();
             services.AddSpaStaticFiles(opt => opt.RootPath = "ClientApp/dist");
             services.AddControllers().AddJsonOptions(options => { options.JsonSerializerOptions.IgnoreNullValues = false; });
-
             //HttpContextAccessor,并用来访问HttpContext。(提供組件或非控制器服務存取HttpContext)
             services.AddHttpContextAccessor();
             services.Configure<Option>(options => Configuration.GetSection("Option").Bind(options));
-           
             //注入word 標籤解析
             string path = $"{ environment.ContentRootPath}/JsonFile/Core";
             services.AddHtexTranslator(path);

+ 6 - 1
TEAMModelOS/appsettings.Development.json

@@ -42,7 +42,12 @@
       "userinfo": "https://api2.teammodel.cn/Oauth2/GetUserInfos"
     },
     "CoreService": {
-      "deviceinfo": "https://api2.teammodel.cn/oauth2/getdeviceinfos"
+      "clientID": "c7317f88-7cea-4e48-ac57-a16071f7b884",
+      "clientSecret": "kguxh:V.PLmxBdaI@jnrTrDSth]A3346",
+      "deviceinfo": "https://api2.teammodel.cn/oauth2/getdeviceinfos",
+      "sendnotification": "https://api2.teammodel.net/service/sendnotification",
+      "getnotification": "https://api2.teammodel.net/service/getnotification",
+      "delnotification": "https://api2.teammodel.net/service/delnotification"
     }
   }
 }

+ 4 - 1
TEAMModelOS/appsettings.json

@@ -43,7 +43,10 @@
       "userinfo": "https://api2.teammodel.cn/Oauth2/GetUserInfos"
     },
     "CoreService": {
-      "deviceinfo": "https://api2.teammodel.cn/oauth2/getdeviceinfos"
+      "deviceinfo": "https://api2.teammodel.cn/oauth2/getdeviceinfos",
+      "sendnotification": "https://api2.teammodel.net/service/sendnotification",
+      "getnotification": "https://api2.teammodel.net/service/getnotification",
+      "delnotification": "https://api2.teammodel.net/service/delnotification"
     }
   }
 }