KnowledgesController.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. using Microsoft.AspNetCore.Mvc;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Threading.Tasks;
  6. using TEAMModelOS.Models;
  7. using TEAMModelOS.SDK.DI;
  8. using System.Text.Json;
  9. using TEAMModelOS.SDK.Helper.Common.StringHelper;
  10. using TEAMModelOS.SDK.Models;
  11. using Microsoft.AspNetCore.Http;
  12. using TEAMModelOS.SDK.Extension;
  13. using Azure.Cosmos;
  14. using Microsoft.AspNetCore.Authentication;
  15. using System.Text;
  16. using TEAMModelOS.SDK.DI.AzureCosmos.Inner;
  17. using Microsoft.Extensions.Options;
  18. using TEAMModelOS.Filter;
  19. using HTEXLib.COMM.Helpers;
  20. using Microsoft.AspNetCore.Authorization;
  21. using TEAMModelOS.SDK;
  22. using static TEAMModelOS.SDK.ValidatorHelper;
  23. using System.ComponentModel.DataAnnotations;
  24. namespace TEAMModelOS.Controllers
  25. {
  26. [ProducesResponseType(StatusCodes.Status200OK)]
  27. [ProducesResponseType(StatusCodes.Status400BadRequest)]
  28. [Route("knowledges")]
  29. [ApiController]
  30. public class KnowledgesController : ControllerBase
  31. {
  32. private readonly SnowflakeId _snowflakeId;
  33. private readonly AzureCosmosFactory _azureCosmos;
  34. private readonly DingDing _dingDing;
  35. private readonly Option _option;
  36. private readonly AzureRedisFactory _azureRedis;
  37. private readonly HttpTrigger _httpTrigger;
  38. public KnowledgesController(HttpTrigger httpTrigger, AzureCosmosFactory azureCosmos, SnowflakeId snowflakeId, DingDing dingDing, IOptionsSnapshot<Option> option, AzureRedisFactory azureRedis)
  39. {
  40. _azureCosmos = azureCosmos;
  41. _snowflakeId = snowflakeId;
  42. _dingDing = dingDing;
  43. _option = option?.Value;
  44. _azureRedis = azureRedis;
  45. _httpTrigger = httpTrigger;
  46. }
  47. /**
  48. *
  49. {
  50. "periodId": "ca484aa8-e7b5-4a7c-8ef3-bd9e7b7d4fp2",
  51. "subjectId":"ac73f07d-2cc8-4174-85ae-b39cc5b6beef",
  52. "scope":"school",
  53. "owner":"hbcn",
  54. "points": [
  55. "一元一次方程","二元一次方程","一元二次方程","直线方程","三元一次方程","鸡兔同笼问题","微积分方程","函数有界性","函数单调性","函数奇偶性","函数周期性","函数连续性","函数凹凸性",
  56. "常函数","一次函数","二次函数","三次函数","四次函数","五次函数","幂函数","指数函数","对数函数","三角函数","反三角函数","常数函数",
  57. "正弦函数","余弦函数","正切函数","余切函数","正割函数","余割函数","正矢函数","余矢函数","半正矢函数","半余矢函数","外正割函数","外余割函数"
  58. ],
  59. "blocks":[
  60. {
  61. "name": "方程式" ,
  62. "points":["一元一次方程","二元一次方程","一元二次方程","直线方程","三元一次方程","鸡兔同笼问题","微积分方程"]
  63. },
  64. {
  65. "name": "函数的特性" ,
  66. "points": ["函数有界性","函数单调性","函数奇偶性","函数周期性","函数连续性","函数凹凸性"]
  67. },
  68. {
  69. "name": "多项式函数" ,
  70. "points": ["常函数","一次函数","二次函数","三次函数","四次函数","五次函数"]
  71. },
  72. {
  73. "name": "基本初等函数" ,
  74. "points": ["幂函数","指数函数","对数函数","三角函数","反三角函数","常数函数"]
  75. },
  76. {
  77. "name": "三角函数" ,
  78. "points":["正弦函数","余弦函数","正切函数","余切函数","正割函数","余割函数","正矢函数","余矢函数","半正矢函数","半余矢函数","外正割函数","外余割函数"]
  79. }
  80. ]
  81. }
  82. */
  83. [ProducesDefaultResponseType]
  84. [HttpPost("upsert")]
  85. [Authorize(Roles = "IES")]
  86. [AuthToken(Roles = "admin", Permissions = "knowledge-upd")]
  87. public async Task<IActionResult> Upsert(Knowledge knowledge)
  88. {
  89. var client = _azureCosmos.GetCosmosClient();
  90. knowledge.code = $"Knowledge-{knowledge.owner}-{knowledge.subjectId}";
  91. StringBuilder sql = new StringBuilder($"select value(c) from c where c.periodId = '{knowledge.periodId}'");
  92. Knowledge old = null;
  93. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<Knowledge>(queryText: sql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{ knowledge.code}") }))
  94. {
  95. old = item;
  96. break;
  97. }
  98. if (old != null)
  99. {
  100. knowledge.id = old.id;
  101. knowledge = await client.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync(knowledge, old.id, new PartitionKey($"{knowledge.code}"));
  102. }
  103. else
  104. {
  105. knowledge.id = Guid.NewGuid().ToString();
  106. knowledge = await client.GetContainer(Constant.TEAMModelOS, "School").CreateItemAsync(knowledge, new PartitionKey($"{knowledge.code}"));
  107. }
  108. var count = new { pcount = knowledge.points != null ? knowledge.points.Count : 0, bcount = knowledge.blocks != null ? knowledge.blocks.Count : 0 };
  109. //处理知识点,知识块计数问题
  110. await _azureRedis.GetRedisClient(8).HashSetAsync($"Knowledge:Count:{knowledge.owner}-{knowledge.subjectId}", knowledge.periodId, count.ToJsonString());
  111. return Ok(knowledge);
  112. }
  113. [ProducesDefaultResponseType]
  114. [HttpPost("upsert-knowledge")]
  115. [Authorize(Roles = "IES")]
  116. [AuthToken(Roles = "admin", Permissions = "knowledge-upd")]
  117. public async Task<IActionResult> UpsertKnowledge(JsonElement json)
  118. {
  119. if (!json.TryGetProperty("school", out JsonElement school)) return BadRequest();
  120. Knowledge knowledge = json.GetProperty("knowledge").ToObject<Knowledge>();
  121. List<OldNew> old_new = null;
  122. if (json.TryGetProperty("old_new", out JsonElement _old_new))
  123. {
  124. old_new = _old_new.ToObject<List<OldNew>>();
  125. }
  126. ValidResult validResult = knowledge.IsValid();
  127. if (!validResult.isVaild)
  128. {
  129. return BadRequest(validResult);
  130. }
  131. var client = _azureCosmos.GetCosmosClient();
  132. knowledge.code = $"Knowledge-{knowledge.owner}-{knowledge.subjectId}";
  133. StringBuilder sql = new StringBuilder($"select value(c) from c where c.periodId = '{knowledge.periodId}'");
  134. Knowledge old = null;
  135. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<Knowledge>(queryText: sql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{ knowledge.code}") }))
  136. {
  137. old = item;
  138. break;
  139. }
  140. if (old != null)
  141. {
  142. knowledge.id = old.id;
  143. knowledge = await client.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync(knowledge, old.id, new PartitionKey($"{knowledge.code}"));
  144. }
  145. else
  146. {
  147. knowledge.id = Guid.NewGuid().ToString();
  148. knowledge = await client.GetContainer(Constant.TEAMModelOS, "School").CreateItemAsync(knowledge, new PartitionKey($"{knowledge.code}"));
  149. }
  150. var count = new { pcount = knowledge.points != null ? knowledge.points.Count : 0, bcount = knowledge.blocks != null ? knowledge.blocks.Count : 0 };
  151. //处理知识点,知识块计数问题
  152. await _azureRedis.GetRedisClient(8).HashSetAsync($"Knowledge:Count:{knowledge.owner}-{knowledge.subjectId}", knowledge.periodId, count.ToJsonString());
  153. if (old_new.IsNotEmpty() && old != null && knowledge != null)
  154. {
  155. var _old = old_new.Select(x => x._old).ToList();
  156. var notinold = _old.Except(old.points);
  157. if (notinold != null && notinold.Count() > 0)
  158. {
  159. return BadRequest($"{notinold.ToJsonString()} 不存在原来的知识点中");
  160. }
  161. var _new = old_new.Select(x => x._new).Where(z => !string.IsNullOrEmpty(z));
  162. if (_new != null && _new.Count() > 0)
  163. {
  164. var notinnew = _new.Except(knowledge.points);
  165. if (notinnew != null && notinnew.Count() > 0)
  166. {
  167. return BadRequest($"{notinnew.ToJsonString()} 不存在新的知识点中");
  168. }
  169. }
  170. _ = _httpTrigger.RequestHttpTrigger(new { old_new = old_new, school = $"{school}" }, _option.Location, "knowledge-change");
  171. }
  172. return Ok(knowledge);
  173. }
  174. /// <summary>
  175. ///
  176. /// "periodId": "ca484aa8-e7b5-4a7c-8ef3-bd9e7b7d4fp2",
  177. /// "subjectId":"ac73f07d-2cc8-4174-85ae-b39cc5b6beef",
  178. /// "owner":"hbcn",
  179. /// "points":["11111"]
  180. /// </summary>
  181. /// <param name="knowledge"></param>
  182. /// <returns></returns>
  183. [ProducesDefaultResponseType]
  184. [HttpPost("item-import")]
  185. [Authorize(Roles = "IES")]
  186. [AuthToken(Roles = "admin", Permissions = "knowledge-upd")]
  187. public async Task<IActionResult> ItemImport(Knowledge dto)
  188. {
  189. var client = _azureCosmos.GetCosmosClient();
  190. dto.code = $"Knowledge-{dto.owner}-{dto.subjectId}";
  191. StringBuilder sql = new StringBuilder($"select value(c) from c where c.periodId = '{dto.periodId}'");
  192. Knowledge knowledge = null;
  193. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<Knowledge>(
  194. queryText: sql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{ dto.code}") }))
  195. {
  196. knowledge = item;
  197. break;
  198. }
  199. if (knowledge != null)
  200. {
  201. var notin = dto.points.Where(x => !knowledge.points.Any(y => y.Equals(x))).ToList();
  202. if (notin.IsNotEmpty())
  203. {
  204. knowledge.points.AddRange(notin);
  205. knowledge = await client.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync(knowledge, knowledge.id, new PartitionKey($"{knowledge.code}"));
  206. }
  207. }
  208. else
  209. {
  210. knowledge = dto;
  211. knowledge.id = Guid.NewGuid().ToString();
  212. knowledge.points = dto.points;
  213. knowledge = await client.GetContainer(Constant.TEAMModelOS, "School").CreateItemAsync(knowledge, new PartitionKey($"{knowledge.code}"));
  214. }
  215. var count = new { pcount = knowledge.points != null ? knowledge.points.Count : 0, bcount = knowledge.blocks != null ? knowledge.blocks.Count : 0 };
  216. //处理知识点,知识块计数问题
  217. await _azureRedis.GetRedisClient(8).HashSetAsync($"Knowledge:Count:{knowledge.owner}-{knowledge.subjectId}", knowledge.periodId, count.ToJsonString());
  218. return Ok(new { knowledge });
  219. }
  220. /// <summary>
  221. /**
  222. {
  223. !"hbcn-ac73f07d-2cc8-4174-85ae-b39cc5b6beef":"ca484aa8-e7b5-4a7c-8ef3-bd9e7b7d4fp2",
  224. }
  225. 单个Item查询一个学校某个科目知识点,知识块数量,如果需要确定某一个学段,则需要加学段。
  226. **/
  227. /// </summary>
  228. /// <param name="request"></param>
  229. /// <returns></returns>
  230. [ProducesDefaultResponseType]
  231. [HttpPost("find-count")]
  232. [AuthToken(Roles = "teacher,admin,student", Permissions = "knowledge-read,knowledge-upd")]
  233. public async Task<IActionResult> FindCount(Dictionary<string, string> request)
  234. {
  235. var (userid, _, _, school) = HttpContext.GetAuthTokenInfo();
  236. List<dynamic> datas = new List<dynamic>();
  237. foreach (var kp in request)
  238. {
  239. var countPoint = 0;
  240. var countBlock = 0;
  241. if (!string.IsNullOrWhiteSpace(kp.Value))
  242. {
  243. var value = await _azureRedis.GetRedisClient(8).HashGetAsync($"Knowledge:Count:{kp.Key}", kp.Value);
  244. if (value != default && !value.IsNullOrEmpty)
  245. {
  246. JsonElement record = value.ToString().ToObject<JsonElement>();
  247. if (record.TryGetProperty("pcount", out JsonElement pcout))
  248. {
  249. int.TryParse($"{pcout}", out countPoint);
  250. }
  251. if (record.TryGetProperty("bcount", out JsonElement bcout))
  252. {
  253. int.TryParse($"{bcout}", out countBlock);
  254. }
  255. if (countPoint == 0)
  256. {
  257. }
  258. }
  259. }
  260. else
  261. {
  262. var values = await _azureRedis.GetRedisClient(8).HashGetAllAsync($"Knowledge:Count:{kp.Key}");
  263. if (values != null)
  264. {
  265. foreach (var value in values)
  266. {
  267. JsonElement record = value.ToString().ToObject<JsonElement>();
  268. if (record.TryGetProperty("pcount", out JsonElement pcout))
  269. {
  270. if (int.TryParse($"{pcout}", out int countP))
  271. {
  272. countPoint = countPoint + countP;
  273. }
  274. }
  275. if (record.TryGetProperty("bcount", out JsonElement bcout))
  276. {
  277. if (int.TryParse($"{bcout}", out int countB))
  278. {
  279. countBlock = countBlock + countB;
  280. }
  281. }
  282. }
  283. }
  284. }
  285. datas.Add(new { key = kp.Key, countPoint, countBlock });
  286. }
  287. return Ok(new { datas });
  288. }
  289. /**
  290. * {
  291. ?"periodId": "ca484aa8-e7b5-4a7c-8ef3-bd9e7b7d4fp2",
  292. !"subjectId": "ac73f07d-2cc8-4174-85ae-b39cc5b6beef",
  293. !"school_code": "hbcn"
  294. }
  295. **/
  296. [ProducesDefaultResponseType]
  297. [HttpPost("find")]
  298. [AuthToken(Roles = "teacher,admin,student", Permissions = "knowledge-read,knowledge-upd")]
  299. public async Task<IActionResult> Find(JsonElement request)
  300. {
  301. var client = _azureCosmos.GetCosmosClient();
  302. request.TryGetProperty("periodId", out JsonElement periodId);
  303. if (!request.TryGetProperty("subjectId", out JsonElement subjectId)) return BadRequest();
  304. if (!request.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
  305. string code = $"Knowledge-{school_code}-{subjectId}";
  306. StringBuilder sql = new StringBuilder($"select value(c) from c");
  307. if (periodId.ValueKind.Equals(JsonValueKind.String))
  308. {
  309. sql.Append($" where c.periodId = '{periodId}'");
  310. }
  311. List<Knowledge> knowledges = new List<Knowledge>();
  312. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<Knowledge>(queryText: sql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{code}") }))
  313. {
  314. knowledges.Add(item);
  315. }
  316. return Ok(knowledges);
  317. }
  318. }
  319. }
  320. using Newtonsoft.Json.Linq;
  321. using System;
  322. using System.Collections.Generic;
  323. using System.ComponentModel;
  324. using System.Net.Http;
  325. using System.Reflection;
  326. using System.Text;
  327. using System.Threading.Tasks;
  328. using System.Security.Cryptography;
  329. using System.Net.Http.Json;
  330. using System.Text.Json;
  331. using System.IO;
  332. using TEAMModelOS.SDK.Extension;
  333. using System.Net;
  334. namespace TEAMModelOS.SDK.DI
  335. {
  336. public class HttpTrigger
  337. {
  338. private readonly HttpClient _httpClient;
  339. public HttpTrigger(HttpClient httpClient)
  340. {
  341. _httpClient = httpClient;
  342. }
  343. // <summary>
  344. /// 请求信息
  345. /// </summary>
  346. /// <param name="robotUrl">釘釘Robot發送Url</param>
  347. /// <param name="secret">加簽密鑰</param>
  348. /// <param name="msg">發送訊息</param>
  349. /// <returns></returns>
  350. public async Task<(int status, string json)> RequestHttpTrigger(object data, string location, string url)
  351. {
  352. var keys = HttpTriggerUrl.HttpTrigger地址.GetDescriptionText().Split(',');
  353. string domain = "";
  354. if (location.Equals("China-Dep"))
  355. {
  356. domain = keys[1];
  357. }
  358. else if (location.Equals("China-Test"))
  359. {
  360. domain = keys[1];
  361. }
  362. else if (location.Equals("China"))
  363. {
  364. domain = keys[2];
  365. }
  366. else if (location.Equals("Global-Dep"))
  367. {
  368. domain = keys[4];
  369. }
  370. else if (location.Equals("Global-Test"))
  371. {
  372. domain = keys[4];
  373. }
  374. else if (location.Equals("Global"))
  375. {
  376. domain = keys[5];
  377. }
  378. string link = domain.Contains("localhost") ? $"http://{domain}/api/{url}" : $"http://{domain}/api/{url}";
  379. HttpContent httpContent = new StringContent(data.ToJsonString());
  380. HttpResponseMessage responseMessage = await _httpClient.PostAsync(link, httpContent);
  381. if (responseMessage.StatusCode == HttpStatusCode.OK)
  382. {
  383. string Content = await responseMessage.Content.ReadAsStringAsync();
  384. Content.ToObject<JsonElement>().TryGetProperty("data", out JsonElement content);
  385. return (200, $"{content}");
  386. }
  387. else
  388. {
  389. string Content = await responseMessage.Content?.ReadAsStringAsync();
  390. return (500, Content);
  391. }
  392. }
  393. }
  394. public enum HttpTriggerUrl
  395. {
  396. [Description("localhost:7071,teammodelosfunction-test.chinacloudsites.cn,teammodelosfunction.chinacloudsites.cn,teammodelosfunction.chinacloudsites.cn,teammodelosfunction.chinacloudsites.cn")]
  397. HttpTrigger地址,
  398. }
  399. }