HiScanController.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. using Microsoft.Azure.Cosmos;
  2. using Microsoft.AspNetCore.Http;
  3. using Microsoft.AspNetCore.Mvc;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.IdentityModel.Tokens.Jwt;
  7. using System.Linq;
  8. using System.Text;
  9. using System.Text.Json;
  10. using System.Threading.Tasks;
  11. using TEAMModelOS.Models.Dto;
  12. using TEAMModelOS.SDK.Models;
  13. using TEAMModelOS.SDK;
  14. using TEAMModelOS.SDK.DI;
  15. using TEAMModelOS.SDK.DI;
  16. using TEAMModelOS.SDK.Extension;
  17. using TEAMModelOS.SDK.Helper.Common.StringHelper;
  18. using TEAMModelOS.Models;
  19. using Microsoft.Extensions.Options;
  20. using TEAMModelOS.SDK.Models.Cosmos;
  21. using Microsoft.AspNetCore.Authorization;
  22. using TEAMModelOS.Filter;
  23. using StackExchange.Redis;
  24. using TEAMModelOS.SDK.Models.Cosmos.Inner;
  25. using System.IO;
  26. using System.Dynamic;
  27. using Azure.Storage.Blobs.Models;
  28. using Azure.Storage.Sas;
  29. using Lib.AspNetCore.ServerSentEvents;
  30. using TEAMModelOS.SDK.Models.Cosmos;
  31. using TEAMModelOS.SDK.Models.Service;
  32. namespace TEAMModelOS.Controllers.Core
  33. {
  34. [ProducesResponseType(StatusCodes.Status200OK)]
  35. [ProducesResponseType(StatusCodes.Status400BadRequest)]
  36. [Authorize(Roles = "HiTool,HiTools")]
  37. [Route("hiscan")]
  38. [ApiController]
  39. public class HiScanController : ControllerBase
  40. {
  41. private readonly AzureRedisFactory _azureRedis;
  42. private readonly AzureCosmosFactory _azureCosmos;
  43. private readonly SnowflakeId _snowflakeId;
  44. private readonly AzureServiceBusFactory _serviceBus;
  45. private readonly DingDing _dingDing;
  46. private readonly Option _option;
  47. private readonly AzureStorageFactory _azureStorage;
  48. // private readonly ServerSentEventsService _sse;
  49. private readonly CoreAPIHttpService _coreAPIHttpService;
  50. private readonly IPSearcher _searcher;
  51. private readonly HttpTrigger _httpTrigger;
  52. public HiScanController(CoreAPIHttpService coreAPIHttpService, AzureCosmosFactory azureCosmos, AzureServiceBusFactory serviceBus, SnowflakeId snowflakeId, DingDing dingDing, IOptionsSnapshot<Option> option,
  53. AzureRedisFactory azureRedis, AzureStorageFactory azureStorage, IPSearcher searcher, HttpTrigger httpTrigger//, ServerSentEventsService sse
  54. )
  55. {
  56. _azureCosmos = azureCosmos;
  57. _serviceBus = serviceBus;
  58. _snowflakeId = snowflakeId;
  59. _dingDing = dingDing;
  60. _option = option?.Value;
  61. _azureRedis = azureRedis;
  62. _coreAPIHttpService = coreAPIHttpService;
  63. _azureStorage = azureStorage;
  64. _searcher = searcher;
  65. _httpTrigger = httpTrigger;
  66. //_sse = sse;
  67. }
  68. ///<summary>
  69. ///查询教师的阅卷任务列表
  70. /// </summary>
  71. /// <data>
  72. /// ! "code":"tmdid"
  73. /// </data>
  74. /// <param name="request"></param>
  75. /// <returns></returns>
  76. [ProducesDefaultResponseType]
  77. [HttpPost("get-schoolinfo")]
  78. // [AuthToken(Roles = "teacher,admin")]
  79. public async Task<IActionResult> GetSchoolinfo(JsonElement request)
  80. {
  81. List<dynamic> schools = new List<dynamic>();
  82. (string ip, string region) = await LoginService.LoginIp(HttpContext, _searcher);
  83. if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
  84. var client = _azureCosmos.GetCosmosClient();
  85. try
  86. {
  87. Teacher response = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<Teacher>($"{id}", new PartitionKey("Base"));
  88. string name = response.name;
  89. string picture = response.picture;
  90. foreach (var obj in response.schools)
  91. {
  92. string statusNow = obj.status;
  93. //正式加入才会有
  94. if (statusNow.Equals("join"))
  95. {
  96. try
  97. {
  98. //dynamic schoolExtobj = new ExpandoObject();
  99. School schoolJson = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>($"{obj.schoolId}", new PartitionKey("Base"));
  100. var schoolId = obj.schoolId;
  101. var schoolName = schoolJson.name;
  102. var schoolPicture = schoolJson.picture;
  103. //检查学校购买的模组是否包含阅卷模组,暂不检查
  104. //int count = 0;
  105. //string sql = $" SELECT value(count(product)) FROM c join product in c.service.product where c.id ='{schoolId}' and c.pk='Product' and product.prodCode='YMPCVCIM' ";
  106. //await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIteratorSql<int>(sql, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Product") }))
  107. //{
  108. // count = item;
  109. //}
  110. //if (count > 0)
  111. //{
  112. // schools.Add(new { name = $"{schoolName}", picture = $"{schoolPicture}", id = $"{schoolId}" });
  113. //}
  114. schools.Add(new { name = $"{schoolName}", picture = $"{schoolPicture}", id = $"{schoolId}" });
  115. }
  116. catch { continue; }
  117. }
  118. }
  119. //用户在线记录
  120. //try
  121. //{
  122. // _ = _httpTrigger.RequestHttpTrigger(new { school = response.defaultSchool, scope = Constant.ScopeTeacher, id = $"{id}", ip = ip, expire = 1 }, _option.Location, "online-record");
  123. //}
  124. //catch { }
  125. var (tblob_uri, tblob_sas) = _azureStorage.GetBlobContainerSAS($"{id}", BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Delete);
  126. return Ok(new { schools, teacher = new { name, picture, id, bloburl = tblob_uri, blobsas = tblob_sas } });
  127. }
  128. catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
  129. {
  130. return Ok(new {error= 1,msg="账号未再IES5使用"});
  131. }
  132. catch (Exception ex) {
  133. return BadRequest();
  134. }
  135. }
  136. ///<summary>
  137. ///查询教师的阅卷任务列表
  138. /// </summary>
  139. /// <data>
  140. /// ! "code":"tmdid"
  141. /// </data>
  142. /// <param name="request"></param>
  143. /// <returns></returns>
  144. [ProducesDefaultResponseType]
  145. [HttpPost("get-examinfo")]
  146. // [AuthToken(Roles = "teacher,admin")]
  147. public async Task<IActionResult> GetExaminfo(JsonElement request)
  148. {
  149. try
  150. {
  151. List<SheetConfig> configs = new List<SheetConfig>();
  152. HashSet<string> classesSet = new HashSet<string>();
  153. List<ExamRcd> sexamRcds = new List<ExamRcd>();
  154. List<ExamRcd> psexamRcds = new List<ExamRcd>();
  155. List<ExamRcd> ppexamRcds = new List<ExamRcd>();
  156. List<ExamRcd> pexamRcds = new List<ExamRcd>();
  157. if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
  158. if (!request.TryGetProperty("schoolId", out JsonElement _schoolId)) return BadRequest();
  159. var client = _azureCosmos.GetCosmosClient();
  160. School school = null;
  161. try
  162. {
  163. school = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>($"{_schoolId}", new PartitionKey("Base"));
  164. }
  165. catch (CosmosException ex)
  166. {
  167. if (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
  168. {
  169. school = null;
  170. }
  171. }
  172. var response = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemStreamAsync($"{id}", new PartitionKey("Base"));
  173. if (school != null)
  174. {
  175. //检查学校购买的模组是否包含阅卷模组
  176. int count = 0;
  177. string sql = $" SELECT value(count(product)) FROM c join product in c.service.product where c.id ='{_schoolId}' and c.pk='Product' and product.prodCode='YMPCVCIM' ";
  178. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIteratorSql<int>(sql, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Product") }))
  179. {
  180. count = item;
  181. }
  182. if (count > 0)
  183. {
  184. //获取学校线下阅卷评测
  185. sexamRcds = await GetExam("school", $"{_schoolId}", $"{_schoolId}", client, configs, classesSet);
  186. }
  187. if (response.StatusCode==System.Net.HttpStatusCode.OK)
  188. {
  189. //获取scope=school
  190. psexamRcds = await GetExam("school", $"{_schoolId}", $"{id}", client, configs, classesSet);
  191. if (psexamRcds.IsNotEmpty())
  192. {
  193. pexamRcds.AddRange(psexamRcds);
  194. }
  195. }
  196. }
  197. if (response.StatusCode==System.Net.HttpStatusCode.OK)
  198. {
  199. //获取scope=private
  200. ppexamRcds = await GetExam("private", null, $"{id}", client, configs, classesSet);
  201. if (ppexamRcds.IsNotEmpty())
  202. {
  203. pexamRcds.AddRange(ppexamRcds);
  204. }
  205. }
  206. (List<RMember> tmdIds, List<RGroupList> classInfo) = await GroupListService.GetMemberByListids(_coreAPIHttpService, client, _dingDing, classesSet.ToList(), $"{_schoolId}");
  207. /*var addStudentsCls = tmdIds.FindAll(x => x.type == 2);
  208. var addTmdidsCls = tmdIds.FindAll(x => x.type == 1);*/
  209. List<SheetConfig> configsN = new List<SheetConfig>();
  210. foreach (var config in configs)
  211. {
  212. if (config.scope.Equals("school"))
  213. {
  214. try
  215. {
  216. SheetConfig con = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<SheetConfig>(config.id, new PartitionKey(config.code));
  217. configsN.Add(con);
  218. }
  219. catch (CosmosException ex) { }
  220. }
  221. else
  222. {
  223. try
  224. {
  225. SheetConfig con = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<SheetConfig>(config.id, new PartitionKey(config.code));
  226. configsN.Add(con);
  227. }
  228. catch (CosmosException ex) { }
  229. }
  230. }
  231. //处理学校发布的评测
  232. if (sexamRcds.IsNotEmpty())
  233. {
  234. sexamRcds.SelectMany(y => y.classes).ToList().ForEach(z => {
  235. var a = classInfo.Where(m => m.id.Equals(z.id)).FirstOrDefault();
  236. if (a != null)
  237. {
  238. z.name = a.name;
  239. z.members = a.members;
  240. //z.tmdInfos = a.members.FindAll(x => x.type == 1);
  241. }
  242. });
  243. sexamRcds.SelectMany(y => y.papers).ToList().ForEach(z => {
  244. if (z.sheet != null)
  245. {
  246. var a = configsN.Where(m => m.id == z.sheet.id).FirstOrDefault();
  247. if (a != null)
  248. {
  249. z.sheet = a;
  250. }
  251. }
  252. });
  253. }
  254. //处理教师发布的个人班级评测和学校班级评测
  255. if (pexamRcds.IsNotEmpty())
  256. {
  257. pexamRcds.SelectMany(y => y.classes).ToList().ForEach(z => {
  258. var a = classInfo.Where(m => m.id == z.id).FirstOrDefault();
  259. if (a != null)
  260. {
  261. z.name = a.name;
  262. z.members = a.members;
  263. // z.members = a.tmdInfos;
  264. }
  265. });
  266. pexamRcds.SelectMany(y => y.papers).ToList().ForEach(z => {
  267. if (z.sheet != null)
  268. {
  269. var a = configsN.Where(m => m.id == z.sheet.id).FirstOrDefault();
  270. if (a != null)
  271. {
  272. z.sheet = a;
  273. }
  274. }
  275. });
  276. }
  277. string teacherBlobSas = null;
  278. string teacherBlobUrl = null;
  279. string schoolBlobSas = null;
  280. string schoolBlobUrl = null;
  281. if (ppexamRcds.IsNotEmpty())
  282. {
  283. var (tblob_uri, tblob_sas) = _azureStorage.GetBlobContainerSAS($"{id}", BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List);
  284. teacherBlobUrl = tblob_uri;
  285. teacherBlobSas = tblob_sas;
  286. }
  287. if (psexamRcds.IsNotEmpty() || sexamRcds.IsNotEmpty())
  288. {
  289. var (sblob_uri, sblob_sas) = _azureStorage.GetBlobContainerSAS(school.id, BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Write);
  290. schoolBlobUrl = sblob_uri;
  291. schoolBlobSas = sblob_sas;
  292. }
  293. return Ok(new { teacherBlobSas, teacherBlobUrl, schoolBlobSas, schoolBlobUrl, school = sexamRcds.IsNotEmpty() ? sexamRcds : null, teacher = pexamRcds.IsNotEmpty() ? pexamRcds : null });
  294. }
  295. catch (Exception ex)
  296. {
  297. await _dingDing.SendBotMsg($"IES5,{_option.Location},hiscan/verify-qrcode()\n{ex.Message}\n{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
  298. return BadRequest();
  299. }
  300. }
  301. private async Task<List<ExamRcd>> GetExam(string scope, string school, string code, CosmosClient client, List<SheetConfig> sheet, HashSet<string> classesSet)
  302. {
  303. List<ExamRcd> examRcds = new List<ExamRcd>();
  304. int i = 1;
  305. StringBuilder sql = new StringBuilder($"SELECT * FROM c where (c.status<>404 or IS_DEFINED(c.status) = false ) and (c.progress='going' or c.progress='finish') and c.scope='{scope}' ");
  306. if (!string.IsNullOrEmpty(school))
  307. {
  308. sql.Append($" and c.school='{school}' ");
  309. }
  310. //await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIteratorSql<Correct>(queryText: "SELECT * FROM c where c.source='2' and c.progress='going' order by c.createTime ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Correct-{code}") }))
  311. await foreach (var exam in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIteratorSql<ExamInfo>(queryText: sql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Exam-{code}") }))
  312. {
  313. List<RGroupList> classes = new List<RGroupList>();
  314. if (exam.classes.IsNotEmpty())
  315. {
  316. exam.classes.ForEach(x => { classes.Add(new RGroupList { id = x }); classesSet.Add(x); });
  317. }
  318. if (exam.stuLists.IsNotEmpty())
  319. {
  320. exam.stuLists.ForEach(x => { classes.Add(new RGroupList { id = x }); classesSet.Add(x); });
  321. }
  322. List<PaperRcd> dys = new List<PaperRcd>();
  323. foreach (var pap in exam.papers)
  324. {
  325. if (!string.IsNullOrEmpty(pap.sheet))
  326. {
  327. if (exam.scope.Equals("school"))
  328. {
  329. SheetConfig config = new SheetConfig { id = pap.sheet, no = pap.sheetNo, scope = exam.scope, mode = pap.mode, code = $"SheetConfig-{exam.school}" };
  330. dys.Add(new PaperRcd { name = pap.name, answers = pap.answers, point = pap.point, sheet = config });
  331. sheet.Add(config);
  332. }
  333. else
  334. {
  335. SheetConfig config = new SheetConfig { id = pap.sheet, no = pap.sheetNo, scope = exam.scope,mode=pap.mode , code = $"SheetConfig-{code}" };
  336. dys.Add(new PaperRcd { name = pap.name, answers = pap.answers, point = pap.point, sheet = config });
  337. sheet.Add(config);
  338. }
  339. }
  340. else
  341. {
  342. dys.Add(new PaperRcd { name = pap.name, answers = pap.answers, point = pap.point, sheet = null });
  343. }
  344. }
  345. examRcds.Add(new ExamRcd
  346. {
  347. id = exam.id,
  348. name = exam.name,
  349. startTime = exam.startTime,
  350. endTime = exam.endTime,
  351. period = exam.period,
  352. grades = exam.grades,
  353. subjects = exam.subjects,
  354. papers = dys,
  355. classes = classes,
  356. scope = exam.scope
  357. });
  358. }
  359. return examRcds;
  360. }
  361. ///<summary>
  362. ///查询教师的阅卷任务列表
  363. /// </summary>
  364. /// <data>
  365. /// ! "code":"tmdid"
  366. /// </data>
  367. /// <param name="request"></param>
  368. /// <returns></returns>
  369. [ProducesDefaultResponseType]
  370. [HttpPost("get-exam-by-sheet")]
  371. // [AuthToken(Roles = "teacher,admin")]
  372. public async Task<IActionResult> GetExamBySheet(JsonElement request)
  373. {
  374. try
  375. {
  376. HashSet<string> classesSet = new HashSet<string>();
  377. ExamSheetData examData = null;
  378. if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
  379. if (!request.TryGetProperty("schoolId", out JsonElement _schoolId)) return BadRequest();
  380. if (!request.TryGetProperty("sheetNo", out JsonElement _sheetNo)) return BadRequest();
  381. string _owner = (request.TryGetProperty("owner", out JsonElement _ownerJ)) ? _ownerJ.ToString() : string.Empty;
  382. string _scope = (request.TryGetProperty("scope", out JsonElement _scopeJ)) ? _scopeJ.ToString() : string.Empty;
  383. if (string.IsNullOrEmpty(_owner) && string.IsNullOrEmpty(_scope)) return BadRequest();
  384. else if (string.IsNullOrEmpty(_owner) && !string.IsNullOrEmpty(_scope)) _owner = _scope;
  385. var client = _azureCosmos.GetCosmosClient();
  386. School school = null;
  387. school = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>($"{_schoolId}", new PartitionKey("Base"));
  388. if (school == null) return BadRequest();
  389. if ($"{_owner}".Equals("school", StringComparison.OrdinalIgnoreCase))
  390. {
  391. examData = await GetExamBySheet($"{_owner}", $"{_schoolId}", $"{_schoolId}", client, classesSet, $"{_sheetNo}");
  392. }
  393. else {
  394. var response = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemStreamAsync($"{id}", new PartitionKey("Base"));
  395. examData = await GetExamBySheet($"{_owner}", null, $"{id}", client, classesSet, $"{_sheetNo}");
  396. if (examData == null && string.IsNullOrEmpty($"{_schoolId}")) {
  397. examData = await GetExamBySheet($"{_owner}", $"{_schoolId}", $"{id}", client, classesSet, $"{_sheetNo}");
  398. }
  399. }
  400. (List<RMember> tmdIds, List<RGroupList> classInfo) = await GroupListService.GetMemberByListids(_coreAPIHttpService, client, _dingDing, classesSet.ToList(), $"{_schoolId}");
  401. List<SheetConfig> configsN = new List<SheetConfig>();
  402. if (examData.sheet != null) {
  403. if (examData.sheet.scope.Equals("school"))
  404. {
  405. ResponseMessage azure = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(examData.sheet.id, new PartitionKey(examData.sheet.code));
  406. if (azure.StatusCode ==System.Net.HttpStatusCode.OK && azure.Content!=null )
  407. {
  408. SheetConfig config = JsonDocument.Parse(azure.Content).RootElement.Deserialize<SheetConfig>();
  409. if (config != null)
  410. {
  411. configsN.Add(config);
  412. }
  413. }
  414. }
  415. else
  416. {
  417. ResponseMessage azure = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemStreamAsync(examData.sheet.id, new PartitionKey(examData.sheet.code));
  418. if (azure.StatusCode ==System.Net.HttpStatusCode.OK && azure.Content != null)
  419. {
  420. SheetConfig config = JsonDocument.Parse(azure.Content).RootElement.Deserialize<SheetConfig>();
  421. if (config != null)
  422. {
  423. configsN.Add(config);
  424. }
  425. }
  426. }
  427. }
  428. if (examData != null)
  429. {
  430. examData.classes.ForEach(z => {
  431. var a = classInfo.Where(m => m.id.Equals(z.id)).FirstOrDefault();
  432. if (a != null)
  433. {
  434. z.no=a.no;
  435. z.creatorId=a.creatorId;
  436. z.year=a.year;
  437. z.expire=a.expire;
  438. z.tcount=a.tcount;
  439. z.scount=a.scount;
  440. z.periodId = a.periodId;
  441. z.scope = a.scope;
  442. z.school = a.school;
  443. z.code = a.code;
  444. z.name = a.name;
  445. z.members = a.members;
  446. //z.tmdInfos = a.tmdInfos;
  447. }
  448. });
  449. if (examData.sheet!=null) {
  450. var a = configsN.Where(m => m.id == examData.sheet.id && m.scope.Equals(examData.sheet.scope)).FirstOrDefault();
  451. if (a != null)
  452. {
  453. examData.sheet = a;
  454. }
  455. }
  456. }
  457. string blobSas = null;
  458. string blobUrl = null;
  459. ExamSheetData exam = null;
  460. if (examData.sheet.scope.Equals("school", StringComparison.OrdinalIgnoreCase))
  461. {
  462. if (examData != null)
  463. {
  464. var (sblob_uri, sblob_sas) = _azureStorage.GetBlobContainerSAS(school.id, BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Write);
  465. blobUrl = sblob_uri;
  466. blobSas = sblob_sas;
  467. exam = examData;
  468. }
  469. }
  470. else {
  471. if (examData != null)
  472. {
  473. var (tblob_uri, tblob_sas) = _azureStorage.GetBlobContainerSAS($"{id}", BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List);
  474. blobUrl = tblob_uri;
  475. blobSas = tblob_sas;
  476. exam = examData;
  477. }
  478. }
  479. return Ok(new { blobUrl, blobSas, exam});
  480. }
  481. catch (Exception ex)
  482. {
  483. await _dingDing.SendBotMsg($"IES5,{_option.Location},get-exam-by-sheet\n{ex.Message}\n{ex.StackTrace}{request.ToJsonString()}", GroupNames.醍摩豆服務運維群組);
  484. return BadRequest();
  485. }
  486. }
  487. private async Task<ExamSheetData> GetExamBySheet(string owner, string school, string code, CosmosClient client,HashSet<string> classesSet, string sheetNo)
  488. {
  489. ExamSheetData examRcds = null;
  490. StringBuilder sql = new StringBuilder($"SELECT value(c) FROM c join papers in c.papers where (c.status<>404 or IS_DEFINED(c.status) = false ) and c.owner='{owner}' and papers.sheetNo='{sheetNo}' ");
  491. if (!string.IsNullOrEmpty(school))
  492. {
  493. sql.Append($" and c.school='{school}' ");
  494. }
  495. //await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIteratorSql<Correct>(queryText: "SELECT * FROM c where c.source='2' and c.progress='going' order by c.createTime ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Correct-{code}") }))
  496. await foreach (var exam in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIteratorSql<ExamInfo>(queryText: sql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Exam-{code}") }))
  497. {
  498. List<RGroupList> classes = new List<RGroupList>();
  499. if (exam.classes.IsNotEmpty())
  500. {
  501. exam.classes.ForEach(x => { classes.Add(new RGroupList { id = x }); classesSet.Add(x); });
  502. }
  503. if (exam.stuLists.IsNotEmpty())
  504. {
  505. exam.stuLists.ForEach(x => { classes.Add(new RGroupList { id = x }); classesSet.Add(x); });
  506. }
  507. PaperRcdData paper = null;
  508. ExamSubjectData subjectData = null;
  509. PaperSimple pap = exam.papers.Find(x => x.sheetNo == sheetNo);
  510. if (pap != null) {
  511. int index = exam.papers.FindIndex(x => x.sheetNo == sheetNo);
  512. ExamSubject subject = exam.subjects[index];
  513. subjectData = new ExamSubjectData { id = subject.id, name = subject.name };
  514. }
  515. SheetConfig config = null;
  516. if (!string.IsNullOrEmpty(pap.sheet))
  517. {
  518. if (exam.scope.Equals("school"))
  519. {
  520. config = new SheetConfig { id = pap.sheet, scope = exam.scope, mode = pap.mode, no = pap.sheetNo, code = $"SheetConfig-{exam.school}" };
  521. paper = new PaperRcdData { name = pap.name, answers = pap.answers, point = pap.point };
  522. }
  523. else
  524. {
  525. config = new SheetConfig { id = pap.sheet, scope = exam.scope, mode = pap.mode,no=pap.sheetNo, code = $"SheetConfig-{code}" };
  526. paper = new PaperRcdData { name = pap.name, answers = pap.answers, point = pap.point };
  527. }
  528. }
  529. else
  530. {
  531. paper = new PaperRcdData { name = pap.name, answers = pap.answers, point = pap.point, };
  532. }
  533. examRcds = new ExamSheetData
  534. {
  535. code = exam.code.Replace("Exam-", ""),
  536. id = exam.id,
  537. name = exam.name,
  538. startTime = exam.startTime,
  539. endTime = exam.endTime,
  540. period = exam.period,
  541. grades = exam.grades,
  542. subject = subjectData,
  543. paper = paper,
  544. classes = classes,
  545. scope = exam.scope,
  546. sheet = config
  547. };
  548. }
  549. return examRcds;
  550. }
  551. }
  552. public record PaperRcdData
  553. {
  554. public string name { get; set; }
  555. public List<List<string>> answers { get; set; } = new List<List<string>>();
  556. public List<double> point { get; set; } = new List<double>();
  557. }
  558. public record PaperRcd
  559. {
  560. public string name { get; set; }
  561. public List<List<string>> answers { get; set; } = new List<List<string>>();
  562. public List<double> point { get; set; } = new List<double>();
  563. public SheetConfig sheet { get; set; }
  564. }
  565. public class ExamSubjectData
  566. {
  567. public string id { get; set; }
  568. public string name { get; set; }
  569. }
  570. public record ExamSheetData
  571. {
  572. public string code { get; set; }
  573. public SheetConfig sheet { get; set; }
  574. public string id { get; set; }
  575. public string name { get; set; }
  576. public long startTime { get; set; }
  577. public long endTime { get; set; }
  578. public PeriodSimple period { get; set; }
  579. public List<Grade> grades { get; set; }
  580. public ExamSubjectData subject { get; set; }
  581. public PaperRcdData paper { get; set; }
  582. public List<RGroupList> classes { get; set; }
  583. public string scope { get; set; }
  584. }
  585. public record ExamRcd
  586. {
  587. public string id { get; set; }
  588. public string name { get; set; }
  589. public long startTime { get; set; }
  590. public long endTime { get; set; }
  591. public PeriodSimple period { get; set; }
  592. public List<Grade> grades { get; set; }
  593. public List<ExamSubject> subjects { get; set; }
  594. public List<PaperRcd> papers { get; set; }
  595. public List<RGroupList> classes { get; set; }
  596. public string scope { get; set; }
  597. }
  598. }