ManageController.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. using IES.ExamLib.Models;
  2. using IES.ExamServer.DI;
  3. using IES.ExamServer.DI.SignalRHost;
  4. using IES.ExamServer.Filters;
  5. using IES.ExamServer.Helper;
  6. using IES.ExamServer.Models;
  7. using Microsoft.AspNetCore.Mvc;
  8. using Microsoft.Extensions.Caching.Memory;
  9. using Microsoft.Extensions.Configuration;
  10. using System.Linq.Expressions;
  11. using System.Net.Http;
  12. using System.Text.Json;
  13. using System.Text.Json.Nodes;
  14. namespace IES.ExamServer.Controllers
  15. {
  16. [ApiController]
  17. [Route("manage")]
  18. public class ManageController:BaseController
  19. {
  20. private readonly IConfiguration _configuration;
  21. private readonly IHttpClientFactory _httpClientFactory;
  22. private readonly IMemoryCache _memoryCache;
  23. private readonly ILogger<ManageController> _logger;
  24. private readonly LiteDBFactory _liteDBFactory;
  25. private readonly DataCenterConnectionService _connectionService;
  26. private readonly int DelayMicro = 10;//微观数据延迟
  27. private readonly int DelayMacro = 100;//宏观数据延迟
  28. private readonly SignalRExamServerHub _signalRExamServerHub;
  29. public ManageController(LiteDBFactory liteDBFactory,ILogger<ManageController> logger, IConfiguration configuration,
  30. IHttpClientFactory httpClientFactory, IMemoryCache memoryCache, DataCenterConnectionService connectionService,SignalRExamServerHub signalRExamServerHub)
  31. {
  32. _logger = logger;
  33. _configuration=configuration;
  34. _httpClientFactory=httpClientFactory;
  35. _memoryCache=memoryCache;
  36. _liteDBFactory=liteDBFactory;
  37. _connectionService=connectionService;
  38. _signalRExamServerHub=signalRExamServerHub;
  39. }
  40. [HttpPost("download-package")]
  41. [AuthToken("admin","teacher")]
  42. public async Task<IActionResult> DownloadPackage(JsonNode json)
  43. {
  44. //C#.NET 6 后端与前端流式通信
  45. //https://www.doubao.com/chat/collection/687687510791426?type=Thread
  46. //下载日志记录:1.步骤,检查,2.获取描述信息,3.分类型,4下载文件,5.前端处理,6.返回结果 , 正在下载...==> [INFO]https://www.doubao.com/chat/collection/687687510791426?type=Thread [Size=180kb] Ok...
  47. //进度条 展示下载文件总大小和已下载,末尾展示 文件总个数和已下载个数
  48. return Ok();
  49. }
  50. [HttpPost("check-short-code")]
  51. public async Task<IActionResult> CheckShortCode(JsonNode json)
  52. {
  53. string shortCode = $"{json["shortCode"]}";
  54. string evaluationId = $"{json["evaluationId"]}";
  55. Expression<Func<EvaluationClient, bool>> predicate = x => true;
  56. if (!string.IsNullOrEmpty(shortCode))
  57. {
  58. var codePredicate = ExpressionHelper.Or<EvaluationClient>(
  59. x => !string.IsNullOrWhiteSpace(x.shortCode) && x.shortCode == shortCode,
  60. x => !string.IsNullOrWhiteSpace(x.password) && x.password == shortCode
  61. );
  62. predicate= predicate.And(codePredicate);
  63. }
  64. else {
  65. return Ok(new { code = 400,msg="必须输入开卷码" });
  66. }
  67. if (!string.IsNullOrWhiteSpace(evaluationId))
  68. {
  69. predicate= predicate.And(x => x.id!.Equals(evaluationId));
  70. }
  71. IEnumerable<EvaluationClient> evaluationClients = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().Find(predicate);
  72. EvaluationClient? evaluationLocal = null;
  73. EvaluationClient? evaluationCloud = null;
  74. if (evaluationClients.Count()>0)
  75. {
  76. evaluationLocal= evaluationClients.First();
  77. }
  78. //如果要访问中心,则需要教师登录联网。
  79. var token = GetAuthTokenInfo();
  80. if (token.scope.Equals(ExamConstant.ScopeTeacher))
  81. {
  82. if ( _connectionService.dataCenterIsConnected)
  83. {
  84. Teacher teacher= _liteDBFactory.GetLiteDatabase().GetCollection<Teacher>().FindOne(x => x.id!.Equals(token.id));
  85. string? CenterUrl = _configuration.GetValue<string>("ExamServer:CenterUrl");
  86. var client = _httpClientFactory.CreateClient();
  87. if (client.DefaultRequestHeaders.Contains(Constant._X_Auth_AuthToken))
  88. {
  89. client.DefaultRequestHeaders.Remove(Constant._X_Auth_AuthToken);
  90. }
  91. client.DefaultRequestHeaders.Add(Constant._X_Auth_AuthToken, teacher.x_auth_token);
  92. HttpResponseMessage message = await client.PostAsJsonAsync($"{CenterUrl}/evaluation-sync/find-sync-info",new { shortCode, evaluationId });
  93. if (message.IsSuccessStatusCode)
  94. {
  95. string content = await message.Content.ReadAsStringAsync();
  96. JsonNode? jsonNode =JsonSerializer.Deserialize<JsonNode>(content);
  97. if (jsonNode!=null)
  98. {
  99. evaluationCloud= JsonSerializer.Deserialize<EvaluationClient>(jsonNode["evaluation"]);
  100. }
  101. }
  102. }
  103. }
  104. //数据,文件,页面 0 没有更新,1 有更新
  105. int data = 0,blob=0,webview=0,status=0;
  106. long dataSize = 0, blobSize=0 , webviewSize=0;
  107. if (evaluationLocal== null && evaluationCloud==null)
  108. {
  109. //线上线下没有数据
  110. status=1;
  111. }
  112. else if (evaluationLocal!=null && evaluationCloud!=null)
  113. {
  114. //线上线下有数据
  115. status = 2;
  116. if ((!string.IsNullOrWhiteSpace(evaluationLocal.blobHash) && !evaluationLocal.blobHash.Equals(evaluationCloud.blobHash))
  117. ||(evaluationLocal.blobTime<evaluationCloud.blobTime)
  118. ||(evaluationLocal.blobCount!= evaluationCloud.blobCount)
  119. ||(evaluationLocal.blobSize!= evaluationCloud.blobSize))
  120. {
  121. blob=1;
  122. blobSize=evaluationCloud.blobSize;
  123. }
  124. if ((evaluationLocal.dataTime<evaluationCloud.dataTime)
  125. ||(evaluationLocal.dataSize!=evaluationCloud.dataSize))
  126. {
  127. data=1;
  128. dataSize=evaluationCloud.dataSize;
  129. }
  130. if ((evaluationLocal.webviewCount!=evaluationCloud.webviewCount)
  131. ||(evaluationLocal.webviewSize!= evaluationCloud.webviewSize)
  132. ||(evaluationLocal.webviewTime!= evaluationCloud.webviewTime)
  133. ||(!string.IsNullOrWhiteSpace(evaluationLocal.webviewPath)&& !evaluationLocal.webviewPath.Equals(evaluationCloud.webviewPath)))
  134. {
  135. webview=1;
  136. webviewSize=evaluationCloud.webviewSize;
  137. }
  138. }
  139. else if (evaluationLocal!=null && evaluationCloud==null)
  140. {
  141. //线下有数据,线上没有数据,可能没联网。
  142. status = 3;
  143. }
  144. else if (evaluationLocal==null && evaluationCloud!=null)
  145. {
  146. //线下没有数据,线上有数据
  147. evaluationLocal= evaluationCloud;
  148. blob=1;
  149. data=1;
  150. webview=1;
  151. blobSize=evaluationCloud.blobSize;
  152. dataSize=evaluationCloud.dataSize;
  153. webviewSize=evaluationCloud.webviewSize;
  154. status = 4;
  155. _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().Insert(evaluationLocal);
  156. }
  157. List<int> file_intact = new List<int>();
  158. if (evaluationLocal!=null)
  159. {
  160. //校验本地文件数据
  161. string packagePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "package");
  162. if (!Directory.Exists(packagePath))
  163. Directory.CreateDirectory(packagePath);
  164. string evaluationPath = Path.Combine(packagePath, evaluationLocal.id!);
  165. await Task.Delay(DelayMacro);
  166. if (!System.IO.File.Exists(Path.Combine(evaluationPath, "evaluation.json")))
  167. {
  168. file_intact.Add(0);
  169. }
  170. await Task.Delay(DelayMacro);
  171. if (!System.IO.File.Exists(Path.Combine(evaluationPath, "groupList.json")))
  172. {
  173. file_intact.Add(0);
  174. }
  175. await Task.Delay(DelayMacro);
  176. if (!System.IO.File.Exists(Path.Combine(evaluationPath, "source.json")))
  177. {
  178. file_intact.Add(0);
  179. }
  180. await Task.Delay(DelayMacro);
  181. }
  182. return Ok(new {code=200, evaluation= evaluationLocal,data,blob,webview,dataSize,blobSize,webviewSize,status });
  183. }
  184. /// <summary>
  185. /// 激活考试
  186. /// </summary>
  187. /// <param name="json"></param>
  188. /// <returns></returns>
  189. [HttpPost("activate-evaluation")]
  190. public IActionResult ActivateEvaluation(JsonNode json)
  191. {
  192. string id = $"{json["id"]}";
  193. string shortCode = $"{json["shortCode"]}";
  194. if (!string.IsNullOrWhiteSpace(id) && !string.IsNullOrWhiteSpace(shortCode))
  195. {
  196. EvaluationClient evaluationClient = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().FindOne(x => x.id!.Equals(id) && !string.IsNullOrWhiteSpace(x.shortCode) && x.shortCode.Equals(shortCode));
  197. if (evaluationClient != null)
  198. {
  199. }
  200. }
  201. return Ok();
  202. }
  203. /// <summary>
  204. /// 加载本地的活动列表
  205. /// </summary>
  206. /// <param name="json"></param>
  207. /// <returns></returns>
  208. [HttpPost("list-local-evaluation")]
  209. public IActionResult ListLocalEvaluation(JsonNode json)
  210. {
  211. IEnumerable<EvaluationClient> evaluationClients = _liteDBFactory.GetLiteDatabase().GetCollection<EvaluationClient>().FindAll().OrderByDescending(x=>x.activate).ThenByDescending(x=>x.stime);
  212. var result = evaluationClients.Select(client =>
  213. {
  214. var properties = client.GetType().GetProperties();
  215. var anonymousObject = new Dictionary<string, object?>();
  216. foreach (var property in properties)
  217. {
  218. if (!property.Name .Equals("password") && !property.Name.Equals("shortCode"))
  219. {
  220. anonymousObject[property.Name] = property.GetValue(client);
  221. }
  222. }
  223. return anonymousObject;
  224. });
  225. return Ok(new {code=200, evaluation= result });
  226. }
  227. }
  228. }