HiTeachController.cs 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  1. using Azure.Cosmos;
  2. using Azure.Storage.Blobs.Models;
  3. using Azure.Storage.Sas;
  4. using Microsoft.AspNetCore.Authorization;
  5. using Microsoft.AspNetCore.Http;
  6. using Microsoft.AspNetCore.Mvc;
  7. using Microsoft.Extensions.Options;
  8. using System;
  9. using System.Collections.Generic;
  10. using System.IdentityModel.Tokens.Jwt;
  11. using System.IO;
  12. using System.Linq;
  13. using System.Text;
  14. using System.Text.Json;
  15. using System.Threading.Tasks;
  16. using TEAMModelOS.Models;
  17. using TEAMModelOS.Filter;
  18. using TEAMModelOS.SDK.DI;
  19. using TEAMModelOS.SDK.Extension;
  20. using Microsoft.Azure.Cosmos.Table;
  21. using TEAMModelOS.SDK.Models;
  22. using System.Dynamic;
  23. namespace TEAMModelOS.Controllers.Client
  24. {
  25. [ProducesResponseType(StatusCodes.Status200OK)]
  26. [ProducesResponseType(StatusCodes.Status400BadRequest)]
  27. //[Authorize(Roles = "HiTeach")]
  28. [Route("hiteach")]
  29. [ApiController]
  30. public class HiTeachController : ControllerBase
  31. {
  32. private readonly AzureStorageFactory _azureStorage;
  33. private readonly AzureRedisFactory _azureRedis;
  34. private readonly AzureCosmosFactory _azureCosmos;
  35. private readonly DingDing _dingDing;
  36. private readonly Option _option;
  37. private readonly SnowflakeId _snowflakeId;
  38. public HiTeachController(
  39. AzureStorageFactory azureStorage,
  40. AzureRedisFactory azureRedis,
  41. AzureCosmosFactory azureCosmos,
  42. DingDing dingDing,
  43. SnowflakeId snowflakeId,
  44. IOptionsSnapshot<Option> option)
  45. {
  46. _azureStorage = azureStorage;
  47. _azureRedis = azureRedis;
  48. _azureCosmos = azureCosmos;
  49. _dingDing = dingDing;
  50. _snowflakeId = snowflakeId;
  51. _option = option?.Value;
  52. }
  53. [ProducesDefaultResponseType]
  54. [HttpPost("get-teacher-info")]
  55. public async Task<IActionResult> GetTeacherInfo()
  56. {
  57. //Debug
  58. //string json = System.Text.Json.JsonSerializer.Serialize(id_token);
  59. try
  60. {
  61. string id_token = HttpContext.GetXAuth("IdToken");
  62. if(string.IsNullOrEmpty(id_token)) return BadRequest();
  63. var jwt = new JwtSecurityToken(id_token);
  64. if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.OrdinalIgnoreCase)) return BadRequest();
  65. var id = jwt.Payload.Sub;
  66. jwt.Payload.TryGetValue("name", out object name);
  67. jwt.Payload.TryGetValue("picture", out object picture);
  68. List<object> schools = new List<object>();
  69. string defaultschool = null;
  70. //TODK 取得Teacher 個人相關數據(課程清單、虛擬教室清單、歷史紀錄清單等),學校數據另外API處理,多校切換時不同
  71. var client = _azureCosmos.GetCosmosClient();
  72. var response = await client.GetContainer("TEAMModelOS", "Teacher").ReadItemStreamAsync(id, new PartitionKey("Base"));
  73. if (response.Status == 200)
  74. {
  75. var jsonsc = await JsonDocument.ParseAsync(response.ContentStream);
  76. if (jsonsc.RootElement.TryGetProperty("schools", out JsonElement value))
  77. {
  78. foreach (var obj in value.EnumerateArray())
  79. {
  80. string statusNow = obj.GetProperty("status").ToString();
  81. if(statusNow == "join") //成為老師的才放入
  82. {
  83. dynamic schoolExtobj = new ExpandoObject();
  84. schoolExtobj.schoolId = obj.GetProperty("schoolId");
  85. schoolExtobj.name = obj.GetProperty("name");
  86. schoolExtobj.status = obj.GetProperty("status");
  87. schools.Add(schoolExtobj);
  88. }
  89. }
  90. }
  91. //預設學校ID
  92. if (jsonsc.RootElement.TryGetProperty("defaultSchool", out JsonElement valueD) && !string.IsNullOrEmpty(valueD.ToString()))
  93. {
  94. defaultschool = valueD.ToString();
  95. }
  96. }
  97. else
  98. {
  99. //如果沒有,則初始化Teacher基本資料到Cosmos
  100. using var stream = new MemoryStream();
  101. using var writer = new Utf8JsonWriter(stream); //new JsonWriterOptions() { Indented = true }
  102. writer.WriteStartObject();
  103. writer.WriteString("code", "Base");
  104. writer.WriteString("id", id);
  105. writer.WriteString("name", name?.ToString());
  106. writer.WriteString("picture", picture?.ToString());
  107. writer.WriteStartArray("schools");
  108. writer.WriteEndArray();
  109. writer.WriteEndObject();
  110. writer.Flush();
  111. //Debug
  112. //string teacher = Encoding.UTF8.GetString(stream.ToArray());
  113. response = await _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "Teacher").CreateItemStreamAsync(stream, new PartitionKey("Base"));
  114. }
  115. //老師個人課程清單
  116. List<object> courses = new List<object>();
  117. await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher").GetItemQueryStreamIterator(queryText: $"SELECT c.id, c.name, c.schedule, c.scope FROM c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Course-{id}") }))
  118. {
  119. var jsontcs = await JsonDocument.ParseAsync(item.ContentStream);
  120. if (jsontcs.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  121. {
  122. foreach (var obj in jsontcs.RootElement.GetProperty("Documents").EnumerateArray())
  123. {
  124. dynamic courseExtobj = new ExpandoObject();
  125. courseExtobj.id = Convert.ToString(obj.GetProperty("id"));
  126. courseExtobj.name = Convert.ToString(obj.GetProperty("name"));
  127. courseExtobj.scope = Convert.ToString(obj.GetProperty("scope"));
  128. List<object> classes = new List<object>();
  129. if(obj.TryGetProperty("schedule", out JsonElement schedule))
  130. {
  131. foreach (var scheduleobj in schedule.EnumerateArray())
  132. {
  133. dynamic classExtobj = new ExpandoObject();
  134. classExtobj.id = null;
  135. classExtobj.code = null;
  136. classExtobj.teacher = null;
  137. if (scheduleobj.TryGetProperty("teacherId", out JsonElement teacherId) && !string.IsNullOrWhiteSpace(Convert.ToString(teacherId)))
  138. {
  139. await foreach (var teaitem in client.GetContainer("TEAMModelOS", "Teacher").GetItemQueryStreamIterator(queryText: $"SELECT c.id, c.name FROM c WHERE c.id = '{teacherId}'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base") }))
  140. {
  141. var jsontea = await JsonDocument.ParseAsync(teaitem.ContentStream);
  142. foreach (var teaobj in jsontea.RootElement.GetProperty("Documents").EnumerateArray())
  143. {
  144. classExtobj.teacher = new ExpandoObject();
  145. classExtobj.teacher = teaobj.ToObject<object>();
  146. }
  147. }
  148. }
  149. classExtobj.scope = "private";
  150. int stuCount = 0;
  151. string stuListId = Convert.ToString(scheduleobj.GetProperty("stulist"));
  152. classExtobj.stuListId = stuListId;
  153. await foreach (var stuitem in client.GetContainer("TEAMModelOS", "Teacher").GetItemQueryStreamIterator(queryText: $"SELECT c.id, c.name, ARRAY_LENGTH(c.students) as stucnt FROM c WHERE c.id = '{stuListId}'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("StuList") }))
  154. {
  155. var jsonstu = await JsonDocument.ParseAsync(stuitem.ContentStream);
  156. foreach (var stuobj in jsonstu.RootElement.GetProperty("Documents").EnumerateArray())
  157. {
  158. classExtobj.name = stuobj.GetProperty("name");
  159. stuCount = stuobj.GetProperty("stucnt").GetInt32();
  160. }
  161. }
  162. classExtobj.stuCnt = stuCount;
  163. classExtobj.grpCnt = 0;
  164. classExtobj.gradeId = null;
  165. classes.Add(classExtobj);
  166. }
  167. }
  168. courseExtobj.classes = classes;
  169. courses.Add(courseExtobj);
  170. }
  171. }
  172. }
  173. //取得老師個人評測 (HiTeach只取source='1'(課中评量))
  174. List<object> exams = new List<object>();
  175. await foreach (var exam in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(queryText: $"SELECT c.code, c.id, c.name, c.startTime, c.endTime ,c.year, c.source, c.type, c.progress, c.stuCount, c.scope FROM c WHERE c.source = '1'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Exam-{id}") }))
  176. {
  177. using var json = await JsonDocument.ParseAsync(exam.ContentStream);
  178. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  179. {
  180. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  181. {
  182. exams.Add(obj.ToObject<object>());
  183. }
  184. }
  185. }
  186. //取得Teacher Blob 容器位置及SAS
  187. var container = _azureStorage.GetBlobContainerClient(id);
  188. await container.CreateIfNotExistsAsync(PublicAccessType.None); //嘗試創建Teacher私有容器,如存在則不做任何事,保障容器一定存在
  189. var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(id, BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Delete);
  190. return Ok(new { blob_uri, blob_sas, schools, defaultschool, courses, exams });
  191. }
  192. catch (Exception ex)
  193. {
  194. // await _dingDing.SendBotMsg($"CoreAPI2,{_option.Location},hiteach/GetTeacherInfo()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
  195. return BadRequest();
  196. }
  197. }
  198. [ProducesDefaultResponseType]
  199. [HttpPost("get-school-info")]
  200. public async Task<IActionResult> GetSchoolInfo(JsonElement requert)
  201. {
  202. try
  203. {
  204. string id_token = HttpContext.GetXAuth("IdToken");
  205. if (string.IsNullOrEmpty(id_token)) return BadRequest();
  206. if (!requert.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
  207. var jwt = new JwtSecurityToken(id_token);
  208. if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.Ordinal)) return BadRequest();
  209. var id = jwt.Payload.Sub;
  210. var client = _azureCosmos.GetCosmosClient();
  211. //取得學校學段、年級、科目、考試類型
  212. List<object> periods = new List<object>();
  213. List<object> grades = new List<object>();
  214. List<object> subjects = new List<object>();
  215. List<object> examTypes = new List<object>();
  216. var responsesch = await client.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync(school_code.ToString(), new PartitionKey($"Base"));
  217. if (responsesch.Status == 200)
  218. {
  219. var jsons = await JsonDocument.ParseAsync(responsesch.ContentStream);
  220. if (jsons.RootElement.TryGetProperty("period", out JsonElement periodJobj))
  221. {
  222. foreach (var periodinfo in periodJobj.EnumerateArray())
  223. {
  224. dynamic periodExtobj = new ExpandoObject();
  225. periodExtobj.id = periodinfo.GetProperty("id");
  226. periodExtobj.name = periodinfo.GetProperty("name");
  227. periods.Add(periodExtobj);
  228. if (periodinfo.TryGetProperty("grades", out JsonElement gradesJobj))
  229. {
  230. foreach (var gradeinfo in gradesJobj.EnumerateArray())
  231. {
  232. dynamic gradeExtobj = new ExpandoObject();
  233. gradeExtobj.id = gradeinfo.GetProperty("id");
  234. gradeExtobj.name = gradeinfo.GetProperty("name");
  235. gradeExtobj.periodId = periodinfo.GetProperty("id");
  236. grades.Add(gradeExtobj);
  237. }
  238. }
  239. if (periodinfo.TryGetProperty("subjects", out JsonElement subjectsJobj))
  240. {
  241. foreach (var subjectinfo in subjectsJobj.EnumerateArray())
  242. {
  243. dynamic subjectExtobj = new ExpandoObject();
  244. subjectExtobj.id = subjectinfo.GetProperty("id");
  245. subjectExtobj.name = subjectinfo.GetProperty("name");
  246. subjectExtobj.periodId = periodinfo.GetProperty("id");
  247. subjects.Add(subjectExtobj);
  248. }
  249. }
  250. if (periodinfo.TryGetProperty("analysis", out JsonElement periodanalysisJobj))
  251. {
  252. if (periodanalysisJobj.TryGetProperty("type", out JsonElement examTypeJobj))
  253. {
  254. foreach (var examType in examTypeJobj.EnumerateArray())
  255. {
  256. examTypes.Add(examType.ToObject<object>());
  257. }
  258. }
  259. }
  260. }
  261. }
  262. }
  263. else //無此學校資料
  264. {
  265. return BadRequest();
  266. }
  267. //該老師排定的學校課程
  268. List<object> courses = new List<object>();
  269. var query = $"SELECT c.id, c.name, c.scope, c.subject, schedule.classId AS scheduleClassId, schedule.teacher AS scheduleTeacher, schedule.stulist AS scheduleStulist, schedule.time AS scheduleTime, schedule.notice AS scheduleNotice FROM c JOIN schedule IN c.schedule WHERE schedule.teacherId = '{id}'";
  270. //var query = $"SELECT c.id, c.name, c.teacher, cc.course, c.scope FROM c JOIN cc IN c.courses JOIN cct IN cc.teachers WHERE cct.id = '{id}'";
  271. await foreach (var item in client.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryText: query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Course-{school_code}") }))
  272. {
  273. var jsoncs = await JsonDocument.ParseAsync(item.ContentStream);
  274. if (jsoncs.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  275. {
  276. foreach (var obj in jsoncs.RootElement.GetProperty("Documents").EnumerateArray())
  277. {
  278. //班級
  279. string classIdNow = string.Empty;
  280. if(obj.TryGetProperty("scheduleClassId", out JsonElement scheduleClassId))
  281. {
  282. classIdNow = Convert.ToString(scheduleClassId);
  283. }
  284. dynamic classExtobj = new ExpandoObject();
  285. classExtobj.id = null;
  286. classExtobj.code = null;
  287. classExtobj.name = null;
  288. classExtobj.scope = null;
  289. classExtobj.gradeId = null;
  290. classExtobj.teacher = null;
  291. classExtobj.stuListId = null;
  292. classExtobj.stuCnt = 0;
  293. classExtobj.grpCnt = 0;
  294. if (!string.IsNullOrWhiteSpace(classIdNow))
  295. {
  296. var querycl = $"SELECT c.code, c.id, c.name, c.teacher, c.scope, c.gradeId FROM c WHERE c.id = '{classIdNow}'";
  297. await foreach (var itemcl in client.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryText: querycl, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Class-{school_code}") }))
  298. {
  299. var jsoncl = await JsonDocument.ParseAsync(itemcl.ContentStream);
  300. foreach (var objcl in jsoncl.RootElement.GetProperty("Documents").EnumerateArray())
  301. {
  302. classExtobj.id = Convert.ToString(objcl.GetProperty("id"));
  303. classExtobj.code = Convert.ToString(objcl.GetProperty("code"));
  304. classExtobj.name = Convert.ToString(objcl.GetProperty("name"));
  305. classExtobj.scope = Convert.ToString(objcl.GetProperty("scope"));
  306. classExtobj.gradeId = Convert.ToString(objcl.GetProperty("gradeId"));
  307. classExtobj.teacher = objcl.GetProperty("teacher");
  308. classExtobj.stuCnt = 0;
  309. classExtobj.grpCnt = 0;
  310. var queryclstc = $"SELECT Count(1) AS stuCnt FROM c WHERE c.classId = '{classIdNow}'";
  311. await foreach (var itemclstc in client.GetContainer("TEAMModelOS", "Student").GetItemQueryStreamIterator(queryText: queryclstc, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base-{school_code}") }))
  312. {
  313. var jsonclstc = await JsonDocument.ParseAsync(itemclstc.ContentStream);
  314. foreach (var objstc in jsonclstc.RootElement.GetProperty("Documents").EnumerateArray())
  315. {
  316. classExtobj.stuCnt = objstc.GetProperty("stuCnt").GetUInt32();
  317. }
  318. }
  319. var queryclgp = $"SELECT c.groupId FROM c WHERE c.classId = '{classIdNow}' AND IS_NULL(c.groupId)=false GROUP BY c.groupId";
  320. await foreach (var itemgp in client.GetContainer("TEAMModelOS", "Student").GetItemQueryStreamIterator(queryText: queryclgp, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base-{school_code}") }))
  321. {
  322. var jsongp = await JsonDocument.ParseAsync(itemgp.ContentStream);
  323. if (jsongp.RootElement.TryGetProperty("_count", out JsonElement gpcount) && gpcount.GetUInt32() > 0)
  324. {
  325. classExtobj.grpCnt = gpcount.GetUInt32();
  326. }
  327. }
  328. }
  329. }
  330. }
  331. var stuListId = obj.GetProperty("scheduleStulist");
  332. if (!stuListId.ValueKind.Equals(JsonValueKind.Null))
  333. {
  334. classExtobj.stuListId = Convert.ToString(stuListId);
  335. await foreach (var stuitem in client.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryText: $"SELECT ARRAY_LENGTH(c.students) as stucnt FROM c WHERE c.id = '{stuListId}'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"StuList-{school_code}") }))
  336. {
  337. var jsonstu = await JsonDocument.ParseAsync(stuitem.ContentStream);
  338. foreach (var stuobj in jsonstu.RootElement.GetProperty("Documents").EnumerateArray())
  339. {
  340. classExtobj.stuCnt = stuobj.GetProperty("stucnt").GetInt32();
  341. }
  342. }
  343. }
  344. //課程
  345. //var scheduleTeacherInfo = obj.GetProperty("scheduleTeacher");
  346. string courseIdNow = obj.GetProperty("id").ToString();
  347. var courseExist = courses.Where((dynamic x) => x.id == courseIdNow).FirstOrDefault();
  348. if (courseExist == null)
  349. {
  350. dynamic courseExtobj = new ExpandoObject();
  351. courseExtobj.id = courseIdNow;
  352. courseExtobj.name = obj.GetProperty("name").ToString();
  353. courseExtobj.scope = obj.GetProperty("scope").ToString();
  354. courseExtobj.classes = new List<object>();
  355. courseExtobj.subject = obj.GetProperty("subject");
  356. //classExtobj.teacher = scheduleTeacherInfo;
  357. courseExtobj.classes.Add(classExtobj);
  358. courses.Add(courseExtobj);
  359. }
  360. else
  361. {
  362. //classExtobj.teacher = scheduleTeacherInfo;
  363. courseExist.classes.Add(classExtobj);
  364. }
  365. }
  366. }
  367. }
  368. //取得校園評測 (HiTeach只取source='1'(課中评量))
  369. List<object> exams = new List<object>();
  370. await foreach (var exam in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(queryText: $"SELECT c.code, c.id, c.name, c.startTime, c.endTime ,c.year, c.source, c.type, c.progress, c.stuCount, c.scope FROM c WHERE c.source = '1'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Exam-{school_code}") }))
  371. {
  372. using var json = await JsonDocument.ParseAsync(exam.ContentStream);
  373. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  374. {
  375. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  376. {
  377. exams.Add(obj.ToObject<object>());
  378. }
  379. }
  380. }
  381. //取得School Blob 容器位置及SAS
  382. string school_code_blob = school_code.GetString().ToLower();
  383. var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(school_code_blob, BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List);
  384. return Ok(new { blob_uri, blob_sas, periods, grades, subjects, courses, examTypes, exams });
  385. }
  386. catch (Exception ex)
  387. {
  388. // await _dingDing.SendBotMsg($"CoreAPI2,{_option.Location},hiteach/GetTeacherInfo()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
  389. return BadRequest();
  390. }
  391. }
  392. //取得試卷
  393. [ProducesDefaultResponseType]
  394. [HttpPost("get-paper")]
  395. public async Task<IActionResult> GetPaperList(JsonElement request)
  396. {
  397. try
  398. {
  399. //Header驗證
  400. string id_token = HttpContext.GetXAuth("IdToken");
  401. if (string.IsNullOrEmpty(id_token)) return BadRequest();
  402. var jwt = new JwtSecurityToken(id_token);
  403. if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.Ordinal)) return BadRequest();
  404. var id = jwt.Payload.Sub;
  405. var client = _azureCosmos.GetCosmosClient();
  406. //參數
  407. if (!request.TryGetProperty("grant_type", out JsonElement grant_type)) return BadRequest();
  408. string partitionid = string.Empty;
  409. string container = string.Empty;
  410. if (grant_type.ToString() == "school")
  411. {
  412. if (!request.TryGetProperty("school_code", out JsonElement school_code_json))
  413. {
  414. return BadRequest();
  415. }
  416. else
  417. {
  418. partitionid = school_code_json.ToString();
  419. container = "School";
  420. }
  421. }
  422. else
  423. {
  424. partitionid = id.ToString();
  425. container = "Teacher";
  426. }
  427. //SQL文
  428. List<object> papers = new List<object>();
  429. string queryWhere = " WHERE 1=1 ";
  430. string queryOption = string.Empty;
  431. //學段
  432. if (request.TryGetProperty("periodId", out JsonElement periodId) && container == "School")
  433. {
  434. queryWhere += $" AND c.periodId = '{periodId}'";
  435. }
  436. //年級
  437. if (request.TryGetProperty("gradeId", out JsonElement gradeIds) && gradeIds.GetArrayLength() > 0 && container == "School")
  438. {
  439. string queryOptionForGrade = string.Empty;
  440. for (int i = 0; i < gradeIds.GetArrayLength(); i++)
  441. {
  442. if(!string.IsNullOrWhiteSpace(queryOptionForGrade))
  443. {
  444. queryOptionForGrade += " OR ";
  445. }
  446. queryOptionForGrade += $" ARRAY_CONTAINS(c.gradeIds, '{gradeIds[i]}', true)";
  447. }
  448. queryWhere += $" AND ( {queryOptionForGrade} )";
  449. }
  450. //科目ID
  451. if (request.TryGetProperty("subjectId", out JsonElement subjectId) && container == "School")
  452. {
  453. queryWhere += $" AND c.subjectId = '{subjectId}'";
  454. }
  455. //科目名稱
  456. if (request.TryGetProperty("subjectName", out JsonElement subjectName))
  457. {
  458. queryWhere += $" AND c.subjectName = '{subjectName}'";
  459. }
  460. int perpage = 0; //每頁幾條
  461. if (request.TryGetProperty("perpage", out JsonElement perpage_json)) perpage = perpage_json.GetInt32();
  462. int page = 0; //目前第幾頁
  463. if (request.TryGetProperty("page", out JsonElement page_json))
  464. {
  465. if(page_json.GetInt32() > 0)
  466. {
  467. page = page_json.GetInt32() - 1;
  468. }
  469. }
  470. string order = "createTime"; //排序項目
  471. if (request.TryGetProperty("order", out JsonElement order_json))
  472. {
  473. if(order_json.ToString() == "useCount")
  474. {
  475. order = order_json.ToString();
  476. }
  477. }
  478. queryOption += $" Order By c." + order + " DESC ";
  479. if(perpage > 0 )
  480. {
  481. queryOption += $" OFFSET {perpage * page} LIMIT {perpage}";
  482. }
  483. //資料取得
  484. await foreach (var item in client.GetContainer("TEAMModelOS", container).GetItemQueryStreamIterator(queryText: $"SELECT c.code, c.id, c.periodId, c.gradeIds, c.subjectId, c.subjectName, c.name, REPLACE(c.blob, 'index.json', '') AS blob, c.score, c.useCount, ARRAY_LENGTH(c.scoring) AS itemCount, c.createTime From c {queryWhere + queryOption}", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Paper-{partitionid}") }))
  485. {
  486. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  487. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  488. {
  489. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  490. {
  491. papers.Add(obj.ToObject<object>());
  492. }
  493. }
  494. }
  495. //總件數
  496. int totalCount = 0;
  497. await foreach (var item in client.GetContainer("TEAMModelOS", container).GetItemQueryStreamIterator(queryText: $"SELECT VALUE COUNT(1) From c {queryWhere}", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Paper-{partitionid}") }))
  498. {
  499. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  500. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  501. {
  502. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  503. {
  504. totalCount = obj.GetInt32();
  505. }
  506. }
  507. }
  508. return Ok(new { papers, totalCount });
  509. }
  510. catch (Exception ex)
  511. {
  512. return BadRequest();
  513. }
  514. }
  515. //取得試題
  516. [ProducesDefaultResponseType]
  517. [HttpPost("get-item")]
  518. public async Task<IActionResult> GetItemList(JsonElement request)
  519. {
  520. try
  521. {
  522. //Header驗證
  523. string id_token = HttpContext.GetXAuth("IdToken");
  524. if (string.IsNullOrEmpty(id_token)) return BadRequest();
  525. var jwt = new JwtSecurityToken(id_token);
  526. if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.Ordinal)) return BadRequest();
  527. var id = jwt.Payload.Sub;
  528. var client = _azureCosmos.GetCosmosClient();
  529. //參數
  530. if (!request.TryGetProperty("grant_type", out JsonElement grant_type)) return BadRequest();
  531. string partitionid = string.Empty;
  532. string container = string.Empty;
  533. if (grant_type.ToString() == "school")
  534. {
  535. if (!request.TryGetProperty("school_code", out JsonElement school_code_json))
  536. {
  537. return BadRequest();
  538. }
  539. else
  540. {
  541. partitionid = school_code_json.ToString();
  542. container = "School";
  543. }
  544. }
  545. else
  546. {
  547. partitionid = id.ToString();
  548. container = "Teacher";
  549. }
  550. //SQL文
  551. List<object> items = new List<object>();
  552. string queryWhere = " WHERE 1=1 ";
  553. string queryOption = string.Empty;
  554. //學段
  555. if (request.TryGetProperty("periodId", out JsonElement periodId) && container == "School")
  556. {
  557. queryWhere += $" AND c.periodId = '{periodId}'";
  558. }
  559. //年級
  560. if (request.TryGetProperty("gradeId", out JsonElement gradeIds) && gradeIds.GetArrayLength() > 0 && container == "School")
  561. {
  562. string queryOptionForGrade = string.Empty;
  563. for (int i = 0; i < gradeIds.GetArrayLength(); i++)
  564. {
  565. if (!string.IsNullOrWhiteSpace(queryOptionForGrade))
  566. {
  567. queryOptionForGrade += " OR ";
  568. }
  569. queryOptionForGrade += $" ARRAY_CONTAINS(c.gradeIds, '{gradeIds[i]}', true)";
  570. }
  571. queryWhere += $" AND ( {queryOptionForGrade} )";
  572. }
  573. //科目ID
  574. if (request.TryGetProperty("subjectId", out JsonElement subjectId) && container == "School")
  575. {
  576. queryWhere += $" AND c.subjectId = '{subjectId}'";
  577. }
  578. //科目名稱
  579. if (request.TryGetProperty("subjectName", out JsonElement subjectName))
  580. {
  581. queryWhere += $" AND c.subjectName = '{subjectName}'";
  582. }
  583. //題型
  584. int dummy = 0;
  585. if (request.TryGetProperty("type", out JsonElement type))
  586. {
  587. queryWhere += $" AND c.type = '{type}'";
  588. }
  589. //難度
  590. dummy = 0;
  591. if (request.TryGetProperty("level", out JsonElement level) && int.TryParse(level.ToString(), out dummy))
  592. {
  593. queryWhere += $" AND c.level = {level}";
  594. }
  595. //層次
  596. if (request.TryGetProperty("field", out JsonElement field) && int.TryParse(field.ToString(), out dummy))
  597. {
  598. queryWhere += $" AND c.field = {field}";
  599. }
  600. int perpage = 0; //每頁幾條
  601. if (request.TryGetProperty("perpage", out JsonElement perpage_json)) perpage = perpage_json.GetInt32();
  602. int page = 0; //目前第幾頁
  603. if (request.TryGetProperty("page", out JsonElement page_json))
  604. {
  605. if (page_json.GetInt32() > 0)
  606. {
  607. page = page_json.GetInt32() - 1;
  608. }
  609. }
  610. string order = "createTime"; //排序項目
  611. if (request.TryGetProperty("order", out JsonElement order_json))
  612. {
  613. if (order_json.ToString() == "useCount")
  614. {
  615. order = order_json.ToString();
  616. }
  617. }
  618. queryOption += $" Order By c." + order + " DESC ";
  619. if (perpage > 0)
  620. {
  621. queryOption += $" OFFSET {perpage * page} LIMIT {perpage}";
  622. }
  623. //資料取得
  624. await foreach (var item in client.GetContainer("TEAMModelOS", container).GetItemQueryStreamIterator(queryText: $"SELECT c.id, c.periodId, c.gradeIds, c.subjectId, c.subjectName, c.blob, c.field, c.level, c.type, c.useCount, c.createTime From c {queryWhere + queryOption}", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{partitionid}") }))
  625. {
  626. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  627. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  628. {
  629. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  630. {
  631. items.Add(obj.ToObject<object>());
  632. }
  633. }
  634. }
  635. //總件數
  636. int totalCount = 0;
  637. await foreach (var item in client.GetContainer("TEAMModelOS", container).GetItemQueryStreamIterator(queryText: $"SELECT VALUE COUNT(1) From c {queryWhere}", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{partitionid}") }))
  638. {
  639. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  640. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  641. {
  642. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  643. {
  644. totalCount = obj.GetInt32();
  645. }
  646. }
  647. }
  648. return Ok(new { items, totalCount });
  649. }
  650. catch (Exception ex)
  651. {
  652. return BadRequest();
  653. }
  654. }
  655. //取得知識點
  656. [ProducesDefaultResponseType]
  657. [HttpPost("get-knowledge")]
  658. public async Task<IActionResult> GetKnowledgePointList(JsonElement request)
  659. {
  660. var client = _azureCosmos.GetCosmosClient();
  661. if (!request.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
  662. //知識點
  663. List<object> points = new List<object>();
  664. await foreach (var item in client.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryText: $"SELECT c.id, c.name, c.subjectId FROM c WHERE c.type = 'point'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Knowledge-{school_code}") }))
  665. {
  666. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  667. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  668. {
  669. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  670. {
  671. points.Add(obj.ToObject<object>());
  672. }
  673. }
  674. }
  675. return Ok(points);
  676. }
  677. //取得課綱
  678. [ProducesDefaultResponseType]
  679. [HttpPost("get-syllabus")]
  680. public async Task<IActionResult> GetSyllabusList(JsonElement request)
  681. {
  682. var client = _azureCosmos.GetCosmosClient();
  683. if (!request.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
  684. //校本課綱
  685. List<SyllabusRole> syllabus = new List<SyllabusRole>();
  686. await foreach (var item in client.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryText: $"SELECT c.id, c.name, c.period, c.grade, c.semester, c.subject, c.scope, c.resourceCount, c.itemCount, c.children from c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Syllabus-{school_code}") }))
  687. {
  688. var jsons = await JsonDocument.ParseAsync(item.ContentStream);
  689. if (jsons.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  690. {
  691. foreach (var obj in jsons.RootElement.GetProperty("Documents").EnumerateArray())
  692. {
  693. SyllabusRole syllabusRole = new SyllabusRole();
  694. syllabusRole.id = obj.GetProperty("id").ToString();
  695. syllabusRole.name = obj.GetProperty("name").ToString();
  696. syllabusRole.period = obj.GetProperty("period");
  697. syllabusRole.grade = obj.GetProperty("grade");
  698. syllabusRole.semester = obj.GetProperty("semester");
  699. syllabusRole.subject = obj.GetProperty("subject");
  700. syllabusRole.resourceCount = obj.GetProperty("resourceCount").GetUInt16();
  701. syllabusRole.itemCount = obj.GetProperty("itemCount").GetUInt16();
  702. List<Syllabus> syllabusList = obj.GetProperty("children").ToObject<List<Syllabus>>();
  703. syllabusList.Insert(0, new Syllabus { id = syllabusRole.id, name = syllabusRole.name, pid = "", order = 0 });
  704. syllabusList = syllabusList.OrderBy(x => x.order).ToList();
  705. syllabusRole.structure = CreateSyllabusTree(syllabusList);
  706. syllabus.Add(syllabusRole);
  707. }
  708. //[DEBUG] string jsonString = System.Text.Json.JsonSerializer.Serialize(syllabusRoles);
  709. }
  710. }
  711. return Ok(syllabus);
  712. }
  713. //取得某班級的學生成員
  714. [ProducesDefaultResponseType]
  715. [HttpPost("get-students-list")]
  716. public async Task<IActionResult> GetStudentsList(JsonElement request)
  717. {
  718. string id_token = HttpContext.GetXAuth("IdToken");
  719. if (string.IsNullOrWhiteSpace(id_token)) return BadRequest();
  720. var jwt = new JwtSecurityToken(id_token);
  721. if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.Ordinal)) return BadRequest();
  722. var id = jwt.Payload.Sub;
  723. if (!request.TryGetProperty("grant_type", out JsonElement grant_type)) return BadRequest();
  724. request.TryGetProperty("class_code", out JsonElement class_code);
  725. request.TryGetProperty("stulist_id", out JsonElement stulist_id);
  726. string classId = Convert.ToString(class_code);
  727. string stulist = Convert.ToString(stulist_id);
  728. if(string.IsNullOrWhiteSpace(classId) && string.IsNullOrWhiteSpace(stulist)) return BadRequest();
  729. request.TryGetProperty("school_code", out JsonElement school_code);
  730. if (grant_type.GetString() == "school" && string.IsNullOrEmpty(Convert.ToString(school_code))) return BadRequest();
  731. var client = _azureCosmos.GetCosmosClient();
  732. List<object> students = new List<object>();
  733. string container = (grant_type.GetString() == "school") ? "School" : "Teacher";
  734. //Case 1 取得stulist成員 (有stulist_id則優先取)
  735. if (!string.IsNullOrWhiteSpace(stulist))
  736. {
  737. string pk = (grant_type.GetString() == "school") ? $"StuList-{school_code}" : $"StuList";
  738. var querystl = $"SELECT c.students FROM c WHERE c.id = '{stulist}'";
  739. Dictionary<string, List<string>> stuDic = new Dictionary<string, List<string>>();
  740. await foreach (var item in client.GetContainer("TEAMModelOS", container).GetItemQueryStreamIterator(queryText: querystl, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey(pk) }))
  741. {
  742. var json = await JsonDocument.ParseAsync(item.ContentStream);
  743. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  744. {
  745. foreach (var stuObj in json.RootElement.GetProperty("Documents").EnumerateArray())
  746. {
  747. foreach (var studentObj in stuObj.GetProperty("students").EnumerateArray())
  748. {
  749. string stuCode = studentObj.GetProperty("code").ToString();
  750. string stuId = studentObj.GetProperty("id").ToString();
  751. if (stuDic.ContainsKey(stuCode) && !stuDic[stuCode].Contains(stuId))
  752. {
  753. if (!stuDic[stuCode].Contains(stuId))
  754. {
  755. stuDic[stuCode].Add(stuId);
  756. }
  757. }
  758. else
  759. {
  760. List<string> stuIdList = new List<string>();
  761. stuIdList.Add(stuId);
  762. stuDic.Add(stuCode, stuIdList);
  763. }
  764. }
  765. }
  766. }
  767. }
  768. if(stuDic.Count > 0)
  769. {
  770. foreach (KeyValuePair<string, List<string>> stuDicRow in stuDic)
  771. {
  772. string stuCode = stuDicRow.Key;
  773. List<string> stuIdList = stuDicRow.Value;
  774. var queryst = $"SELECT c.id, c.name, null AS no, c.schoolId FROM c WHERE ARRAY_CONTAINS({JsonSerializer.Serialize(stuIdList)}, c.id)";
  775. await foreach (var item in client.GetContainer("TEAMModelOS", "Student").GetItemQueryStreamIterator(queryText: queryst, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey(stuCode) }))
  776. {
  777. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  778. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  779. {
  780. foreach (var stuObj in json.RootElement.GetProperty("Documents").EnumerateArray())
  781. {
  782. students.Add(stuObj.ToObject<object>());
  783. }
  784. }
  785. }
  786. }
  787. }
  788. }
  789. //Case 2 取得班級固定成員
  790. if(grant_type.GetString() == "school" && students.Count == 0 && !string.IsNullOrWhiteSpace(classId) && string.IsNullOrWhiteSpace(stulist))
  791. {
  792. var query = $"SELECT c.id, c.name, c.no, c.schoolId, c.groupId, c.groupName FROM c WHERE c.classId = '{classId}'";
  793. await foreach (var item in client.GetContainer("TEAMModelOS", "Student").GetItemQueryStreamIterator(queryText: query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base-{school_code}") }))
  794. {
  795. using var jsonst = await JsonDocument.ParseAsync(item.ContentStream);
  796. if (jsonst.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  797. {
  798. foreach (var stuObj in jsonst.RootElement.GetProperty("Documents").EnumerateArray())
  799. {
  800. students.Add(stuObj.ToObject<object>());
  801. }
  802. }
  803. }
  804. }
  805. return Ok(new { students });
  806. }
  807. [ProducesDefaultResponseType]
  808. [HttpPost("start-lesson")]
  809. public async Task<IActionResult> StartLesson(JsonElement request)
  810. {
  811. //取得授課ID
  812. string lesson_code = (request.TryGetProperty("lesson_id", out JsonElement lesson_id) && !string.IsNullOrWhiteSpace(Convert.ToString(lesson_id))) ? Convert.ToString(lesson_id) : _snowflakeId.NextId().ToString();
  813. bool get_lesson_id = (string.IsNullOrWhiteSpace(Convert.ToString(lesson_id)) || Convert.ToString(lesson_id) != lesson_code) ? false : true;
  814. //取得醍摩豆ID
  815. string teacherId = string.Empty;
  816. string id_token = HttpContext.GetXAuth("IdToken");
  817. if (!string.IsNullOrWhiteSpace(id_token))
  818. {
  819. var jwt = new JwtSecurityToken(id_token);
  820. if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.OrdinalIgnoreCase)) return BadRequest();
  821. teacherId = jwt.Payload.Sub;
  822. }
  823. if (string.IsNullOrWhiteSpace(teacherId) && get_lesson_id) return BadRequest(); //有授課ID無醍摩豆ID,BadRequest
  824. //DB操作
  825. if (!string.IsNullOrWhiteSpace(teacherId))
  826. {
  827. string tableName = "TeacherLesson";
  828. CloudTable table = _azureStorage.GetCloudTableClient().GetTableReference(tableName);
  829. Lesson lessonEntity = new Lesson(teacherId, lesson_code);
  830. TableOperation operation = TableOperation.InsertOrReplace(lessonEntity);
  831. TableResult result = await table.ExecuteAsync(operation);
  832. }
  833. return Ok(new { lesson_code });
  834. }
  835. [ProducesDefaultResponseType]
  836. [HttpPost("upd-exam-result")]
  837. public async Task<IActionResult> UploadExamResult(JsonElement request)
  838. {
  839. try
  840. {
  841. string message = "";
  842. int error = 0;
  843. string id_token = HttpContext.GetXAuth("IdToken");
  844. if (string.IsNullOrWhiteSpace(id_token)) return BadRequest();
  845. var jwt = new JwtSecurityToken(id_token);
  846. if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.Ordinal)) return BadRequest();
  847. var id = jwt.Payload.Sub;
  848. if (!request.TryGetProperty("exam", out JsonElement exam)) return BadRequest();
  849. if (!request.TryGetProperty("examClassResult", out JsonElement examClassResult)) return BadRequest();
  850. ExamInfo dbExamInfo = exam.ToObject<ExamInfo>();
  851. List<ExamClassResultStudentAnswerArray> dbExamClassResultList = examClassResult.ToObject<List<ExamClassResultStudentAnswerArray>>();
  852. //ExamInfo內容取得、調整
  853. string blobContainer = (dbExamInfo.range == "school" && dbExamInfo.scope == "school" && dbExamInfo.school != null) ? dbExamInfo.school : id; //blob容器
  854. dbExamInfo.source = "1"; //評測來源固定為 1:課中評量
  855. //UPDATE
  856. var examResponse = _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "Common").UpsertItemAsync(dbExamInfo, new PartitionKey(dbExamInfo.code)).GetAwaiter().GetResult();
  857. //ExamClassResult內容調整
  858. foreach (ExamClassResultStudentAnswerArray examClassResultRow in dbExamClassResultList)
  859. {
  860. ExamClassResult examClassResultUpd = new ExamClassResult();
  861. examClassResultUpd.pk = examClassResultRow.pk;
  862. examClassResultUpd.code = examClassResultRow.code;
  863. examClassResultUpd.id = examClassResultRow.id;
  864. examClassResultUpd.school = examClassResultRow.school;
  865. examClassResultUpd.examId = examClassResultRow.examId;
  866. examClassResultUpd.subjectId = examClassResultRow.subjectId;
  867. examClassResultUpd.gradeId = examClassResultRow.gradeId;
  868. examClassResultUpd.year = examClassResultRow.year;
  869. examClassResultUpd.info = examClassResultRow.info;
  870. examClassResultUpd.progress = examClassResultRow.progress;
  871. examClassResultUpd.studentIds = examClassResultRow.studentIds;
  872. examClassResultUpd.studentAnswers = new List<List<string>>();
  873. examClassResultUpd.studentScores = examClassResultRow.studentScores;
  874. examClassResultUpd.scope = examClassResultRow.scope;
  875. examClassResultUpd.sum = examClassResultRow.sum;
  876. string examId = examClassResultRow.examId;
  877. string subjectId = examClassResultRow.subjectId;
  878. //examClassResult.studentAnswers 將學生答案上傳blob後轉換內容為blob路徑
  879. if (examClassResultRow.studentIds != null && examClassResultRow.studentIds.Count > 0 && examClassResultRow.studentAnswersArray != null && examClassResultRow.studentAnswersArray.Count > 0)
  880. {
  881. for (int i = 0; i < examClassResultRow.studentAnswersArray.Count; i++)
  882. {
  883. string studentId = examClassResultRow.studentIds[i];
  884. string fileName = examId + "/" + subjectId + "/" + studentId;
  885. string blob = fileName + "/" + "ans.json";
  886. await _azureStorage.UploadFileByContainer(blobContainer, examClassResultRow.studentAnswersArray[i].ToJsonString(), "exam", blob, false);
  887. List<string> studenrAnswerRow = new List<string>();
  888. studenrAnswerRow.Add(blob);
  889. examClassResultUpd.studentAnswers.Add(studenrAnswerRow);
  890. }
  891. }
  892. //UPDATE
  893. var examClassResultResponse = await _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "Common").UpsertItemAsync(examClassResultUpd, new PartitionKey(examClassResultUpd.code));
  894. }
  895. return Ok(new { error, message });
  896. }
  897. catch (Exception ex)
  898. {
  899. return BadRequest();
  900. }
  901. }
  902. //課綱的model先記在下面,待式樣確定後再轉換
  903. private List<SyllabusNode> CreateSyllabusTree(List<Syllabus> syllabuses)
  904. {
  905. List<SyllabusNode> nodes = new List<SyllabusNode>();
  906. foreach (var syllabus in syllabuses)
  907. {
  908. if (syllabus.pid == "")
  909. nodes.Add(new SyllabusNode { id = syllabus.id, name = syllabus.name });
  910. else
  911. {
  912. CreateNode(nodes, syllabus);
  913. }
  914. }
  915. return nodes;
  916. }
  917. private void CreateNode(List<SyllabusNode> nodes, Syllabus parent)
  918. {
  919. foreach (var node in nodes)
  920. {
  921. if (node.id == parent.pid)
  922. {
  923. node.children.Add(new SyllabusNode { id = parent.id, name = parent.name });
  924. }
  925. else
  926. {
  927. CreateNode(node.children, parent);
  928. }
  929. }
  930. }
  931. public class SyllabusRole
  932. {
  933. public string id { get; set; }
  934. public string name { get; set; }
  935. public object period { get; set; }
  936. public object semester { get; set; }
  937. public object grade { get; set; }
  938. public object subject { get; set; }
  939. public int resourceCount { get; set; }
  940. public int itemCount { get; set; }
  941. public object structure { get; set; }
  942. }
  943. public class Syllabus
  944. {
  945. public string id { get; set; }
  946. public string name { get; set; }
  947. public string pid { get; set; }
  948. public int order { get; set; }
  949. }
  950. public class SyllabusNode
  951. {
  952. public string id { get; set; }
  953. public string name { get; set; }
  954. public List<SyllabusNode> children { get; set; }
  955. public SyllabusNode()
  956. {
  957. children = new List<SyllabusNode>();
  958. }
  959. }
  960. public class ExamClassResultStudentAnswerArray : ExamClassResult
  961. {
  962. public List<List<List<string>>> studentAnswersArray { get; set; }
  963. }
  964. }
  965. }