using IES.ExamLibrary.Models; using IES.ExamServer.DI; using IES.ExamServer.Filters; using IES.ExamServer.Helper; using IES.ExamServer.Helpers; using IES.ExamServer.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Hosting; using Microsoft.VisualBasic; using System; using System.Text.Json.Nodes; using System.Threading.Tasks; namespace IES.ExamServer.Controllers { [ApiController] [Route("student")] public class StudentController : BaseController { private readonly IConfiguration _configuration; private readonly IHttpClientFactory _httpClientFactory; private readonly IMemoryCache _memoryCache; private readonly ILogger _logger; private readonly CenterServiceConnectionService _connectionService; private readonly LiteDBFactory _liteDBFactory; private readonly DataQueue _dataQueue; public StudentController(ILogger logger, IConfiguration configuration, IHttpClientFactory httpClientFactory, IMemoryCache memoryCache, CenterServiceConnectionService connectionService, LiteDBFactory liteDBFactory, DataQueue dataQueue) { _logger = logger; _configuration=configuration; _httpClientFactory=httpClientFactory; _memoryCache=memoryCache; _connectionService=connectionService; _liteDBFactory=liteDBFactory; _dataQueue=dataQueue; } /// /// 学生提交音乐作答 /// /// /// [HttpPost("submit-music-ai-result")] [AuthToken("student")] public IActionResult SubmitMusicAIResult(JsonNode json) { int finished = int.Parse($"{json["finished"]}"); string evaluationId = $"{json["evaluationId"]}"; string taskId = $"{json["taskId"]}"; string questionId = $"{json["questionId"]}"; long costTime = int.Parse($"{json["costTime"]}"); string settingId = $"{json["settingId"]}"; var token = GetAuthTokenInfo(); EvaluationRoundSetting? setting = _liteDBFactory.GetLiteDatabase().GetCollection().FindOne(x => x.id!.Equals(settingId) && evaluationId.Equals(x.evaluationId) && x.activate==1); EvaluationClient? evaluationClient = _liteDBFactory.GetLiteDatabase().GetCollection().FindOne(x => evaluationId.Equals(x.id)); if (evaluationClient!=null && setting!=null && setting.activate==1) { string resultId = ShaHashHelper.GetSHA1(evaluationId+_connectionService?.serverDevice?.school?.id+token.id); EvaluationStudentResult studentResult = _liteDBFactory.GetLiteDatabase().GetCollection() .FindOne(x => resultId.Equals(x.id) && token.id.Equals(x.studentId) && evaluationId.Equals(x.evaluationId)); if (studentResult!=null) { long now = DateTimeOffset.Now.ToUnixTimeMilliseconds(); //判断开始时间 if ((setting.startline>0 && setting.startline>now)|| evaluationClient.stime>now) { //未到开始时间 return Ok(new { msg = "未到开始时间。", code = 1 }); } //判断截止时间 long deadline; if (setting.countdownType==2) { deadline= studentResult.startTime+setting.countdown; } else { deadline= setting.startline+setting.countdown; } deadline+= 10*60*1000;//漂移10分钟,允许学生延迟提交,但是前端页面显示的截止时间是准的,时间一到,可自动提交。 //已过截止时间 //if ((deadline>0&&deadline0) { var result = new EvaluationMusicAIResult() { id= ShaHashHelper.GetSHA1($"{evaluationId}{questionId}{taskId}{token.id}"), taskId = taskId, questionId = questionId, costTime = costTime, finished = finished, submitTime = now, questionName=!string.IsNullOrWhiteSpace(evaluationClient?.music?.questionName) ? evaluationClient.music.questionName : null, evaluationId=evaluationId, createTime=now, pushed=0//强制重新推送 }; studentResult.musicAIResult= result; if (_connectionService!.centerIsConnected) { result.pushed=1; studentResult.musicAIResult.pushed=1; } _liteDBFactory.GetLiteDatabase().GetCollection().Upsert(result); _liteDBFactory.GetLiteDatabase().GetCollection().Upsert(studentResult); return Ok(new { code = 200, studentResult = studentResult, msg = "提交成功!" }); } else { return Ok(new { msg = "提交失败,请检查参数。", code = 3 }); } } else { return Ok(new { msg = "未找到该学生的作答信息。", code = 4 }); } } else { return Ok(new { msg = "未匹配到正则开考的评测。", code = 5 }); } } /// /// 学生提交科目作答 /// /// /// [HttpPost("submit-subject-result")] [AuthToken("student")] public async Task SubmitSubjectResult(JsonNode json) { List>? answers = json["answer"]?.ToObject>>(); string evaluationId = $"{json["evaluationId"]}"; string examId = $"{json["examId"]}"; string subjectId = $"{json["subjectId"]}"; string paperId = $"{json["paperId"]}"; long costTime = int.Parse($"{json["costTime"]}"); string settingId = $"{json["settingId"]}"; var token = GetAuthTokenInfo(); EvaluationRoundSetting? setting = _liteDBFactory.GetLiteDatabase().GetCollection().FindOne(x => x.id!.Equals(settingId) && evaluationId.Equals(x.evaluationId) && x.activate==1); EvaluationClient? evaluationClient = _liteDBFactory.GetLiteDatabase().GetCollection().FindOne(x=>evaluationId.Equals(x.id)); if (evaluationClient!=null && setting!=null && setting.activate==1) { string resultId = ShaHashHelper.GetSHA1(evaluationId+_connectionService?.serverDevice?.school?.id+token.id); EvaluationStudentResult studentResult = _liteDBFactory.GetLiteDatabase().GetCollection() .FindOne(x => resultId.Equals(x.id) && token.id.Equals(x.studentId) && evaluationId.Equals(x.evaluationId)); if (studentResult!=null) { long now = DateTimeOffset.Now.ToUnixTimeMilliseconds(); //判断开始时间 if ((setting.startline>0 && setting.startline>now)|| evaluationClient.stime>now) { //未到开始时间 return Ok(new { msg = "未到开始时间。", code = 1 }); } //判断截止时间 long deadline; if (setting.countdownType==2) { deadline= studentResult.startTime+setting.countdown; } else { deadline= setting.startline+setting.countdown; } deadline+= 10*60*1000;//漂移10分钟,允许学生延迟提交,但是前端页面显示的截止时间是准的,时间一到,可自动提交。 //已过截止时间 //if ((deadline>0&&deadline examId.Equals(x.examId)&& subjectId.Equals(x.subjectId)); var papers= subjectExams.FirstOrDefault()?.papers.FindAll(x => paperId.Equals(x.paperId)); if (papers.IsNotEmpty()) { if (answers!.Count()!=papers!.First()?.questionCount) { return Ok(new { msg = "提交的答案数量与试卷题目数量不匹配。", code = 5 }); } } string subjectResultId = ShaHashHelper.GetSHA1(evaluationClient.id+examId+subjectId+token.id); var subjectResult = studentResult.subjectResults.Where(x => subjectResultId.Equals(x.id) && subjectId.Equals(x.subjectId) && examId.Equals(x.examId) && paperId.Equals(x.paperId)).FirstOrDefault(); EvaluationSubjectResult result = new EvaluationSubjectResult() { id = subjectResultId, evaluationId = evaluationId, examId = examId, examName = subjectResult?.examName, subjectId = subjectId, subjectName = subjectResult?.subjectName, paperId =paperId, paperName = subjectResult?.paperName, createTime=now, finished=1, costTime=costTime, submitTime=now, answers=answers, questionCount=papers.IsNotEmpty() ? papers!.First().questionCount : 0, pushed=0//强制重新推送 }; if (subjectResult!=null) { subjectResult.answers=answers; subjectResult.finished=1; subjectResult.costTime=costTime; subjectResult.submitTime=now; subjectResult.pushed=0;//强制重新推送 } else { studentResult.subjectResults.Add(result); } if (_connectionService!.centerIsConnected) { result.pushed=1; if (subjectResult!=null) { subjectResult!.pushed=1; } await _dataQueue.TryAddAsync(new SubjectPushData(result, studentResult)); } _liteDBFactory.GetLiteDatabase().GetCollection().Upsert(result); _liteDBFactory.GetLiteDatabase().GetCollection().Upsert(studentResult); } } return Ok(new { code = 200, studentResult = studentResult, msg = "提交成功!" }); } else { return Ok(new { msg = "未找到该学生的作答信息。", code = 4}); } } else { return Ok(new { msg = "未匹配到正则开考的评测。", code = 3 }); } } /// /// 获取学生当前考试的作答信息。 /// /// /// [HttpPost("load-evaluation-result")] [AuthToken("student")] public IActionResult LoadEvaluationResult(JsonNode json) { string evaluationId = $"{json["evaluationId"]}"; var token = GetAuthTokenInfo();//6af32bbd-144e-4366-8bc0-61ba4c85677c string resultId = ShaHashHelper.GetSHA1(evaluationId+_connectionService?.serverDevice?.school?.id+token.id); string? scoolId = _connectionService?.serverDevice?.school?.id; EvaluationStudentResult studentResult = _liteDBFactory.GetLiteDatabase().GetCollection() .FindOne(x=> resultId.Equals(x.id) && !string.IsNullOrWhiteSpace(x.schoolId) && x.schoolId.Equals(scoolId)&& token.id.Equals(x.studentId) && evaluationId.Equals(x.evaluationId)); if (studentResult!=null) { //标记开始作答 if (studentResult.finished<1) { studentResult.finished=1; } if (studentResult.startTime<=0) { studentResult.startTime=DateTimeOffset.Now.ToUnixTimeMilliseconds(); } _liteDBFactory.GetLiteDatabase().GetCollection().Update(studentResult); return Ok(new { code = 200, studentResult = studentResult }); } else { return Ok(new { msg = "未找到该学生的作答信息。", code = 404}); } } /// /// 登录 /// /// /// [HttpPost("login")] public IActionResult Login(JsonNode json) { string studentId = $"{json["studentId"]}"; string studentName = $"{json["studentName"]}"; string evaluationId = $"{json["evaluationId"]}"; string settingId = $"{json["settingId"]}"; EvaluationRoundSetting? setting = _liteDBFactory.GetLiteDatabase().GetCollection().FindOne(x => x.id!.Equals(settingId) && evaluationId.Equals(x.evaluationId) && x.activate==1); EvaluationClient? evaluationClient = null; if (setting!=null) { evaluationClient = _liteDBFactory.GetLiteDatabase().GetCollection().FindOne(x => x.id!.Equals(setting.evaluationId)); if (evaluationClient!=null) { //检查是否在作答时间内 (code, msg)= CheckActivate(evaluationClient, setting); if (code==200) { long time = DateTimeOffset.Now.ToUnixTimeMilliseconds(); _memoryCache.TryGetValue(Constant._KeyServerDevice, out ServerDevice? server); School? school = null; ///获取名单文件,解析信息,应该在设置开考轮次的时候进行解析,并放在数据库中,并且在此时看是否是需要 分配试卷,还是在登录的时候获取试卷。 if (server!=null) { school = server.school; } EvaluationMember? member = _liteDBFactory.GetLiteDatabase().GetCollection().FindOne(x => studentId.Equals(x.id)&& studentName.Equals(x.name)); if (member!=null) { if (evaluationId.Equals(member.evaluationId)) { string x_auth_token = JwtAuthExtension.CreateAuthToken("www.teammodel.cn", studentId, studentName, picture: string.Empty, ExamConstant.JwtSecretKey, ExamConstant.ScopeStudent, 8, schoolID: school?.id, new string[] { "student" },expire: 1, year: member.year); return Ok(new { code = 200, x_auth_token = x_auth_token }); } else { return Ok(new { msg = "当前考试未添加该学生!", code = 7 }); } } else { return Ok(new { msg = "学者账号和姓名不匹配!", code = 1 }); } } else { return Ok(new { msg = msg, code = code }); } } else { return Ok(new { msg = "未找到考试设置。", code = 6 }); } } else { return Ok(new { msg = "未找到考试设置。", code = 2 }); } } /// /// 学生端获取激活的考试 /// /// /// [HttpPost("get-activate-evaluation")] public IActionResult GetActivateEvaluation(JsonNode json) { // _connectionService.serverDevice.school.id? try { IEnumerable? settings = _liteDBFactory.GetLiteDatabase().GetCollection().Find(x =>x.activate==1 ); if (settings != null && settings.Count() > 0) { if (settings.Count()>1) { msg="有多个正在开考的评测,请监考教师重新设置开考评测。"; code=2; } else { EvaluationRoundSetting? setting = settings.First(); ; EvaluationClient evaluationClient = _liteDBFactory.GetLiteDatabase().GetCollection().FindOne(x => x.id ==setting.evaluationId); if (evaluationClient!=null) { (code ,msg)= CheckActivate(evaluationClient, setting); var anonymousObject = new Dictionary(); var properties = evaluationClient.GetType().GetProperties(); foreach (var property in properties) { if (!property.Name.Equals("shortCode") && !property.Name.Equals("openCode")) { anonymousObject[property.Name] = property.GetValue(evaluationClient); } } return Ok(new { evaluationClient = anonymousObject, code = code, msg = msg, setting }); } else { msg="未找到评测信息。"; code=6; } //foreach (var subject in evaluationClient.subjects) //{ // foreach (var paper in subject.papers) // { // paper.blob=$"package/{evaluationClient.id}/papers/{paper.paperId}"; // } //} } } else { msg="暂无正在开考的评测"; code=1; } } catch (Exception ex) { } return Ok(new { msg ,code}); } private (int code, string msg) CheckActivate(EvaluationClient evaluationClient, EvaluationRoundSetting setting) { code = 200; if (evaluationClient.scope!.Equals("school")) { if (!evaluationClient!.ownerId!.Equals($"{_connectionService.serverDevice?.school?.id}")) { msg="授权学校与评测归属学校不一致。"; code=3; } } //当前时间 long now = DateTimeOffset.Now.ToUnixTimeMilliseconds(); //if (setting.countdownType>0) //{ //} //else //{ //} if ((setting.startline>0 &&setting.startline>now) || evaluationClient.stime>now) { msg="评测暂未开始。"; code=4; } if ((setting.deadline>0 && setting.deadline