AClassONEController.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. using Azure.Cosmos;
  2. using Azure.Storage.Blobs.Models;
  3. using Microsoft.AspNetCore.Authorization;
  4. using Microsoft.AspNetCore.Http;
  5. using Microsoft.AspNetCore.Mvc;
  6. using Microsoft.Extensions.Configuration;
  7. using Microsoft.Extensions.Options;
  8. using StackExchange.Redis;
  9. using System;
  10. using System.Collections.Generic;
  11. using System.ComponentModel.DataAnnotations;
  12. using System.Dynamic;
  13. using System.IdentityModel.Tokens.Jwt;
  14. using System.Linq;
  15. using System.Net;
  16. using System.Net.Http;
  17. using System.Text;
  18. using System.Text.Json;
  19. using System.Threading.Tasks;
  20. using TEAMModelOS.Models;
  21. using TEAMModelOS.SDK.DI;
  22. using TEAMModelOS.SDK.Extension;
  23. using TEAMModelOS.SDK.Models;
  24. using TEAMModelOS.SDK.Services;
  25. using static TEAMModelOS.SDK.Services.BlobService;
  26. namespace TEAMModelOS.Controllers
  27. {
  28. /// <summary>
  29. ///
  30. ///
  31. /*
  32. AClassONE
  33. ee6a461a-3b40-4f70-8842-cf275d1e15ee
  34. px-njcS.jL1P7g0-kW:EAkO2Ve7[9k1x
  35. 8124850f-03d8-4949-9355-ed0d0709189e
  36. l2aR-bk2LfCGt7OjSwRi:qZqfXXhL4:=
  37. */
  38. /// </summary>
  39. [Route("aclassone")]
  40. [ApiController]
  41. public class AClassONEController : ControllerBase
  42. {
  43. private readonly IHttpClientFactory _httpClient;
  44. private readonly AzureStorageFactory _azureStorage;
  45. private readonly AzureRedisFactory _azureRedis;
  46. private readonly AzureCosmosFactory _azureCosmos;
  47. private readonly DingDing _dingDing;
  48. private readonly Option _option;
  49. private readonly SnowflakeId _snowflakeId;
  50. private readonly IConfiguration _configuration;
  51. public AClassONEController(
  52. AzureStorageFactory azureStorage,
  53. AzureRedisFactory azureRedis,
  54. AzureCosmosFactory azureCosmos,
  55. DingDing dingDing,
  56. SnowflakeId snowflakeId,
  57. IOptionsSnapshot<Option> option, IHttpClientFactory httpClient, IConfiguration configuration)
  58. {
  59. _azureStorage = azureStorage;
  60. _azureRedis = azureRedis;
  61. _azureCosmos = azureCosmos;
  62. _dingDing = dingDing;
  63. _snowflakeId = snowflakeId;
  64. _option = option?.Value;
  65. _httpClient = httpClient;
  66. _configuration = configuration;
  67. }
  68. /// <summary>
  69. /// js_code获取小程序用户信息
  70. /// </summary>
  71. /// <param name="json"></param>
  72. /// <returns></returns>
  73. [ProducesDefaultResponseType]
  74. [HttpPost("get-miniapp-userinfo")]
  75. //[Authorize(Roles = "AClassONE")]
  76. public async Task<IActionResult> GetMiniAPPOpenid(JsonElement json)
  77. {
  78. // string Content = await responseMessage.Content.ReadAsStringAsync();
  79. var location = _option.Location;
  80. var clientID = _configuration.GetValue<string>("HaBookAuth:AClassONE:clientID");
  81. var clientSecret = _configuration.GetValue<string>("HaBookAuth:AClassONE:clientSecret");
  82. var wxappid = _configuration.GetValue<string>("HaBookAuth:WXMiniAPP:appid");
  83. var wxsecret = _configuration.GetValue<string>("HaBookAuth:WXMiniAPP:secret");
  84. if (location.Contains("China"))
  85. {
  86. location = "China";
  87. }
  88. else if (location.Contains("Global"))
  89. {
  90. location = "Global";
  91. }
  92. var token = await CoreTokenExtensions.CreateAccessToken(clientID, clientSecret, location);
  93. //return Ok(new { token = new { token.TokenType,token.AccessToken } });
  94. if (!json.TryGetProperty("js_code", out JsonElement js_code)) return BadRequest("js_code is null");
  95. string url = $"https://api.weixin.qq.com/sns/jscode2session?appid={wxappid}&secret={wxsecret}&js_code={js_code}&grant_type=authorization_code";
  96. HttpResponseMessage responseMessage = await _httpClient.CreateClient().GetAsync(url);
  97. if (responseMessage.StatusCode == HttpStatusCode.OK)
  98. {
  99. JsonDocument document = JsonDocument.Parse(responseMessage.Content.ReadAsStream());
  100. return Ok(new { miniappData = document, token = new { token.TokenType, token.AccessToken } });
  101. }
  102. else
  103. {
  104. string Content = await responseMessage.Content?.ReadAsStringAsync();
  105. return BadRequest(Content);
  106. }
  107. }
  108. /// <summary>
  109. /// 根据家长手机号获取监护学生的信息
  110. /// </summary>
  111. /// <param name="json"></param>
  112. /// <returns></returns>
  113. [ProducesDefaultResponseType]
  114. [HttpPost("get-students-phone")]
  115. #if !DEBUG
  116. [Authorize(Roles = "AClassONE")]
  117. #endif
  118. public async Task<IActionResult> GetStudentsByPhone(JsonElement json)
  119. {
  120. try
  121. {
  122. if (!json.TryGetProperty("mobile", out JsonElement _mobile)) return BadRequest("mobile is null");
  123. json.TryGetProperty("name", out JsonElement _name);
  124. json.TryGetProperty("picture", out JsonElement _picture);
  125. json.TryGetProperty("query", out JsonElement _query);
  126. string sql = $"select value c from c where c.mobile='{_mobile}'";
  127. List<Guardian> guardians = new List<Guardian>();
  128. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).
  129. GetItemQueryIterator<Guardian>(queryText: sql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey("Base-Guardian") }))
  130. {
  131. guardians.Add(item);
  132. }
  133. //没有找到监护人信息时,尝试跨分区搜索,但是不建议。
  134. if (!guardians.Any() || _query.ValueKind.Equals(JsonValueKind.True))
  135. {
  136. List<Student> students = new List<Student>();
  137. string stuSql = $"select distinct value c from c join g in c.guardians where g.mobile='{_mobile}'";
  138. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).
  139. GetItemQueryIterator<Student>(queryText: stuSql, requestOptions: new QueryRequestOptions { }))
  140. {
  141. students.Add(item);
  142. }
  143. if (students.Any())
  144. {
  145. string guardianName = "";
  146. string mobile = $"{_mobile}";
  147. List<GuardianStudent> guardianStudents = new List<GuardianStudent>();
  148. students.ForEach(x =>
  149. {
  150. var studentGuardian = x.guardians.Find(x => !string.IsNullOrWhiteSpace(x.mobile) && x.mobile.Equals(mobile));
  151. if (studentGuardian != null)
  152. {
  153. guardianName = studentGuardian.name;
  154. guardianStudents.Add(new GuardianStudent { type = 2, id = x.id, code = x.schoolId, name = x.name, picture = x.picture });
  155. }
  156. });
  157. if (guardians.Any())
  158. {
  159. guardians.First().students.AddRange(guardianStudents);
  160. }
  161. else
  162. {
  163. Guardian guardian = new Guardian() { id = Guid.NewGuid().ToString(), name = guardianName, mobile = mobile, students = guardianStudents, code = "Base-Guardian", pk = "Guardian" };
  164. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).CreateItemAsync(guardian, new PartitionKey("Base-Guardian"));
  165. guardians.Add(guardian);
  166. }
  167. }
  168. }
  169. if (guardians.Any())
  170. {
  171. var students = guardians.SelectMany(x => x.students).DistinctBy(x => $"{x.type}-{x.id}{x.code}");
  172. var first = guardians.First();
  173. first.students = students.ToList();
  174. if (guardians.Count > 1)
  175. {
  176. //合并,并移除多余的绑定的手机号。
  177. guardians.Remove(first);
  178. if (guardians.Any() && !guardians.Select(x => x.id).Contains(first.id))
  179. {
  180. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).DeleteItemsStreamAsync(guardians.Select(x => x.id).ToList(), "Base-Guardian");
  181. }
  182. }
  183. first.nickname = !string.IsNullOrWhiteSpace($"{_name}") ? $"{_name}" : first.name;
  184. first.picture = !string.IsNullOrWhiteSpace($"{_picture}") ? $"{_picture}" : first.picture;
  185. await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).ReplaceItemAsync(first, first.id, new PartitionKey(first.code));
  186. var schoolcodes = first.students.Where(s => !string.IsNullOrWhiteSpace(s.code)).Select(x => x.code);
  187. List<School> idSchools = new List<School>();
  188. if (schoolcodes.Any())
  189. {
  190. string sqlschool = $"select c.id,c.name,c.picture,c.period from c where c.id in ({string.Join(",", schoolcodes.Select(s => $"'{s}'"))})";
  191. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).
  192. GetItemQueryIterator<School>(queryText: sqlschool, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey("Base") }))
  193. {
  194. idSchools.Add(item);
  195. }
  196. }
  197. var stus = first.students.GroupBy(x => x.code).Select(x => new { x.Key, list = x.ToList() });
  198. List<Student> studentes = new List<Student>();
  199. List<Class> classes = new List<Class>();
  200. foreach (var stu in stus)
  201. {
  202. HashSet<string> classIds = new HashSet<string>();
  203. string sqlStudent = $"select c.name ,c.periodId ,c.id ,c.schoolId, c.picture, c.classId, c.gender, c.year from c where c.id in ({string.Join(",", stu.list.Select(s => $"'{s.id}'"))})";
  204. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).
  205. GetItemQueryIterator<Student>(queryText: sqlStudent, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"Base-{stu.Key}") }))
  206. {
  207. studentes.Add(item);
  208. classIds.Add(item.classId);
  209. }
  210. string sqlClassIds = $" select c.name ,c.periodId ,c.id ,c.school, c.teacher,c.year from c where c.id in ({string.Join(",", classIds.Select(s => $"'{s}'"))})";
  211. await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).
  212. GetItemQueryIterator<Class>(queryText: sqlClassIds, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"Class-{stu.Key}") }))
  213. {
  214. classes.Add(item);
  215. }
  216. }
  217. List<dynamic> stuData = new List<dynamic>();
  218. first.students.ForEach(x =>
  219. {
  220. var stu = studentes.Find(s => s.id.Equals(x.id) && s.schoolId.Equals(x.code));
  221. var school = idSchools.Find(s => s.id.Equals(x.code));
  222. string periodName = "";
  223. if (school != null && stu != null && !string.IsNullOrWhiteSpace(stu.periodId))
  224. {
  225. var period = school.period.Find(p => p != null && p.id.Equals(stu.periodId));
  226. periodName = period?.name;
  227. }
  228. string className = "";
  229. string teacherTmdid = "";
  230. string teacherName = "";
  231. int? classYear = 0;
  232. if (stu != null && !string.IsNullOrWhiteSpace(stu.classId))
  233. {
  234. var clazz = classes.Find(p => p != null && p.id.Equals(stu.classId));
  235. className = clazz?.name;
  236. teacherTmdid = clazz?.teacher?.id;
  237. teacherName = clazz?.teacher?.name;
  238. classYear = clazz?.year;
  239. }
  240. stuData.Add(new
  241. {
  242. x.id,
  243. schoolId = x.code,
  244. stu.name,
  245. stu.periodId,
  246. stu.picture,
  247. stu.classId,
  248. stu.gender,
  249. x.type,
  250. x.relation,
  251. stuYear = stu.year,
  252. schoolName = school.name,
  253. schoolPicture = school.picture,
  254. periodName,
  255. className,
  256. teacherTmdid,
  257. teacherName,
  258. classYear
  259. });
  260. });
  261. return Ok(new { guardian = new { first.id, first.name, first.picture, first.nickname, first.mobile, students = stuData } });
  262. }
  263. else
  264. {
  265. return Ok(new { error = 1, msg = "暂未找到学生信息" });
  266. }
  267. }
  268. catch (Exception ex)
  269. {
  270. return BadRequest("500错误");
  271. }
  272. }
  273. /// <summary>
  274. /// 查询考试信息
  275. /// </summary>
  276. /// <param name="request"></param>
  277. /// <returns></returns>
  278. [ProducesDefaultResponseType]
  279. //[Authorize(Roles = "AClassONE")]
  280. [HttpPost("find-activity")]
  281. public async Task<IActionResult> FindExam(JsonElement request)
  282. {
  283. try
  284. {
  285. //var client = _azureCosmos.GetCosmosClient();
  286. var (id, name, pic, school) = HttpContext.GetAuthTokenInfo();
  287. (List<StuActivity> datas, string continuationToken) = await ActivityStudentService.FindActivity(request, id, school, _azureCosmos, _azureRedis);
  288. return Ok(new { datas, continuationToken });
  289. }
  290. catch (Exception e)
  291. {
  292. await _dingDing.SendBotMsg($"OS,{_option.Location},exam/find-activity()\n{e.Message}\n{e.StackTrace}", GroupNames.醍摩豆服務運維群組);
  293. return BadRequest("500错误");
  294. }
  295. }
  296. }
  297. }