123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 |
- using Azure.Messaging.ServiceBus;
- using Azure.Storage.Blobs.Models;
- using Azure;
- using Microsoft.Azure.Cosmos;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Security.Cryptography;
- using System.Text;
- using System.Text.Json;
- using System.Threading.Tasks;
- using TEAMModelOS.SDK.DI;
- using TEAMModelOS.SDK.Extension;
- using TEAMModelOS.SDK.Models.Service.BI;
- using TEAMModelOS.SDK.Services;
- using static TEAMModelOS.SDK.Models.JointEventGroupBase;
- using Azure.Core;
- using Microsoft.Extensions.Configuration;
- namespace TEAMModelOS.SDK.Models.Service
- {
- public static class JointService
- {
- //取得JointExam生成Exam
- public static async Task GenerateExamFromJointExamAsync(CosmosClient client, AzureStorageFactory _azureStorage, AzureServiceBusFactory _serviceBus, CoreAPIHttpService _coreAPIHttpService, AzureRedisFactory _azureRedis, IConfiguration _configuration, DingDing _dingDing, JointExam jointExam)
- {
- try
- {
- long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
- //取得JointExam
- List<JointEventClassBase> classes = new List<JointEventClassBase>();
- List<JointEventGroupBase> stuLists = new List<JointEventGroupBase>();
- //取得JointCourse ※examType == "custom" 之後再處理
- List<JointEventGroupDb> jointCourses = new List<JointEventGroupDb>();
- if (!jointExam.examType.Equals("custom"))
- {
- string jointCourseSql = $"SELECT * FROM c WHERE c.jointEventId = '{jointExam.jointEventId}' AND c.jointGroupId = '{jointExam.jointGroupId}'";
- await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher").GetItemQueryIteratorSql<JointEventGroupDb>(queryText: jointCourseSql, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"JointCourse") }))
- {
- jointCourses.Add(item);
- }
- }
- //評量資料生成 ExamInfo actExamInfo ※一個課程一個Exam
- List<ExamInfo> examList = new List<ExamInfo>();
- foreach (JointEventGroupDb jointCourse in jointCourses)
- {
- string actExamCreatorId = jointCourse.creatorId;
- //個人課程
- if(jointCourse.scope.Equals("private"))
- {
- foreach (JointEventGroupCourse jointExamGroupCourse in jointCourse.courseLists)
- {
- string actExamCourseId = jointExamGroupCourse.courseId;
- string actExamCourseName = jointExamGroupCourse.courseName;
- //評量資料生成
- ExamInfo actExamInfo = new ExamInfo();
- ///取得已生成的Exam ※
- string examSql = $"SELECT DISTINCT c.id, c.source, c.name, c.jointExamId, c.subjects, c.stuLists, c.targets, c.papers, c.year, c.startTime, c.endTime FROM c JOIN s IN c.subjects WHERE c.jointExamId = '{jointExam.id}' AND s.id = '{actExamCourseId}'";
- await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher").GetItemQueryIteratorSql<ExamInfo>(queryText: examSql, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Exam-{actExamCreatorId}") }))
- {
- actExamInfo = item;
- }
- ///尚無評量資料
- if (string.IsNullOrWhiteSpace(actExamInfo.id))
- {
- actExamInfo.code = $"Exam-{actExamCreatorId}";
- actExamInfo.owner = "teacher";
- actExamInfo.scope = jointCourse.scope;
- actExamInfo.creatorId = actExamCreatorId;
- actExamInfo.id = Guid.NewGuid().ToString();
- }
- actExamInfo.source = jointExam.source;
- actExamInfo.name = jointExam.name;
- actExamInfo.jointExamId = jointExam.id;
- actExamInfo.subjects = new List<ExamSubject>() { new ExamSubject() { id = actExamCourseId, name = actExamCourseName, classCount = jointExamGroupCourse.groupLists.Count } };
- ///評量stuLists
- foreach (JointEventGroupCourseGroup actGroup in jointExamGroupCourse.groupLists)
- {
- if(!actExamInfo.stuLists.Contains(actGroup.id))
- {
- actExamInfo.stuLists.Add(actGroup.id);
- }
- List<string> targetRow = new List<string>() { actExamCourseId, actGroup.id };
- var targetRowJson = JsonSerializer.SerializeToElement(targetRow);
- if(!actExamInfo.targets.Contains(targetRowJson))
- {
- actExamInfo.targets.Add(targetRowJson);
- }
- }
- ///試卷
- actExamInfo.papers = Newtonsoft.Json.JsonConvert.DeserializeObject<List<PaperSimple>>(Newtonsoft.Json.JsonConvert.SerializeObject(jointExam.papers));
- ///時間
- actExamInfo.year = DateTimeOffset.UtcNow.Year;
- actExamInfo.startTime = jointExam.startTime;
- actExamInfo.endTime = jointExam.endTime;
- examList.Add(actExamInfo);
- }
- }
- //[待做] 學校班級
- }
- //生成評量
- if (examList.Count > 0)
- {
- foreach (ExamInfo exam in examList)
- {
- await GenerateExam(client, _azureStorage, _serviceBus, _coreAPIHttpService, _azureRedis, _configuration, _dingDing, jointExam, exam);
- }
- }
- }
- catch (Exception)
- {
-
- }
- }
- //生成評量(單)
- private static async Task<string> GenerateExam(CosmosClient client, AzureStorageFactory _azureStorage, AzureServiceBusFactory _serviceBus, CoreAPIHttpService _coreAPIHttpService, AzureRedisFactory _azureRedis, IConfiguration _configuration, DingDing _dingDing, JointExam jointExam, ExamInfo exam)
- {
- long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
- string Result = string.Empty;
- exam.createTime = now;
- if (exam.startTime <= 0) exam.startTime = now;
- List<(string pId, List<string> gid)> ps = new();
- var group = exam.groupLists;
- if (group.Count > 0)
- {
- foreach (var keys in group)
- {
- foreach (KeyValuePair<string, List<string>> pp in keys)
- {
- ps.Add((pp.Key, pp.Value));
- }
- }
- }
- List<string> classes = ExamService.getClasses(exam.classes, exam.stuLists);
- (List<RMember> tchList, List<RGroupList> classLists) = await GroupListService.GetMemberByListids(_coreAPIHttpService, client, _dingDing, classes, exam.school, ps);
- exam.stuCount = tchList.Count;
- string mode = string.Empty;
- ResponseMessage response = null;
- if (string.IsNullOrEmpty(exam.id))
- {
- mode = "add";
- }
- else
- {
- response = await client.GetContainer("TEAMModelOS", "Common").ReadItemStreamAsync(exam.id, new PartitionKey($"{exam.code}"));
- if (response.StatusCode == System.Net.HttpStatusCode.OK) mode = "upd";
- else mode = "add";
- }
- //DB操作
- if (mode.Equals("add")) //新建
- {
- if (string.IsNullOrWhiteSpace(exam.id)) exam.id = Guid.NewGuid().ToString();
- exam.progress = (exam.startTime > now) ? "pending" : "going";
- var messageBlob = new ServiceBusMessage();
- if (exam.scope.Equals("school") && !string.IsNullOrWhiteSpace(exam.school))
- {
- exam.size = await _azureStorage.GetBlobContainerClient(exam.school).GetBlobsSize($"exam/{exam.id}");
- await BlobService.RefreshBlobRoot(new BlobRefreshMessage { progress = "insert", root = $"exam", name = exam.school }, _serviceBus, _configuration, _azureRedis);
- }
- else
- {
- exam.size = await _azureStorage.GetBlobContainerClient(exam.creatorId).GetBlobsSize($"exam/{exam.id}");
- await BlobService.RefreshBlobRoot(new BlobRefreshMessage { progress = "insert", root = $"exam", name = exam.creatorId }, _serviceBus, _configuration, _azureRedis);
- }
- int n = 0;
- List<string> sheetIds = new List<string>();
- foreach (PaperSimple simple in exam.papers)
- {
- simple.blob = $"/exam/{exam.id}/paper/{exam.subjects[n].id}";
- n++;
- simple.sheet = null;
- }
- exam = await client.GetContainer(Constant.TEAMModelOS, "Common").CreateItemAsync(exam, new PartitionKey($"{exam.code}"));
- await BIStats.SetTypeAddStats(client, _dingDing, exam.school, "Exam", 1);//BI统计增/减量
- }
- else if (response != null) //更新
- {
- using var json = await JsonDocument.ParseAsync(response.Content);
- ExamInfo info = json.ToObject<ExamInfo>();
- if (info.progress.Equals("going"))
- {
- Result = "活动正在进行中,无法修改";
- }
- var messageBlob = new ServiceBusMessage();
- if (exam.scope.Equals("school") && !string.IsNullOrWhiteSpace(exam.school))
- {
- exam.size = await _azureStorage.GetBlobContainerClient(exam.school).GetBlobsSize($"exam/{exam.id}");
- await BlobService.RefreshBlobRoot(new BlobRefreshMessage { progress = "update", root = $"exam", name = exam.school }, _serviceBus, _configuration, _azureRedis);
- }
- else
- {
- exam.size = await _azureStorage.GetBlobContainerClient(exam.creatorId).GetBlobsSize($"exam/{exam.id}");
- await BlobService.RefreshBlobRoot(new BlobRefreshMessage { progress = "update", root = $"exam", name = exam.creatorId }, _serviceBus, _configuration, _azureRedis);
- }
- exam.progress = info.progress;
- int n = 0;
- List<string> sheetIds = new List<string>();
- foreach (PaperSimple simple in exam.papers)
- {
- if (!string.IsNullOrEmpty(simple.subjectId))
- {
- simple.blob = $"/exam/{exam.id}/paper/{simple.subjectId}/{simple.id}";
- }
- else
- {
- simple.blob = $"/exam/{exam.id}/paper/{exam.subjects[n].id}";
- n++;
- }
- simple.sheet = null;
- }
- exam = await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(exam, exam.id, new PartitionKey($"{exam.code}"));
- }
- //Blob操作 ※取得試卷源(blob)、複製到評測紀錄下
- ///試卷源字典
- List<Dictionary<string, string>> sourcePaperInfo = new List<Dictionary<string, string>>();
- foreach (PaperSimple paperInfo in jointExam.papers)
- {
- string paperBlobPath = (!paperInfo.blob.EndsWith("/")) ? paperInfo.blob + "/" : paperInfo.blob;
- paperBlobPath = (paperInfo.blob.StartsWith("/")) ? paperBlobPath.Remove(0, 1) : paperBlobPath;
- sourcePaperInfo.Add(new Dictionary<string, string>() { { "id", paperInfo.id }, { "blob", paperBlobPath }, { "itemcount", paperInfo.point.Count.ToString() } });
- }
- bool paperDataCopyErrFlg = false; //試卷資料拷貝錯誤Flag true:拷貝錯誤
- //Blob拷貝程序
- int paperIndex = 0;
- foreach (Dictionary<string, string> sourcePaperInfoDic in sourcePaperInfo)
- {
- //拷貝源:Container => jointExam.creatorId Path:papers.blob
- //拷貝對象:Container => exam.creatorId, Path:exam/{exam.id}/paper/{exam.subjects[paperIndex].id}/
- string targetScope = exam.scope; //評測對象 school:校本班級 private:私人課程
- var sourceBlobContainer = _azureStorage.GetBlobContainerClient(jointExam.creatorId); //統測活動來源一定是個人
- var blobPrivateContainer = (targetScope.Equals("school")) ? _azureStorage.GetBlobContainerClient(exam.school) : _azureStorage.GetBlobContainerClient(exam.creatorId);
- string sourceBlobPath = sourcePaperInfoDic["blob"];
- string subjectId = exam.subjects[paperIndex].id;
- string destBlobPath = $"exam/{exam.id}/paper/{subjectId}/"; //拷貝對象路徑 path:exam/{評測ID}/paper/{subjectID}/
- Pageable<BlobItem> sourceBlobs = sourceBlobContainer.GetBlobs(prefix: sourceBlobPath);
- if (sourceBlobs.Count() > 0)
- {
- foreach (var blob in sourceBlobs)
- {
- var sourceFileBlob = sourceBlobContainer.GetBlobClient(blob.Name);
- if (sourceFileBlob.Exists())
- {
- var sourceFileUri = sourceBlobContainer.GetBlobClient(blob.Name).Uri;
- string fileName = blob.Name.Replace(sourceBlobPath, "");
- string destBlobFilePath = $"{destBlobPath}{fileName}";
- await blobPrivateContainer.GetBlobClient(destBlobFilePath).StartCopyFromUriAsync(sourceFileUri);
- }
- else
- {
- paperDataCopyErrFlg = true;
- }
- }
- }
- paperIndex++;
- }
- return Result;
- }
- }
- }
|