EvaluationSyncInfoService.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. using Azure.Storage.Blobs.Models;
  2. using IES.ExamServer.Models;
  3. using Microsoft.Azure.Cosmos;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Reflection.Metadata.Ecma335;
  8. using System.Text;
  9. using System.Text.Json;
  10. using System.Text.Json.Nodes;
  11. using System.Threading.Tasks;
  12. using TEAMModelOS.SDK.DI;
  13. using TEAMModelOS.SDK.Extension;
  14. using TEAMModelOS.SDK.Models.Cosmos;
  15. using TEAMModelOS.SDK.Models.Cosmos.Normal;
  16. using TEAMModelOS.SDK.Models.Cosmos.Student;
  17. using TEAMModelOS.SDK.Models.Dtos;
  18. namespace TEAMModelOS.SDK.Models.Service
  19. {
  20. public sealed class EvaluationSyncInfoService
  21. {
  22. /// <summary>
  23. /// 活动数据打包
  24. /// </summary>
  25. /// <param name="id"></param>
  26. /// <param name="scope"></param>
  27. /// <param name="owner"></param>
  28. /// <param name="type"></param>
  29. /// <param name="azureCosmos"></param>
  30. /// <param name="azureStorage"></param>
  31. public static async Task<EvaluationSyncInfo> PackageEvaluation( string id,string scope, string ownerId, string type, AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage,CoreAPIHttpService _coreAPIHttpService, DingDing _dingDing)
  32. {
  33. EvaluationSource evaluationSource = new EvaluationSource() { type=type,id=id};
  34. EvaluationSyncInfo evaluationSyncInfo= null;
  35. EvaluationClient evaluationClient = null;
  36. List<EvaluationExam> evaluationExams = new List<EvaluationExam>();
  37. long? dataTime = 0;
  38. long stime = 0;
  39. long etime = 0;
  40. string? ownerName=string.Empty;
  41. string? ownerPicture = string.Empty;
  42. string schoolCode = null;
  43. if (scope.Equals("school"))
  44. {
  45. School school = await azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemAsync<School>(ownerId, new PartitionKey("Base"));
  46. schoolCode= ownerId;
  47. evaluationSource.school = school;
  48. ownerName = school.name;
  49. ownerPicture = school.picture;
  50. }
  51. else
  52. {
  53. Teacher teacher = await azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemAsync<Teacher>(ownerId, new PartitionKey("Base"));
  54. evaluationSource.teacher = teacher;
  55. ownerName = teacher.name;
  56. ownerPicture = teacher.picture;
  57. }
  58. var responseEvaluationSyncInfo = await azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Normal).ReadItemStreamAsync(id, new PartitionKey("EvaluationSyncInfo"));
  59. if (responseEvaluationSyncInfo.IsSuccessStatusCode)
  60. {
  61. evaluationSyncInfo= JsonDocument.Parse(responseEvaluationSyncInfo.Content).RootElement.Deserialize<EvaluationSyncInfo>();
  62. }
  63. else {
  64. evaluationSyncInfo=new EvaluationSyncInfo {
  65. id = id,
  66. scope = scope,
  67. type = type,
  68. pk="EvaluationSyncInfo",
  69. code="ActivitySyncInfo",
  70. ownerId = ownerId,
  71. ownerPicture = ownerPicture,
  72. ownerName = ownerName,
  73. };
  74. }
  75. switch (true)
  76. {
  77. case bool when (type == "Exam"):
  78. {
  79. string code = $"Exam-{ownerId}";
  80. var response = await azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).ReadItemStreamAsync(id, new PartitionKey(code));
  81. if (response.IsSuccessStatusCode)
  82. {
  83. ExamInfo exam= JsonDocument.Parse(response.Content).RootElement.Deserialize<ExamInfo>();
  84. dataTime= exam._ts*1000;
  85. evaluationSyncInfo.name=exam.name;
  86. evaluationSyncInfo.subjects = exam.subjects?.Select(x=>new IES.ExamServer.Models.SubjectExam { subjectId=x.id,subjectName=x.name,examId=id}).ToList();
  87. evaluationSyncInfo.dataTime= DateTimeOffset.Now.ToUnixTimeMilliseconds();
  88. evaluationSyncInfo.scode=exam.code;
  89. stime=exam.startTime;
  90. etime=exam.endTime;
  91. HashSet<string> grouplist = new HashSet<string>();
  92. if (exam.classes.IsNotEmpty()) {
  93. exam.classes.ForEach(x => { grouplist.Add(x); });
  94. }
  95. if (exam.stuLists.IsNotEmpty())
  96. {
  97. exam.stuLists.ForEach(x => { grouplist.Add(x); });
  98. }
  99. evaluationSyncInfo.grouplist=grouplist.ToList() ;
  100. evaluationSyncInfo.paperCount=exam.papers.IsNotEmpty()? exam.papers.Count():0;
  101. foreach (var group in exam.papers.GroupBy(x=>x.subjectId).Select(x=>new { key = x.Key,list= x.ToList()}))
  102. {
  103. var subject= exam.subjects.Find(x => x.id.Equals(group.key));
  104. if (subject!=null)
  105. {
  106. evaluationSyncInfo.subjects.Add(new IES.ExamServer.Models.SubjectExam {
  107. subjectId=subject.id,
  108. subjectName=subject.name,
  109. examId=id,
  110. papers= group.list.Select(x=>new SubjectExamPaper {paperId= x.id,paperName=x.name,blob=x.blob }).ToList(),
  111. } );
  112. EvaluationExam evaluationExam = new EvaluationExam()
  113. {
  114. examId=exam.id,
  115. evaluationId=evaluationSyncInfo.id,
  116. examName=evaluationSyncInfo.name,
  117. subjectId=subject.id,
  118. subjectName=subject.name,
  119. classes= evaluationSyncInfo.grouplist,
  120. owner=exam.owner,
  121. scope=scope,
  122. stime=stime,
  123. etime=etime,
  124. papers= group.list.Select(x => new EvaluationPaper { paperId= x.id, paperName=x.name, blob=x.blob, point=x.point,knowledge=x.knowledge,type=x.type,field=x.field }).ToList(),
  125. };
  126. evaluationExams.Add(evaluationExam);
  127. }
  128. }
  129. evaluationSource.exam=exam;
  130. }
  131. break;
  132. }
  133. case bool when (type == "Art"):
  134. {
  135. string code = $"Art-{ownerId}";
  136. var response = await azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).ReadItemStreamAsync(id, new PartitionKey(code));
  137. if (response.IsSuccessStatusCode)
  138. {
  139. ArtEvaluation art = JsonDocument.Parse(response.Content).RootElement.Deserialize<ArtEvaluation>();
  140. // evaluationSyncInfo.subjects = art.subjects?.Select(x => new IES.ExamServer.Models.SubjectExam { id=x.id, name=x.name, examId=id }).ToList();
  141. evaluationSyncInfo.name = art.name;
  142. evaluationSyncInfo.pid= art.pId;
  143. evaluationSyncInfo.scode=art.code;
  144. evaluationSyncInfo.dataTime = DateTimeOffset.Now.ToUnixTimeMilliseconds();
  145. HashSet<string> grouplist = new HashSet<string>();
  146. if (art.classes.IsNotEmpty())
  147. {
  148. art.classes.ForEach(x => { grouplist.Add(x); });
  149. }
  150. if (art.stuLists.IsNotEmpty())
  151. {
  152. art.stuLists.ForEach(x => { grouplist.Add(x); });
  153. }
  154. if (art.tchLists.IsNotEmpty())
  155. {
  156. art.tchLists.ForEach(x => { grouplist.Add(x); });
  157. }
  158. evaluationSyncInfo.grouplist=grouplist.ToList();
  159. evaluationSource.art=art;
  160. dataTime= art._ts*1000;
  161. stime=art.startTime;
  162. etime=art.endTime;
  163. var quota_22 = art.settings.Find(x => x.id.Equals("quota_21"));
  164. foreach (var item in quota_22.task)
  165. {
  166. if (!string.IsNullOrWhiteSpace(item.acId))
  167. {
  168. var subject = art.subjects.Find(x => x.id.Equals(item.subject));
  169. var examResponse= await azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).ReadItemStreamAsync(item.acId, new PartitionKey($"Exam-{ownerId}"));
  170. if (examResponse.IsSuccessStatusCode)
  171. {
  172. ExamInfo exam = JsonDocument.Parse(examResponse.Content).RootElement.Deserialize<ExamInfo>() ;
  173. var papers = exam.papers.FindAll(x => x.subjectId.Equals(item.subject));
  174. evaluationSyncInfo.subjects.Add(new IES.ExamServer.Models.SubjectExam
  175. {
  176. subjectId=item.subject,
  177. subjectName=subject.name,
  178. examId=item.acId,
  179. papers=papers?.Select(x => new SubjectExamPaper { paperId=x.id,paperName=x.name, blob=x.blob }).ToList(),
  180. });
  181. dataTime= dataTime<exam._ts*1000 ? exam._ts*1000 : dataTime;
  182. evaluationSource.artExams.Add(exam);
  183. EvaluationExam evaluationExam = new EvaluationExam()
  184. {
  185. examId=exam.id,
  186. evaluationId=evaluationSyncInfo.id,
  187. examName=evaluationSyncInfo.name,
  188. subjectId=subject.id,
  189. subjectName=subject.name,
  190. classes= evaluationSyncInfo.grouplist,
  191. owner=exam.owner,
  192. scope=scope,
  193. stime=stime,
  194. etime=etime,
  195. papers= papers.Select(x => new EvaluationPaper { paperId= x.id, paperName=x.name, blob=x.blob, point=x.point, knowledge=x.knowledge, type=x.type, field=x.field }).ToList(),
  196. };
  197. evaluationExams.Add(evaluationExam);
  198. }
  199. }
  200. }
  201. }
  202. }
  203. break;
  204. default:
  205. break;
  206. }
  207. if (evaluationSyncInfo.subjects.IsNotEmpty() && evaluationSyncInfo.grouplist.IsNotEmpty())
  208. {
  209. long blobTime =-1;
  210. long blobSize = 0;
  211. long blobCount = 0;
  212. if (!string.IsNullOrWhiteSpace(evaluationSyncInfo.shortCode))
  213. {
  214. evaluationSyncInfo.shortCode = $"{MurmurHash3.Hash32(evaluationSyncInfo.id)}";
  215. }
  216. var listInfo = await GroupListService.GetMemberByListids(_coreAPIHttpService, azureCosmos.GetCosmosClient(), _dingDing, evaluationSyncInfo.grouplist, schoolCode);
  217. evaluationSyncInfo.studentCount = listInfo.rmembers.Count();
  218. evaluationSyncInfo.paperCount =evaluationSyncInfo.subjects.Select(x => x.papers).Count();
  219. var client = azureStorage.GetBlobContainerClient(ownerId);
  220. foreach (var subject in evaluationSyncInfo.subjects)
  221. {
  222. var evaluationExam = evaluationExams.FindAll(x => x.subjectId.Equals(subject.subjectId)).FirstOrDefault();
  223. foreach (var paper in subject.papers)
  224. {
  225. List<BlobHashInfo> blobs = new List<BlobHashInfo>();
  226. try
  227. {
  228. await foreach (BlobItem blobItem in client.GetBlobsAsync(BlobTraits.None, BlobStates.None, paper.blob))
  229. {
  230. var lastModified = blobItem.Properties.LastModified;
  231. if (lastModified.HasValue)
  232. {
  233. lastModified.Value.ToUnixTimeMilliseconds();
  234. }
  235. var hash = blobItem.Properties.ContentHash;
  236. var path = blobItem.Name;
  237. var size = blobItem.Properties.ContentLength;
  238. blobs.Add(new BlobHashInfo
  239. {
  240. hash = Md5Hash.GetbyteToString(hash),
  241. last = lastModified.HasValue ? lastModified.Value.ToUnixTimeMilliseconds() : 0,
  242. path = path,
  243. size = size.HasValue ? size.Value : 0
  244. });
  245. };
  246. var evaluationPaper= evaluationExam.papers.Find(x => x.paperId.Equals(paper.paperId));
  247. evaluationPaper.blobs=blobs;
  248. }
  249. catch
  250. {
  251. }
  252. long lastTime = blobs.Max(x => x.last);
  253. blobTime= lastTime>blobTime?lastTime:blobTime;
  254. if (blobs.IsNotEmpty())
  255. {
  256. blobSize+=blobs.Sum(x => x.size);
  257. blobCount+=blobs.Count;
  258. var order = blobs.OrderBy(x => $"{x.path}-{x.hash}-{x.size}-{x.last}");
  259. string blobStr = string.Join(",", order.Select(x=> $"{x.path}-{x.hash}-{x.size}-{x.last}"));
  260. // 计算hash,校准路径,文件hash,文件大小,最后修改时间
  261. paper.paperHash= ShaHashHelper.GetSHA1(blobStr);
  262. }
  263. }
  264. }
  265. evaluationSyncInfo.blobTime = blobTime> evaluationSyncInfo.blobTime ? blobTime : evaluationSyncInfo.blobTime;
  266. evaluationSyncInfo.blobSize = blobSize;
  267. evaluationSyncInfo.blobCount = blobCount;
  268. evaluationSyncInfo.blobLastHash = evaluationSyncInfo.blobHash;
  269. evaluationSyncInfo.blobHash = ShaHashHelper.GetSHA1(string.Join("-", evaluationSyncInfo.subjects.SelectMany(x => x.papers).Select(x => x.paperHash)));
  270. evaluationSyncInfo.dataTime = dataTime.Value;
  271. evaluationSource.updateTime = dataTime.Value;
  272. var groupList = new { members = listInfo.rmembers, groupList = listInfo.groups };
  273. {
  274. //计算数据的hash值
  275. StringBuilder groupListData = new StringBuilder();
  276. //名单的hash值
  277. var orderList = listInfo.groups.OrderBy(x => x.id);
  278. foreach (var item in orderList)
  279. {
  280. groupListData.Append($"{item.id}-{item.name}");
  281. var orderMembers = item.members.OrderBy(x => x.id);
  282. foreach (var member in orderMembers)
  283. {
  284. groupListData.Append($"{member.id}-{member.name}");
  285. }
  286. }
  287. evaluationSyncInfo.grouplistHash= ShaHashHelper.GetSHA1(groupListData.ToString());
  288. var order= evaluationSyncInfo.subjects.OrderBy(x => x.subjectId);
  289. StringBuilder dataStr = new StringBuilder();
  290. dataStr.Append(evaluationSyncInfo.id);
  291. dataStr.Append(evaluationSyncInfo.name);
  292. dataStr.Append(evaluationSyncInfo.type);
  293. dataStr.Append(evaluationSyncInfo.owner);
  294. dataStr.Append(evaluationSyncInfo.ow);
  295. dataStr.Append(evaluationSyncInfo.scode);
  296. dataStr.Append(evaluationSyncInfo.scope);
  297. dataStr.Append(evaluationSyncInfo.grouplistHash);
  298. dataStr.Append(evaluationSyncInfo.blobHash);
  299. dataStr.Append(evaluationSyncInfo.shortCode);
  300. dataStr.Append($"{stime}{etime}");
  301. dataStr.Append(string.Join("", order.Select(x=>x.subjectId)));
  302. //计算dataHash
  303. evaluationSyncInfo.dataHash = ShaHashHelper.GetSHA1(dataStr.ToString());
  304. }
  305. evaluationClient= new EvaluationClient
  306. {
  307. id = evaluationSyncInfo.id,
  308. pid = evaluationSyncInfo.pid,
  309. name = evaluationSyncInfo.name,
  310. type = evaluationSyncInfo.type,
  311. owner = evaluationSyncInfo.owner,
  312. scode = evaluationSyncInfo.scode,
  313. scope = evaluationSyncInfo.scope,
  314. subjects = evaluationSyncInfo.subjects,
  315. dataTime = evaluationSyncInfo.dataTime,
  316. dataSize = evaluationSyncInfo.dataSize,
  317. blobTime = evaluationSyncInfo.blobTime,
  318. blobSize = evaluationSyncInfo.blobSize,
  319. blobCount = evaluationSyncInfo.blobCount,
  320. blobHash = evaluationSyncInfo.blobHash,
  321. blobLastHash = evaluationSyncInfo.blobLastHash,
  322. webviewCount = evaluationSyncInfo.webviewCount,
  323. webviewPath = evaluationSyncInfo.webviewPath,
  324. webviewSize = evaluationSyncInfo.webviewSize,
  325. webviewTime = evaluationSyncInfo.webviewTime,
  326. studentCount = evaluationSyncInfo.studentCount,
  327. paperCount = evaluationSyncInfo.paperCount,
  328. grouplist = evaluationSyncInfo.grouplist,
  329. shortCode = evaluationSyncInfo.shortCode,
  330. stime=stime,
  331. etime=etime,
  332. dataHash = evaluationSyncInfo.dataHash,
  333. grouplistHash = evaluationSyncInfo.grouplistHash,
  334. ownerId = evaluationSyncInfo.ownerId,
  335. ownerPicture =evaluationSyncInfo.ownerPicture,
  336. ownerName = evaluationSyncInfo.ownerName,
  337. //password = evaluationSyncInfo.password,
  338. //recordUrl = evaluationSyncInfo.recordUrl
  339. };
  340. long dataSize = 0;
  341. string sourceJson = evaluationSource.ToJsonString();
  342. dataSize+= Encoding.UTF8.GetByteCount(sourceJson);
  343. string groupListJson = groupList.ToJsonString();
  344. dataSize+= Encoding.UTF8.GetByteCount(groupListJson);
  345. string evaluationJson = new { evaluationClient, evaluationExams }.ToJsonString().ToJsonString();
  346. dataSize+= Encoding.UTF8.GetByteCount(evaluationJson);
  347. string evaluationSyncInfoSJson = evaluationSyncInfo.ToJsonString();
  348. dataSize+= Encoding.UTF8.GetByteCount(evaluationSyncInfoSJson);
  349. evaluationClient.dataSize = dataSize;
  350. await azureStorage.GetBlobContainerClient(ownerId).UploadFileByContainer(sourceJson, $"package/{id}", "source.json");
  351. await azureStorage.GetBlobContainerClient(ownerId).UploadFileByContainer(groupListJson, $"package/{id}", "groupList.json");
  352. await azureStorage.GetBlobContainerClient(ownerId).UploadFileByContainer(new { evaluationClient, evaluationExams }.ToJsonString(), $"package/{id}", "evaluation.json");
  353. evaluationSyncInfo.dataSize = dataSize;
  354. //学校logo 下载到本地、
  355. await azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Normal).UpsertItemAsync<EvaluationSyncInfo>(evaluationSyncInfo, new PartitionKey("EvaluationSyncInfo"));
  356. // await azureStorage.GetBlobContainerClient(owner).UploadFileByContainer(evaluationSyncInfo.ToJsonString(), $"package/{id}", "syncinfo.json");
  357. }
  358. return evaluationSyncInfo;
  359. }
  360. }
  361. }