123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320 |
- using Microsoft.Azure.Cosmos;
- using Azure.Storage.Blobs.Models;
- using Azure.Storage.Sas;
- using Microsoft.AspNetCore.Authorization;
- using Microsoft.AspNetCore.Http;
- using Microsoft.AspNetCore.Mvc;
- using Microsoft.Extensions.Options;
- using System;
- using System.Collections.Generic;
- using System.IdentityModel.Tokens.Jwt;
- using System.IO;
- using System.Linq;
- using System.Text;
- using System.Text.Json;
- using System.Threading.Tasks;
- using TEAMModelOS.Models;
- using TEAMModelOS.Filter;
- using TEAMModelOS.SDK.DI;
- using TEAMModelOS.SDK.Extension;
- using TEAMModelOS.SDK.Models.Table;
- using TEAMModelOS.SDK.Models;
- using System.Dynamic;
-
- using StackExchange.Redis;
- using TEAMModelOS.SDK.Models.Cosmos.Common;
- using TEAMModelOS.SDK;
- using Microsoft.Extensions.Configuration;
- using Azure.Messaging.ServiceBus;
- using TEAMModelOS.SDK.Services;
- using TEAMModelOS.SDK.Models.Service;
- using TEAMModelOS.Models.Request;
- using Azure;
- using TEAMModelOS.Controllers.Both;
- using TEAMModelOS.SDK.Models.Cosmos.School;
- using Azure.Storage.Blobs;
- using HtmlAgilityPack;
- using System.Diagnostics;
- using TEAMModelOS.Models.Service;
- namespace TEAMModelOS.Controllers.Client
- {
- [ProducesResponseType(StatusCodes.Status200OK)]
- [ProducesResponseType(StatusCodes.Status400BadRequest)]
- //[Authorize(Roles = "HiTeach")]
- [Route("hiteach")]
- [ApiController]
- public class HiTeachController : ControllerBase
- {
- private readonly AzureStorageFactory _azureStorage;
- private readonly AzureRedisFactory _azureRedis;
- private readonly AzureCosmosFactory _azureCosmos;
- private readonly DingDing _dingDing;
- private readonly Option _option;
- private readonly SnowflakeId _snowflakeId;
- private readonly AzureServiceBusFactory _serviceBus;
- private readonly IConfiguration _configuration;
- private readonly CoreAPIHttpService _coreAPIHttpService;
- private readonly IPSearcher _searcher;
- private readonly HttpTrigger _httpTrigger;
- public HiTeachController(
- AzureStorageFactory azureStorage,
- AzureRedisFactory azureRedis,
- AzureCosmosFactory azureCosmos,
- DingDing dingDing,
- SnowflakeId snowflakeId,
- IOptionsSnapshot<Option> option,
- AzureServiceBusFactory serviceBus,
- IConfiguration configuration,
- CoreAPIHttpService coreAPIHttpService, IPSearcher searcher, HttpTrigger httpTrigger)
- {
- _azureStorage = azureStorage;
- _azureRedis = azureRedis;
- _azureCosmos = azureCosmos;
- _dingDing = dingDing;
- _snowflakeId = snowflakeId;
- _option = option?.Value;
- _serviceBus = serviceBus;
- _configuration = configuration;
- _coreAPIHttpService = coreAPIHttpService;
- _searcher = searcher;
- _httpTrigger = httpTrigger;
- }
- /// <summary>
- /// 更新课堂记录
- /// </summary>
- /// <param name="request"></param>
- /// <returns></returns>
- //[Authorize(Roles = "HiTeach")]
- [ProducesDefaultResponseType]
- [HttpPost("update-lesson-record")]
- public async Task<IActionResult> UpdateLessonRecord(JsonElement request)
- {
- var client = _azureCosmos.GetCosmosClient();
- if (!request.TryGetProperty("lesson_id", out JsonElement _lessonId)) return BadRequest();
- if (!request.TryGetProperty("tmdid", out JsonElement _tmdid)) return BadRequest();
- request.TryGetProperty("name", out JsonElement name);
- request.TryGetProperty("school", out JsonElement _school);
- if (!request.TryGetProperty("scope", out JsonElement _scope)) return BadRequest();
- request.TryGetProperty("grant_types", out JsonElement _grant_types);
- string tbname;
- string code;
- if (_scope.GetString().Equals("school") && !string.IsNullOrWhiteSpace(_school.GetString()))
- {
- code = $"LessonRecord-{_school}";
- tbname = "School";
- }
- else if ($"{_scope}".Equals("private"))
- {
- code = $"LessonRecord";
- tbname = "Teacher";
- }
- else
- {
- return BadRequest();
- }
- try
- {
- LessonRecord lessonRecord = await client.GetContainer(Constant.TEAMModelOS, tbname).ReadItemAsync<LessonRecord>($"{_lessonId}", new PartitionKey(code));
- List<LessonUpdate> updates = new List<LessonUpdate>() { new LessonUpdate { grant_type = "up-base" } };
- if (_grant_types.ValueKind.Equals(JsonValueKind.Array))
- {
- updates = _grant_types.ToObject<List<LessonUpdate>>();
- if (!updates.Select(x => x.grant_type).Contains("up-base"))
- {
- updates.Add(new LessonUpdate { grant_type = "up-base" });
- }
- }
- if (!string.IsNullOrWhiteSpace($"{name}"))
- {
- lessonRecord.name = $"{name}";
- await client.GetContainer(Constant.TEAMModelOS, tbname).ReplaceItemAsync<LessonRecord>(lessonRecord, $"{_lessonId}", new PartitionKey(code));
- }
- var ActiveTask = _configuration.GetValue<string>("Azure:ServiceBus:ActiveTask");
- string msg = null;
- msg = new { lesson_id = $"{_lessonId}", tmdid = $"{_tmdid}", grant_types = updates, school = $"{_school}", scope = $"{_scope}" }.ToJsonString();
- var messageChange = new ServiceBusMessage(msg);
- messageChange.ApplicationProperties.Add("name", "LessonRecordEvent");
- //await _dingDing.SendBotMsg($"{_option.Location},课堂id:{_lessonId} 更新事件,{msg}", GroupNames.醍摩豆服務運維群組);
- await _serviceBus.GetServiceBusClient().SendMessageAsync(ActiveTask, messageChange);
- await LessonServiceIES.SetLearnRecordContent(_school, _tmdid, _lessonId, _scope, _azureCosmos, _azureStorage);
- return Ok(new { status = 200 });
- }
- catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
- {
- await _dingDing.SendBotMsg($"更新课堂记录出错\n{ex.StackTrace}{ex.Message}", GroupNames.成都开发測試群組);
- return BadRequest("课堂记录不存在");
- }
- catch (Exception ex)
- {
- await _dingDing.SendBotMsg($"更新课堂记录出错\n{ex.StackTrace}{ex.Message}", GroupNames.成都开发測試群組);
- return BadRequest();
- }
- }
- /// <summary>
- /// 產生指定日期區間的學習紀錄(包含學校課程、個人課程、評量)
- /// </summary>
- /// <param name="request"></param>
- /// <returns></returns>
- [Authorize(Roles = "HiTeach")]
- [ProducesDefaultResponseType]
- [HttpPost("run-lesson-LearnRecord")]
- public async Task<IActionResult> RunLessonLearnRecord(JsonElement request)
- {
- try
- {
- if (!request.TryGetProperty("startdate", out JsonElement _startdate)) return BadRequest();
- if (!request.TryGetProperty("enddate", out JsonElement _enddate)) return BadRequest();
- var client = _azureCosmos.GetCosmosClient();
- #region 學校課堂
- string sql = $"SELECT c.id, c.tmdid, c.school, c.scope FROM c WHERE CONTAINS(c.code,'LessonRecord-') and c.startTime > {_startdate} and c.startTime < {_enddate}";
- List<LessonRecordItemPart> LessonRecordItemPartList = new List<LessonRecordItemPart>();
- await foreach (var item in client.GetContainer(Constant.TEAMModelOS, Constant.School).GetItemQueryIteratorSql<LessonRecordItemPart>(queryText: sql))
- {
- LessonRecordItemPartList.Add(item);
- }
- foreach (LessonRecordItemPart lrip in LessonRecordItemPartList)
- {
- await SetLearnRecordContentForBatch(lrip.school, lrip.tmdid, lrip.id, lrip.scope, "0");
- }
- #endregion
- #region 個人課堂
- string sql2 = $"SELECT c.id, c.tmdid, c.school, c.scope FROM c WHERE c.code = 'LessonRecord' and c.startTime > {_startdate} and c.startTime < {_enddate}";
- List<LessonRecordItemPart> LessonRecordItemPartList2 = new List<LessonRecordItemPart>();
- await foreach (var item in client.GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetItemQueryIteratorSql<LessonRecordItemPart>(queryText: sql2))
- {
- LessonRecordItemPartList2.Add(item);
- }
- foreach (LessonRecordItemPart lrip in LessonRecordItemPartList2)
- {
- await SetLearnRecordContentForBatch("", lrip.tmdid, lrip.id, lrip.scope, "1");
- }
- #endregion
- #region 評量
- string sql3 = $"SELECT * FROM c WHERE CONTAINS(c.code,'Exam-') and c.endTime > {_startdate} and c.endTime < {_enddate}";
- await foreach (var item in client.GetContainer(Constant.TEAMModelOS, Constant.Common).GetItemQueryIteratorSql<ExamInfo>(queryText: sql3))
- {
- await SetLearnRecordContent(item, _azureStorage, _azureCosmos);
- }
- #endregion
- return Ok(new { status = 200 });
- }
- catch (Exception ex)
- {
- return BadRequest();
- }
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="info"></param>
- /// <param name="data"></param>
- /// <param name="_azureStorage"></param>
- /// <param name="_azureCosmos"></param>
- /// <returns></returns>
- private static async Task SetLearnRecordContent(ExamInfo info, AzureStorageFactory _azureStorage, AzureCosmosFactory _azureCosmos)
- {
- try
- {
- if (info.papers.Count > 0)
- {
- // Unix 时间戳的起始时间是 1970 年 1 月 1 日 00:00:00 UTC
- DateTime unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
- // 将 Unix 时间戳转换为 TimeSpan,并加到 Unix 起始时间上
- // 将时间戳转换为 DateTime
- DateTime dateTime = unixEpoch.AddMilliseconds(info.endTime);
- // 将 DateTime 格式化为 yyyyMMdd 格式的日期字符串
- string date_path = dateTime.ToString("yyyyMMdd");
- for (int i = 0; i < info.papers.Count; i++)
- {// 每一個科目的試卷
- string rootName = "";
- //if (info.school == "SYSTEM_NO_SCHOOL")
- if (info.scope == "private")
- {// 未入校老師的評量
- rootName = info.creatorId;
- }
- else
- {// 如果有學校代碼
- rootName = info.school;
- }
- if (_azureStorage.GetBlobContainerClient(rootName).GetBlobClient($"{info.papers[i].blob}/index.json").Exists())
- {// 如果試卷的blob存在,再開始
- BlobDownloadResult paperblobDownload = await _azureStorage.GetBlobContainerClient(rootName).GetBlobClient($"{info.papers[i].blob}/index.json").DownloadContentAsync();
- PaperIndex paperIndex = paperblobDownload.Content.ToObjectFromJson<PaperIndex>();
- List<LearnRecordItem> learnRecordItems = new();
- StringBuilder sbsql = new StringBuilder($" SELECT * FROM c WHERE c.examId = '{info.id}' and c.pk = 'ExamClassResult' and c.subjectId = '{info.subjects[i].id}' ");
- #region === 開始拼裝資料 ===
- //Debug.WriteLine("開始拼裝資料start ----" + DateTime.Now.ToLongTimeString());
- if (info.classes.Count > 0 || info.stuLists.Count > 0)
- {
- // 組合SQL
- if (info.classes.Count > 0)
- {// 按照classes取ans.json
- sbsql.Append($" and ARRAY_CONTAINS({System.Text.Json.JsonSerializer.Serialize(info.classes)}, c.info.id)");
- }
- else if (info.stuLists.Count > 0)
- {
- sbsql.Append($" and ARRAY_CONTAINS({System.Text.Json.JsonSerializer.Serialize(info.stuLists)}, c.info.id)");
- }
- // 取學生答案及學生名單
- var client = _azureCosmos.GetCosmosClient();
- Dictionary<string, List<string>> stuDic = new Dictionary<string, List<string>>();
- if (!string.IsNullOrWhiteSpace(info.school) && !stuDic.ContainsKey(info.school))
- {
- stuDic.Add(info.school, new List<string>());
- }
- List<StudentAnswers> studentAnswersList = new List<StudentAnswers>();
- List<string> stuListForSql = new List<string>();
- await foreach (var item in client.GetContainer(Constant.TEAMModelOS, Constant.Common).GetItemQueryIteratorSql<StudentAnswers>(queryText: sbsql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"ExamClassResult-{rootName}") }))
- {
- studentAnswersList.Add(item);
- stuListForSql = stuListForSql.Union(item.studentIds).ToList();
- }
- //取得學校的學生名單
- List<string> stuOpenIdList = new List<string>();
- if (!string.IsNullOrWhiteSpace(info.school))
- {
- StringBuilder stusql = new StringBuilder($"SELECT VALUE c.id FROM c WHERE c.pk = 'Base' AND ARRAY_CONTAINS({System.Text.Json.JsonSerializer.Serialize(stuListForSql)}, c.id)");
- await foreach (string item in client.GetContainer(Constant.TEAMModelOS, Constant.Student).GetItemQueryIteratorSql<string>(queryText: stusql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base-{info.school}") }))
- {
- stuDic[info.school].Add(item);
- }
- }
- // 按照取出的學生答案blob 對答案 組合資料
- foreach (var studentAnswers in studentAnswersList)
- {// 每一個班級
- foreach (var studentAnswersBlob in studentAnswers.studentAnswers)
- {// 每一個學生
- if (studentAnswersBlob.Count > 0)
- {// 有學生的答案才開始
- if (_azureStorage.GetBlobContainerClient(rootName).GetBlobClient($"/exam/{studentAnswersBlob[0]}").Exists())
- {// 如果blob存在才開始
- BlobDownloadResult ansblobDownload = await _azureStorage.GetBlobContainerClient(rootName).GetBlobClient($"/exam/{studentAnswersBlob[0]}").DownloadContentAsync();
- List<List<string>> ansList = Newtonsoft.Json.JsonConvert.DeserializeObject<List<List<string>>>(ansblobDownload.Content.ToString());
- // 從blob路徑取出學生id
- string[] arr = studentAnswersBlob[0].Split('/');
- string stuid = arr[arr.Length - 2];
- #region ===StartExam 開始評量===
- LearnRecordItem LRItem_StartExam = new();
- LRItem_StartExam.verb = "StartExam";
- LRItem_StartExam.actor = getStuId(info.school, stuid, stuDic);
- LRItem_StartExam.time = info.createTime;
- LRItem_StartExam.ID = info.id;
- LRItem_StartExam.Desc = info.name;
- LRItem_StartExam.Correct = null;
- LRItem_StartExam.Choices = null;
- LRItem_StartExam.ExamQuesQty = info.papers[i].point.Count;
- LRItem_StartExam.TotalScore = 0;
- foreach (var pointItem in info.papers[i].point)
- {
- LRItem_StartExam.TotalScore = LRItem_StartExam.TotalScore + pointItem;
- }
- LRItem_StartExam.Success = null;
- learnRecordItems.Add(LRItem_StartExam);
- #endregion
- //Debug.WriteLine("開始評量題目start ----" + DateTime.Now.ToLongTimeString());
- #region ===評量題目===
- for (int j = 0; j < ansList.Count; j++)
- {
- #region === 判斷題型 ===
- // 這五種題型才記錄
- if (paperIndex.slides[j].type == "single" ||
- paperIndex.slides[j].type == "multiple" ||
- paperIndex.slides[j].type == "judge" ||
- paperIndex.slides[j].type == "complete" ||
- paperIndex.slides[j].type == "subjective")
- {
- LearnRecordItem learnRecordItem = new();
- // 單選
- if (paperIndex.slides[j].type == "single") { learnRecordItem.verb = "AnsSingle"; }
- // 複選
- if (paperIndex.slides[j].type == "multiple") { learnRecordItem.verb = "AnsMultiple"; }
- // 是非
- if (paperIndex.slides[j].type == "judge") { learnRecordItem.verb = "AnsJudge"; }
- // 填充
- if (paperIndex.slides[j].type == "complete") { learnRecordItem.verb = "AnsComplete"; }
- // 問答
- if (paperIndex.slides[j].type == "subjective") { learnRecordItem.verb = "AnsSubjective"; }
- learnRecordItem.actor = getStuId(info.school, stuid, stuDic);
- learnRecordItem.time = info.endTime;
- string[] arrurlsingle = paperIndex.slides[j].url.Split('.');
- learnRecordItem.ID = arrurlsingle[0];
- //Debug.WriteLine("設定Correct Choices Desc start ----" + DateTime.Now.ToLongTimeString());
- #region === 設定Correct Choices Desc===
- if (_azureStorage.GetBlobContainerClient(rootName).GetBlobClient($"{info.papers[i].blob}/{paperIndex.slides[j].url}").Exists())
- {
- BlobDownloadResult itemblobDownload = await _azureStorage.GetBlobContainerClient(rootName).GetBlobClient($"{info.papers[i].blob}/{paperIndex.slides[j].url}").DownloadContentAsync();
- QuestionData questionData = itemblobDownload.Content.ToObjectFromJson<QuestionData>();
- setCorrectChoicesExam(questionData, learnRecordItem);
- // 使用HtmlAgilityPack解析HTML
- HtmlDocument doc = new HtmlDocument();
- doc.LoadHtml(questionData.item[0].question);
- // 先刪除所有<img>標籤
- foreach (var imgNode in doc.DocumentNode.Descendants("img").ToArray())
- {
- imgNode.Remove();
- }
- // 再取純文字
- learnRecordItem.Desc = doc.DocumentNode.InnerText;
- }
- #endregion
- //Debug.WriteLine("設定Correct Choices Desc end ----" + DateTime.Now.ToLongTimeString());
- learnRecordItem.ExamQuesQty = null;
- learnRecordItem.TotalScore = null;
- learnRecordItem.Points = paperIndex.slides[j].scoring == null ? new List<string>() : paperIndex.slides[j].scoring.knowledge;
- //比對答案
- learnRecordItem.Success = paperIndex.slides[j].scoring == null ? null : (paperIndex.slides[j].scoring.ans.SequenceEqual(ansList[j]) ? true : false);
- learnRecordItems.Add(learnRecordItem);
- }
- #endregion
- }
- #endregion
- //Debug.WriteLine("開始評量題目end ----" + DateTime.Now.ToLongTimeString());
- #region ===EndExam 結束評量===
- LearnRecordItem LRItem_EndExam = new();
- LRItem_EndExam.verb = "EndExam";
- LRItem_EndExam.actor = getStuId(info.school, stuid, stuDic);
- LRItem_EndExam.time = info.endTime;
- LRItem_EndExam.ID = info.id;
- LRItem_EndExam.Desc = info.name;
- LRItem_EndExam.Correct = null;
- LRItem_EndExam.Choices = null;
- LRItem_EndExam.ExamQuesQty = info.papers[i].point.Count;
- LRItem_EndExam.TotalScore = 0;
- foreach (var pointItem in info.papers[i].point)
- {
- LRItem_EndExam.TotalScore = LRItem_EndExam.TotalScore + pointItem;
- }
- LRItem_EndExam.Success = null;
- learnRecordItems.Add(LRItem_EndExam);
- #endregion
- }
- }
- }
- }
- }
- //Debug.WriteLine("開始拼裝資料end ----" + DateTime.Now.ToLongTimeString());
- #endregion
- if (learnRecordItems.Count > 0)
- {
- #region 寫入blob
- //// 容器名称
- //string containerName = "twmoeld";
- //// 要上传的文件内容
- //string jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(learnRecordItems);
- //// 指定目录和文件名
- //string directoryPath = @"D:\twmoeld\exam";
- //string fileName = $"{info.id}.json";
- //string filePath = Path.Combine(directoryPath, fileName);
- //try
- //{
- // // 将 JSON 字符串写入文件
- // System.IO.File.WriteAllText(filePath, jsonString);
- // Console.WriteLine($"JSON 数据已成功写入文件: {filePath}");
- //}
- //catch (Exception ex)
- //{
- // Console.WriteLine($"写入文件时发生错误: {ex.Message}");
- //}
- // 容器名称
- string containerName = "twmoeld";
- // 新文件的名称
- //string blobName = $"/{DateTime.Now.ToString("yyyyMMdd")}/{info.id}.json";
- string blobName = $"/{date_path}/{info.id}.json";
- // 要上传的文件内容
- string fileContent = Newtonsoft.Json.JsonConvert.SerializeObject(learnRecordItems);
- // 获取容器引用
- BlobContainerClient containerClient = _azureStorage.GetBlobContainerClient(containerName);
- // 获取 Blob 客户端
- BlobClient blobClient = containerClient.GetBlobClient(blobName);
- // 将文件内容上传到 Blob
- using (MemoryStream stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(fileContent)))
- {
- await blobClient.UploadAsync(stream, true);
- }
- #endregion
- }
- }
- }
- }
- }
- catch (Exception ex)
- {
- }
- }
- /// <summary>
- /// 取得學習紀錄的actor
- /// </summary>
- /// <param name="learnRecordItem"></param>
- /// <param name="school"></param>
- /// <param name="stuid"></param>
- /// <returns></returns>
- private static string getStuId(string school, string stuid, Dictionary<string, List<string>> stuDic)
- {
- if (!string.IsNullOrWhiteSpace(school) && stuDic.ContainsKey(school) && stuDic[school].Contains(stuid))
- {// 校內帳號用組合的 "Base-hbgl,473891247381"
- return $"Base-{school.Trim()},{stuid}";
- }
- else
- {// 未入校老師的評量
- return stuid;
- }
- }
- /// <summary>
- /// 評量 - 對答案
- /// </summary>
- /// <param name="questionData"></param>
- /// <param name="learnRecordItem"></param>
- private static void setCorrectChoicesExam(QuestionData questionData, LearnRecordItem learnRecordItem)
- {
- #region === Correct Choices ===
- #region === 是非題邏輯 ===
- if (questionData.exercise.type == "judge" && questionData.exercise.answer.Count > 0)
- {// 如果是是非題 正確答案要用true false的方式設定
- if (questionData.exercise.answer[0] == "A")
- {
- learnRecordItem.Correct = new string[] { "true" };
- }
- else
- {
- learnRecordItem.Correct = new string[] { "false" };
- }
- }
- else
- {// 防呆 去html標籤
- if (questionData.exercise.answer.Count > 0)
- {
- List<string> anslist = new();
- foreach (var answer in questionData.exercise.answer)
- {
- // 使用HtmlAgilityPack解析HTML
- HtmlDocument doc = new HtmlDocument();
- doc.LoadHtml(answer);
- // 再取純文字
- anslist.Add(doc.DocumentNode.InnerText);
- }
- learnRecordItem.Correct = anslist;
- }
- else
- {
- learnRecordItem.Correct = questionData.exercise.answer;
- }
- }
- #endregion
- if (questionData.item[0].option.Count > 0)
- {// 如果有選項資料 記錄起來
- foreach (var option in questionData.item[0].option)
- {
- ChoicesItem item = new();
- item.id = option.code;
- if (questionData.exercise.type == "judge")
- {// 如果是是非題 固定選項
- if (option.code == "A")
- {
- item.description.zhTW = "是";
- }
- else
- {
- item.description.zhTW = "否";
- }
- }
- else
- {
- if (string.IsNullOrWhiteSpace(option.value))
- {
- item.description.zhTW = $"選項{option.code}";
- }
- else
- {
- // 使用HtmlAgilityPack解析HTML
- HtmlDocument doc = new HtmlDocument();
- doc.LoadHtml(option.value);
- // 再取純文字
- item.description.zhTW = doc.DocumentNode.InnerText;
- }
- }
- learnRecordItem.Choices.Add(item);
- }
- }
- #endregion
- }
- /// <summary>
- /// 更新课堂记录
- /// </summary>
- /// <param name="request"></param>
- /// <returns></returns>
- [Authorize(Roles = "HiTeach")]
- [ProducesDefaultResponseType]
- [HttpPost("update-lesson-recordLearnRecord")]
- public async Task<IActionResult> UpdateLessonRecordLearnRecord(JsonElement request)
- {
- try
- {
- if (!request.TryGetProperty("lesson_id", out JsonElement _lessonId)) return BadRequest();
- if (!request.TryGetProperty("scope", out JsonElement _scope)) return BadRequest();
- if (!request.TryGetProperty("tmdid", out JsonElement _tmdid)) return BadRequest();
- request.TryGetProperty("school", out JsonElement _school);
- await LessonServiceIES.SetLearnRecordContent(_school, _tmdid, _lessonId, _scope, _azureCosmos, _azureStorage);
- return Ok(new { status = 200 });
- }
- catch (Exception ex)
- {
- return BadRequest();
- }
- }
- /// <summary>
- /// 本機使用教育雲-學習紀錄
- /// </summary>
- /// <param name="request"></param>
- /// <returns></returns>
- [Authorize(Roles = "HiTeach")]
- [ProducesDefaultResponseType]
- [HttpPost("local-lesson-learnrecord")]
- public async Task<IActionResult> LocalLessonLearnRecord(JsonElement request)
- {
- try
- {
- if (!request.TryGetProperty("lesson_id", out JsonElement _lessonId)) return BadRequest();
- if (!request.TryGetProperty("tmdid", out JsonElement _tmdid)) return BadRequest();
- request.TryGetProperty("school", out JsonElement _school);
- request.TryGetProperty("scope", out JsonElement _scope);
- await LessonServiceIES.SetLearnRecordContent(_school, _tmdid, _lessonId, _scope, _azureCosmos, _azureStorage, false);
- return Ok(new { status = 200 });
- }
- catch (Exception ex)
- {
- return BadRequest();
- }
- }
-
- private async Task SetLearnRecordContentForBatch(string _school, string _tmdid, string _lessonId, string _scope, string htype, bool _isIES = true)
- {
- try
- {
- var client = _azureCosmos.GetCosmosClient();
- string school = $"{_school}";
- string tmdid = _tmdid;
- string lessonId = _lessonId;
- string rootName = "";
- string date_path = "";
- List<LearnRecordItem> learnRecordItems = new List<LearnRecordItem>();
- // 判斷個人或是學校課堂以及是否為本地課程 來取blob的容器位置
- if (_scope == null)
- {// 本地課堂
- rootName = tmdid;
- }
- else
- {
- if (_scope.Equals("school") && !string.IsNullOrWhiteSpace(_school))
- {// 學校課堂
- rootName = school;
- }
- else if ($"{_scope}".Equals("private"))
- {// 個人課堂
- rootName = tmdid;
- }
- }
- // 本地路徑 1524738018 / temp / records / 1334aa30868520170580732778614850743
- string blobTimeLineUrl = "";
- string blobIRSUrl = "";
- string blobbaseUrl = "";
- string blobTaskUrl = "";
- // 處理資料是由IES5或是hiteach本地來的邏輯
- if (_isIES)
- {
- blobTimeLineUrl = $"/records/{lessonId}/IES/TimeLine.json";
- blobIRSUrl = $"/records/{lessonId}/IES/IRS.json";
- blobbaseUrl = $"/records/{lessonId}/IES/base.json";
- blobTaskUrl = $"/records/{lessonId}/IES/Task.json";
- }
- else
- {
- blobTimeLineUrl = $"/temp/records/{lessonId}/IES/TimeLine.json";
- blobIRSUrl = $"/temp/records/{lessonId}/IES/IRS.json";
- blobbaseUrl = $"/temp/records/{lessonId}/IES/base.json";
- blobTaskUrl = $"/temp/records/{lessonId}/IES/Task.json";
- }
- // 檢查 TimeLine 是否存在blob
- if (_azureStorage.GetBlobContainerClient(rootName).GetBlobClient(blobTimeLineUrl).Exists() &&
- _azureStorage.GetBlobContainerClient(rootName).GetBlobClient(blobIRSUrl).Exists() &&
- _azureStorage.GetBlobContainerClient(rootName).GetBlobClient(blobbaseUrl).Exists())
- {
- // 開啟 base.json
- BlobDownloadResult baseblobDownload = await _azureStorage.GetBlobContainerClient(rootName).GetBlobClient(blobbaseUrl).DownloadContentAsync();
- ScoreLessonBase lessonBase = baseblobDownload.Content.ToObjectFromJson<ScoreLessonBase>();
- date_path = lessonBase.summary.date.Replace(".", "");
- //取得學校學生名單
- List<string> stuIdForSql = new List<string>();
- if (lessonBase.student.Count > 0)
- {
- foreach (LessonStudent stu in lessonBase.student)
- {
- if (!string.IsNullOrWhiteSpace(stu.id) && !stuIdForSql.Contains(stu.id))
- {
- stuIdForSql.Add(stu.id);
- }
- }
- }
- GroupList groupList = new ();
- List<LessonStudent> student = lessonBase.student.FindAll(x => x.type.Equals(2));
- if (student.Count > 0 && string.IsNullOrWhiteSpace(school)) // 如果有學生事校內帳號而且沒有schoolid 先取出班級id 下面設定schoolid的時候可以用
- {
-
- var clientTeacher = _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher);
- GroupIdsFromLesson groupIdsFromLesson = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemAsync<GroupIdsFromLesson>(lessonId, new PartitionKey($"LessonRecord"));
- groupList = await clientTeacher.ReadItemAsync<GroupList>(groupIdsFromLesson.groupIds[0], new PartitionKey($"GroupList"));
- }
-
- // 開啟 TimeLine.json
- BlobDownloadResult TimeLineblobDownload = await _azureStorage.GetBlobContainerClient(rootName).GetBlobClient(blobTimeLineUrl).DownloadContentAsync();
- TimeLineEvents timeLineEvents = TimeLineblobDownload.Content.ToObjectFromJson<TimeLineEvents>();
- // 開啟 IRS.json
- BlobDownloadResult IRSblobDownload = await _azureStorage.GetBlobContainerClient(rootName).GetBlobClient(blobIRSUrl).DownloadContentAsync();
- List<IRSItem> iRSItems = IRSblobDownload.Content.ToObjectFromJson<List<IRSItem>>();
- // 開啟 Task.json
- BlobDownloadResult taskblobDownload = await _azureStorage.GetBlobContainerClient(rootName).GetBlobClient(blobTaskUrl).DownloadContentAsync();
- List<TaskItem> taskItems = taskblobDownload.Content.ToObjectFromJson<List<TaskItem>>();
- if (timeLineEvents.events.Count > 0)
- {
- for (int i = 0; i < timeLineEvents.events.Count; i++)
- {
- switch (timeLineEvents.events[i].Event)
- {
- // 互動
- case "PopQuesLoad":
- case "QuesLoad":
- for (int j = 0; j < iRSItems.Count; j++)
- {
- if (timeLineEvents.events[i].Pgid == iRSItems[j].pageID) // 比對 Pgid 找到 IRS.json 該活動的詳細資料
- {
- switch (iRSItems[j].question.exercise.type)
- {
- // 單選
- case "single":
- await SetPopQuesLoadContent(lessonBase, school, lessonId, iRSItems[j], timeLineEvents.events[i], "AnsSingle", learnRecordItems, groupList);
- break;
- // 複選
- case "multiple":
- await SetPopQuesLoadContent(lessonBase, school, lessonId, iRSItems[j], timeLineEvents.events[i], "AnsMultiple", learnRecordItems, groupList);
- break;
- // 是非
- case "judge":
- await SetPopQuesLoadContent(lessonBase, school, lessonId, iRSItems[j], timeLineEvents.events[i], "AnsJudge", learnRecordItems, groupList);
- break;
- // 填充
- case "complete":
- await SetPopQuesLoadContent(lessonBase, school, lessonId, iRSItems[j], timeLineEvents.events[i], "AnsComplete", learnRecordItems, groupList);
- break;
- // 問答
- case "subjective":
- await SetPopQuesLoadContent(lessonBase, school, lessonId, iRSItems[j], timeLineEvents.events[i], "AnsSubjective", learnRecordItems, groupList);
- break;
- }
- }
- }
- break;
- // 搶權
- case "BuzrAns":
- for (int j = 0; j < iRSItems.Count; j++)
- {
- if (timeLineEvents.events[i].Pgid == iRSItems[j].pageID && iRSItems[j].isBuzz) // 比對 Pgid 找到 IRS.json 該活動的詳細資料
- {
- for (int k = 0; k < iRSItems[j].buzzClients.Count; k++)
- {
- LearnRecordItem learnRecordItem = new();
- for (int m = 0; m < lessonBase.student.Count; m++)
- {// 比對學生座號 取學號
- if (lessonBase.student[m].seatID.ToString() == iRSItems[j].buzzClients[k])
- {
- if (lessonBase.student[k].type == 2)
- {// 校內帳號
- await getSchoolCode(school, lessonId, lessonBase.student[k].id, learnRecordItem, groupList);
- }
- else
- {// 非校內帳號
- learnRecordItem.actor = setActor(school, lessonBase.student[k].id);
- }
- }
- }
- string[] arrymd = lessonBase.summary.date.Split('.');
- string[] arrhms = lessonBase.summary.startTime.Split(':');
- DateTime dt = new DateTime(int.Parse(arrymd[0]), int.Parse(arrymd[1]), int.Parse(arrymd[2]), int.Parse(arrhms[0]), int.Parse(arrhms[1]), int.Parse(arrhms[2]));
- dt = dt.AddSeconds(timeLineEvents.events[i].Time);
- learnRecordItem.verb = "AnsBuzzin";
- learnRecordItem.time = dt.ToUnixTimestamp();
- learnRecordItem.ID = timeLineEvents.events[i].Pgid;
- if (iRSItems[j].question.item[0].question == "_popquiz_" || iRSItems[j].question.item[0].question == "")
- {
- learnRecordItem.Desc = "隨堂問答";
- }
- else
- {
- learnRecordItem.Desc = iRSItems[j].question.item[0].question;
- }
- learnRecordItem.Points = iRSItems[j].question.exercise.knowledges;
- await setCorrectChoices(iRSItems[j], learnRecordItem);
- learnRecordItem.ExamQuesQty = null;
- learnRecordItem.TotalScore = null;
- learnRecordItem.Success = null;
- learnRecordItems.Add(learnRecordItem);
- }
- }
- }
- break;
- // 上傳作品
- case "WrkSpaceLoad":
- for (int j = 0; j < taskItems.Count; j++)
- {
- if (timeLineEvents.events[i].Pgid == taskItems[j].pageID) // 比對 Pgid 找到 IRS.json 該活動的詳細資料
- {
- for (int k = 0; k < taskItems[j].clientWorks.Count; k++)
- {
- LearnRecordItem learnRecordItem = new();
- for (int m = 0; m < lessonBase.student.Count; m++)
- {// 比對學生座號 取學號
- if (lessonBase.student[m].seatID == taskItems[j].clientWorks[k].seatID)
- {
- if (lessonBase.student[k].type == 2)
- {// 校內帳號
- await getSchoolCode(school, lessonId, lessonBase.student[k].id, learnRecordItem, groupList);
- }
- else
- {// 非校內帳號
- learnRecordItem.actor = setActor(school, lessonBase.student[k].id);
- }
- }
- }
- string[] arrymd = lessonBase.summary.date.Split('.');
- string[] arrhms = taskItems[j].clientWorks[k].reciveTime.Split(':');
- DateTime dt = new DateTime(int.Parse(arrymd[0]), int.Parse(arrymd[1]), int.Parse(arrymd[2]), int.Parse(arrhms[0]), int.Parse(arrhms[1]), int.Parse(arrhms[2]));
- dt = dt.AddSeconds(timeLineEvents.events[i].Time);
- learnRecordItem.verb = "SubmitTask";
- learnRecordItem.time = dt.ToUnixTimestamp();
- learnRecordItem.ID = timeLineEvents.events[i].Pgid;
- learnRecordItem.Desc = "隨堂作品";
- learnRecordItem.Correct = null;
- learnRecordItem.Choices = null;
- learnRecordItem.ExamQuesQty = null;
- learnRecordItem.TotalScore = null;
- learnRecordItem.Success = null;
- learnRecordItems.Add(learnRecordItem);
- }
- }
- }
- break;
- case "FastPgPush":
- for (int k = 0; k < lessonBase.student.Count; k++)
- {
- LearnRecordItem learnRecordItem = new();
- for (int m = 0; m < lessonBase.student.Count; m++)
- {// 比對學生座號 取學號
- if (lessonBase.student[k].type == 2)
- {
- await getSchoolCode(school, lessonId, lessonBase.student[k].id, learnRecordItem, groupList);
- }
- else
- {// 非校內帳號
- learnRecordItem.actor = setActor(school, lessonBase.student[k].id);
- }
- }
- string[] arrymd = lessonBase.summary.date.Split('.');
- string[] arrhms = lessonBase.summary.startTime.Split(':');
- DateTime dt = new DateTime(int.Parse(arrymd[0]), int.Parse(arrymd[1]), int.Parse(arrymd[2]), int.Parse(arrhms[0]), int.Parse(arrhms[1]), int.Parse(arrhms[2]));
- dt = dt.AddSeconds(timeLineEvents.events[i].Time);
- learnRecordItem.verb = "ViewPage";
- learnRecordItem.time = dt.ToUnixTimestamp();
- learnRecordItem.ID = timeLineEvents.events[i].Pgid;
- learnRecordItem.Desc = $"https://www.teammodel.net/viewpage?id={timeLineEvents.events[i].Pgid}";
- learnRecordItem.Correct = null;
- learnRecordItem.Choices = null;
- learnRecordItem.ExamQuesQty = null;
- learnRecordItem.TotalScore = null;
- learnRecordItem.Success = null;
- learnRecordItems.Add(learnRecordItem);
- }
- break;
- case "ActStart":
- case "ActEnd":
- for (int k = 0; k < lessonBase.student.Count; k++)
- {
- LearnRecordItem learnRecordItem = new();
- for (int m = 0; m < lessonBase.student.Count; m++)
- {// 比對學生座號 取學號
- if (lessonBase.student[k].type == 2)
- {
- await getSchoolCode(school, lessonId, lessonBase.student[k].id, learnRecordItem, groupList);
- }
- else
- {// 非校內帳號
- learnRecordItem.actor = setActor(school, lessonBase.student[k].id);
- }
- }
- string[] arrymd = lessonBase.summary.date.Split('.');
- string[] arrhms = lessonBase.summary.startTime.Split(':');
- DateTime dt = new DateTime(int.Parse(arrymd[0]), int.Parse(arrymd[1]), int.Parse(arrymd[2]), int.Parse(arrhms[0]), int.Parse(arrhms[1]), int.Parse(arrhms[2]));
- dt = dt.AddSeconds(timeLineEvents.events[i].Time);
- if (timeLineEvents.events[i].Event == "ActStart") { learnRecordItem.verb = "StartExam"; }
- if (timeLineEvents.events[i].Event == "ActEnd") { learnRecordItem.verb = "EndExam"; }
- learnRecordItem.time = dt.ToUnixTimestamp();
- learnRecordItem.ID = lessonId;
- learnRecordItem.Desc = lessonBase.summary.activityName;
- learnRecordItem.Correct = null;
- learnRecordItem.Choices = null;
- learnRecordItem.ExamQuesQty = 0;
- foreach (var item in timeLineEvents.events)
- {
- if (item.Event == "PopQuesLoad" || item.Event == "QuesLoad" || item.Event == "BuzrAns")
- {
- learnRecordItem.ExamQuesQty = learnRecordItem.ExamQuesQty + 1;
- }
- }
- learnRecordItem.TotalScore = learnRecordItem.ExamQuesQty * 10;
- learnRecordItem.Success = null;
- learnRecordItems.Add(learnRecordItem);
- }
- break;
- // 測驗
- case "SPQStrt":
- //// 開啟 .json
- //BlobDownloadResult taskblobDownload = await _azureStorage.GetBlobContainerClient(school).GetBlobClient($"/records/{lessonId}/IES/Task.json").DownloadContentAsync();
- //List<TaskItem> taskItems = taskblobDownload.Content.ToObjectFromJson<List<TaskItem>>();
- break;
- }
- }
- }
- #region 寫入blob
- //// 容器名称
- //string containerName = "twmoeld";
- //// 要上传的文件内容
- //string jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(learnRecordItems);
- //// 指定目录和文件名
- //string directoryPath = @"D:\twmoeld";
- //if (htype == "0") { directoryPath = @"D:\twmoeld\school"; }
- //if (htype == "1") { directoryPath = @"D:\twmoeld\private"; }
- //if (htype == "2") { directoryPath = @"D:\twmoeld\exam"; }
- //directoryPath = $"{directoryPath}\\{date_path}";
- //string fileName = $"{_lessonId}.json";
- //string filePath = Path.Combine(directoryPath, fileName);
- // 容器名称
- string containerName = "twmoeld";
- // 新文件的名称
- string blobName = $"/{date_path}/{_lessonId}.json";
- // 要上传的文件内容
- string fileContent = Newtonsoft.Json.JsonConvert.SerializeObject(learnRecordItems);
- // 获取容器引用
- BlobContainerClient containerClient = _azureStorage.GetBlobContainerClient(containerName);
- // 获取 Blob 客户端
- BlobClient blobClient = containerClient.GetBlobClient(blobName);
- // 将文件内容上传到 Blob
- using (MemoryStream stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(fileContent)))
- {
- await blobClient.UploadAsync(stream, true);
- }
- //try
- //{
- // // 将 JSON 字符串写入文件
- // System.IO.File.WriteAllText(filePath, jsonString);
- // Console.WriteLine($"JSON 数据已成功写入文件: {filePath}");
- //}
- //catch (Exception ex)
- //{
- // Console.WriteLine($"写入文件时发生错误: {ex.Message}");
- //}
- #endregion
- }
- }
- catch (Exception ex)
- {
- // throw;
- }
- }
- #region ===雲端課程專區===
- /// <summary>
- /// 新增課程API
- /// </summary>
- /// <param name="request"></param>
- /// <returns></returns>
- [Authorize(Roles = "HiTeach")]
- [ProducesDefaultResponseType]
- [HttpPost("hiteach-create-course")]
- public async Task<IActionResult> Manage(JsonElement request)
- {
- try
- {
- #region === 驗證身分 ===
- string id_token = HttpContext.GetXAuth("IdToken");
- if (string.IsNullOrEmpty(id_token)) return BadRequest();
- var jwt = new JwtSecurityToken(id_token);
- if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.OrdinalIgnoreCase)) return BadRequest();
- var tmdid = jwt.Payload.Sub;
- #endregion
- if (!request.TryGetProperty("courseName", out JsonElement courseName)) return BadRequest();
- if (!request.TryGetProperty("groupListName", out JsonElement groupListName)) return BadRequest();
- if (!request.TryGetProperty("creatorId", out JsonElement creatorId)) return BadRequest();
- if (!request.TryGetProperty("teacherName", out JsonElement tName)) return BadRequest();
- if (!request.TryGetProperty("limitCount", out JsonElement limitCount)) return BadRequest();
- // 未來會用到 是否允許自選座號
- request.TryGetProperty("isOptionalSeat", out JsonElement isOptionalSeat);
- request.TryGetProperty("courseId", out JsonElement courseId);
- var client = _azureCosmos.GetCosmosClient();
- CourseBase courseBase = new();
- GroupListWithCourseTaskId groupListWithCourseTaskId = new();
- if (string.IsNullOrWhiteSpace(courseId.GetString()))
- {// 如果沒有給課程Id 則為新增課程及名單
- #region === 新增課程 ===
- courseBase.name = courseName.GetString();
- courseBase.id = "";
- courseBase.subject = null;
- courseBase.period = null;
- courseBase.major = null;
- courseBase.desc = "";
- courseBase.no = "";
- courseBase.school = null;
- courseBase.color = null;
- courseBase.status = 1;
- courseBase.pk = "CourseBase";
- courseBase.scope = "private";
- string tbname = Constant.Teacher;
- StringBuilder sqlCourse = new StringBuilder(" select value c from c ");
- sqlCourse.Append($" where c.name ='{courseBase.name}' and c.creatorId='{tmdid}' ");
- courseBase.creatorId = tmdid;
- courseBase.code = $"CourseBase";
- List<CourseBase> courseBases = new List<CourseBase>();
- try
- {
- await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, tbname)
- .GetItemQueryIteratorSql<CourseBase>(queryText: sqlCourse.ToString(), requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey(courseBase.code) }))
- {
- if (courseBase.scope.Equals(item.scope))
- {// 只取個人課程
- if (!item.id.Equals(courseBase.id) && item.name.Equals(courseBase.name))
- {// id不同 但是名稱相同
- return Ok(new { code = 500, msg = "名字重复" });
- }
- }
- }
- }
- catch (Exception ex)
- {
- await _dingDing.SendBotMsg($"{_option.Location},执行课程更新异常{sqlCourse}\n{ex.Message},{ex.StackTrace}", GroupNames.成都开发測試群組);
- }
- if (string.IsNullOrWhiteSpace(courseBase.id))
- {// 新增課程 所以建一個新的id
- courseBase.id = Guid.NewGuid().ToString();
- }
- // 新增課程
- await client.GetContainer(Constant.TEAMModelOS, tbname).UpsertItemAsync(courseBase, new PartitionKey(courseBase.code));
- #endregion
- //新增名單
- groupListWithCourseTaskId = await SaveGroupList(creatorId.GetString(), groupListName.GetString(), courseBase.id, isOptionalSeat, limitCount.GetInt32());
- }
- else
- {// 如果有給課程Id 則只有新增名單
- groupListWithCourseTaskId = await SaveGroupList(creatorId.GetString(), groupListName.GetString(), courseId.GetString(), isOptionalSeat, limitCount.GetInt32());
- }
- string apiUrl = this.Request.GetRequestUrlAddress();
- // 解析URL
- Uri uri = new Uri(apiUrl);
- // 获取包含协议的主机部分
- string hostWithProtocol = uri.GetLeftPart(UriPartial.Authority);
- //組合完整網止
- string longUrl = $"{hostWithProtocol}/joinclass?listName={groupListWithCourseTaskId.groupList.name}&cusDesc=暫無資料&cusId={groupListWithCourseTaskId.CourseTaskId}" +
- $"&tName={tName}&listNo={groupListWithCourseTaskId.groupList.no}&cusName={courseName.GetString()}&m=前往加入課程:{courseName.GetString()}{groupListWithCourseTaskId.groupList.name}&o=1";
- // 轉換為短網址
- string shortUrl = await GetShortUrl(Uri.EscapeUriString(longUrl));
- return Ok(new
- {
- code = 200,
- result = shortUrl,
- longUrl = $"{hostWithProtocol}/joinclass?listName={groupListWithCourseTaskId.groupList.name}&cusDesc=暫無資料&cusId={groupListWithCourseTaskId.CourseTaskId}&tName={tName}&listNo={groupListWithCourseTaskId.groupList.no}&cusName={courseName.GetString()}&m=前往加入課程:{courseName.GetString()}{groupListWithCourseTaskId.groupList.name}&o=1",
- groupListId = groupListWithCourseTaskId.groupList.id
- });
- }
- catch (Exception ex)
- {
- await _dingDing.SendBotMsg($"{_option.Location},课程处理异常,{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
- return Ok(new { code = 500, msg = ex.Message });
- }
- }
- /// <summary>
- /// 新增課程更新名單
- /// </summary>
- /// <param name="creatorId"></param>
- /// <param name="groupListName"></param>
- /// <param name="courseId"></param>
- /// <param name="limitCount"></param>
- /// <param name="joinLock"></param>
- /// <returns></returns>
- private async Task<GroupListWithCourseTaskId> SaveGroupList(string creatorId, string groupListName, string courseId, JsonElement isOptionalSeat, int limitCount = 200, int joinLock = 1)
- {
- try
- {
- //var (userid, _, _, school) = HttpContext.GetAuthTokenInfo();
- //if (string.IsNullOrEmpty(list.type))
- //{
- // return BadRequest();
- //}
- int optNo = 0;
- if (isOptionalSeat.ValueKind.Equals(JsonValueKind.True))
- {
- optNo = 1;
- }
- GroupListWithCourseTaskId groupListWithCourseTaskId = new();
- GroupList list = new();
- list.year = list.year > 0 ? list.year : DateTimeOffset.UtcNow.Year;
- list.ttl = -1;
- list.creatorId = creatorId;
- list.leader = creatorId;
- list.name = groupListName;
- list.pk = "GroupList";
- list.code = "GroupList";
- list.school = null;
- list.scope = "private";
- list.joinLock = joinLock;
- list.limitCount = limitCount;
- list.optNo = optNo;
- list.type = "teach";
- GroupList dblist = null;
- if (!string.IsNullOrWhiteSpace(list.id))
- {
- var response = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemStreamAsync(list.id, new PartitionKey(list.code));
- if (response.StatusCode==System.Net.HttpStatusCode.OK)
- {
- dblist = JsonDocument.Parse(response.Content).RootElement.ToObject<GroupList>();
- }
- }
- list = await GroupListService.CheckListNo(list, _azureCosmos, _dingDing, _option);
- list = await GroupListService.UpsertList(list, _azureCosmos, _configuration, _serviceBus, _client: "hita");
- #region === 更新DB課程名單 ===
- //if (!request.TryGetProperty("datas", out JsonElement _datas))
- //{
- // return BadRequest();
- //}
- //string tbname = $"{scope}".Equals("school", StringComparison.OrdinalIgnoreCase) ? Constant.School : Constant.Teacher;
- List<CourseTaskChanged> datas = new();
- CourseTaskChanged courseTaskChanged = new();
- courseTaskChanged.courseId = courseId;
- courseTaskChanged.type = "teach";
- courseTaskChanged.groupId = list.id;
- courseTaskChanged.teacherId = creatorId;
- courseTaskChanged.startTime = 0;
- datas.Add(courseTaskChanged);
- var client = _azureCosmos.GetCosmosClient();
- string grant_type = "insert-scheduleTask";
- string school = null;
- //获取相关的名单
- List<GroupListDto> groupListDtos = await GroupListService.GetGroupListByListids(client, _dingDing, datas.Select(z => z.groupId).ToHashSet().ToList(), school);
- //获取相关的教室
- var roomIds = datas.Where(x => !string.IsNullOrWhiteSpace(x.roomId)).Select(c => $"'{c.roomId}'");
- List<Room> rooms = new List<Room>();
- //获取教师
- List<Teacher> teachers = new List<Teacher>();
- var teacherIds = datas.Where(x => !string.IsNullOrWhiteSpace(x.teacherId)).Select(c => $"'{c.teacherId}'");
- if (teacherIds.Any())
- {
- string sqlTeacher = $"select value c from c where c.id in ({string.Join(",", teacherIds)}) ";
- var result = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<Teacher>(sqlTeacher, $"Base");
- if (result.list.IsNotEmpty())
- {
- teachers.AddRange(result.list);
- }
- }
- //获取课程
- List<CourseBase> courseBases = new List<CourseBase>();
- var courseIds = datas.Where(x => !string.IsNullOrWhiteSpace(x.courseId)).Select(c => $"'{c.courseId}'");
- if (courseIds.Any())
- {
- string sqlCourse = $"select value c from c where c.id in ({string.Join(",", courseIds)}) and c.creatorId='{creatorId}' ";
- var result = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<CourseBase>(sqlCourse, $"CourseBase");
- if (result.list.IsNotEmpty())
- {
- courseBases.AddRange(result.list);
- }
- }
- HashSet<CourseTask> courseTasks = new HashSet<CourseTask>();
- List<CourseTaskChanged> invalidCourseTaskInsert = new List<CourseTaskChanged>();
- foreach (var data in datas)
- {
- var courseTaskInsert = SchoolService.CheckCourseTaskInsertOrChanged($"{grant_type}", "private", data, null, null, courseBases, groupListDtos, rooms, null, teachers);
- if (courseTaskInsert.invalidCode == 0)
- {
- string taskCode = $"CourseTask";
- string taskId = courseTaskInsert.courseId;
- CourseTask courseTask = courseTasks.Where(z => z.id.Equals(taskId) && z.code.Equals(taskCode)).FirstOrDefault();
- if (courseTask == null)
- {
- ResponseMessage response = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemStreamAsync(taskId, new PartitionKey(taskCode));
- if (response.StatusCode==System.Net.HttpStatusCode.OK)
- {
- courseTask = JsonDocument.Parse(response.Content).RootElement.ToObject<CourseTask>();
- }
- else
- {
- courseTask = new CourseTask
- {
- id = taskId,
- code = taskCode,
- pk = "CourseTask",
- ttl = -1,
- courseId = courseTaskInsert.courseId,
- schedules = new List<ScheduleTask> { new ScheduleTask {
- roomId = courseTaskInsert.roomId,
- groupId = courseTaskInsert.groupId,
- type = courseTaskInsert.type,
- teacherId = courseTaskInsert.teacherId,
- notice=courseTaskInsert.notice,
- startTime = courseTaskInsert.startTime,
- times= new List<ScheduleTime>(),
- school=courseTaskInsert.school,
- } }
- };
- }
- }
- ScheduleTask scheduleTask = null;
- var scheduleTasks = courseTask.schedules.FindAll(z => z.type.Equals(courseTaskInsert.type) && z.groupId.Equals(courseTaskInsert.groupId));
- if (scheduleTasks.IsNotEmpty())
- {
- if (scheduleTasks.Count > 2)
- {
- courseTask.schedules.RemoveRange(1, scheduleTasks.Count - 1);
- }
- scheduleTask = scheduleTasks.First();
- scheduleTask.roomId = string.IsNullOrWhiteSpace(courseTaskInsert.roomId) ? scheduleTask.roomId : courseTaskInsert.roomId;
- scheduleTask.school = school;
- scheduleTask.teacherId = courseTaskInsert.teacherId;
- scheduleTask.startTime = courseTaskInsert.startTime > 0 ? courseTaskInsert.startTime : scheduleTask.startTime;
- scheduleTask.notice = string.IsNullOrWhiteSpace(courseTaskInsert.notice) ? scheduleTask.notice : courseTaskInsert.notice;
- scheduleTask.assistants = courseTaskInsert.assistants != null ? courseTaskInsert.assistants : courseTaskInsert.assistants;
- }
- else
- {
- scheduleTask = new ScheduleTask()
- {
- roomId = courseTaskInsert.roomId,
- groupId = courseTaskInsert.groupId,
- type = courseTaskInsert.type,
- teacherId = courseTaskInsert.teacherId,
- times = new List<ScheduleTime>(),
- school = school,
- notice = courseTaskInsert.notice,
- };
- courseTask.schedules.Add(scheduleTask);
- }
- //修改教师或名单
- if (grant_type.ToString().Equals("change-scheduleTask", StringComparison.OrdinalIgnoreCase))
- {
- if (!string.IsNullOrWhiteSpace(courseTaskInsert.teacherIdChanged))
- {
- scheduleTask.teacherId = courseTaskInsert.teacherIdChanged;
- }
- if (!string.IsNullOrWhiteSpace(courseTaskInsert.typeChanged) && !string.IsNullOrWhiteSpace(courseTaskInsert.groupIdChanged))
- {
- scheduleTask.groupId = courseTaskInsert.groupIdChanged;
- scheduleTask.type = courseTaskInsert.typeChanged;
- }
- }
- //await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(courseTask, new PartitionKey(taskCode));
- //删除教师及名单的排课信息
- if (grant_type.ToString().Equals("delete-scheduleTask", StringComparison.OrdinalIgnoreCase))
- {
- courseTask.schedules.Remove(scheduleTask);
- }
- //如果被删除完了,就删除该条记录。
- if (courseTask.schedules.Count <= 0)
- {
- courseTasks.Remove(courseTask);
- await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).DeleteItemStreamAsync(courseTask.id, new PartitionKey(courseTask.code));
- }
- else
- {
- courseTasks.Add(courseTask);
- await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(courseTask, new PartitionKey(taskCode));
- }
- groupListWithCourseTaskId.CourseTaskId = courseTask.id;
- }
- else
- {
- invalidCourseTaskInsert.Add(courseTaskInsert);
- }
- }
- #endregion
- groupListWithCourseTaskId.groupList = list;
- return groupListWithCourseTaskId;
- }
- catch (Exception ex)
- {
- throw ex;
- }
- }
- /// <summary>
- /// 將完整網址轉換為短網址
- /// </summary>
- /// <param name="url"></param>
- /// <returns></returns>
- public async Task<string> GetShortUrl(string url)
- {
- try
- {
- var uri = new Uri(url);
- string md5url = Md5Hash.GetMd5String(uri.OriginalString);
- char[] chars = new char[]
- {
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
- 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
- 'y', 'z', '0', '1', '2', '3', '4', '5',
- '6', '7', '8', '9', 'A', 'B', 'C', 'D',
- 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
- 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
- 'U', 'V', 'W', 'X', 'Y', 'Z'
- };
- //把加密字元按照8位一組16進位制與0x3FFFFFFF進行位與運算
- int hexint = 0x3FFFFFFF & Convert.ToInt32(string.Concat("0x", md5url.AsSpan(0, 8)), 16);
- StringBuilder outShort = new();
- for (int j = 0; j < 6; j++)
- {
- //把得到的值與0x0000003D進行位與運算,取得字元陣列chars索引
- int index = 0x0000003D & hexint;
- //把取得的字元相加
- outShort.Append(chars[index]);
- //每次迴圈按位右移5位
- hexint >>= 5;
- }
- var shortid = outShort.ToString();
- var table = _azureStorage.GetCloudTableClient().GetTableReference("ShortUrl");
- ShortUrl su = new() { PartitionKey = uri.Host, RowKey = shortid, Url = uri.AbsoluteUri };
- await table.SaveOrUpdate<ShortUrl>(su);
- var result = new UriBuilder() { Scheme = uri.Scheme, Host = uri.Host, Path = shortid }.ToString();
- return result;
- }
- catch (Exception ex)
- {
- throw ex;
- }
- }
- /// <summary>
- /// 取得課程列表 API
- /// </summary>
- /// <param name="request"></param>
- /// <returns></returns>
- [Authorize(Roles = "HiTeach")]
- [ProducesDefaultResponseType]
- [HttpPost("hiteach-get-courselist")]
- public async Task<IActionResult> GetCourseList(JsonElement request)
- {
- try
- {
- string id_token = HttpContext.GetXAuth("IdToken");
- if (string.IsNullOrEmpty(id_token)) return BadRequest();
- if (!request.TryGetProperty("tmdid", out JsonElement _tmdid)) return BadRequest();
- string tmdid = _tmdid.GetString();
- var jwt = new JwtSecurityToken(id_token);
- if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.OrdinalIgnoreCase)) return BadRequest();
- #region 取得資料邏輯
- List<IdName> idNames = new();
- HashSet<string> courseIds = new HashSet<string>();
- // 1. 取CourseBase的資料 取全部的課程Id
- string sqlCoursePrivate = $"select value c.id from c where c.creatorId='{tmdid}'";
- var resultCourseBasePrivate = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<string>(sqlCoursePrivate, $"CourseBase");
- if (resultCourseBasePrivate.list.IsNotEmpty())
- {
- courseIds = new HashSet<string>(resultCourseBasePrivate.list);
- }
- // 2.取CourseTask的資料
- string sqlprivate = $"SELECT distinct value c FROM c join b in c.schedules where c.pk='CourseTask' and (ARRAY_CONTAINS(b.assistants,'{tmdid}')or b.teacherId ='{tmdid}' )";
- var resultTeacher = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<CourseTask>(sqlprivate, $"CourseTask");
- if (resultTeacher.list.IsNotEmpty())
- {
- resultTeacher.list.ForEach(x =>
- {
- var schedulesTeacherOrAssistant = x.schedules.Where(z => (!string.IsNullOrWhiteSpace(z.teacherId) && z.teacherId.Equals(tmdid)) || z.assistants.Contains(tmdid));
- if (schedulesTeacherOrAssistant.Any())
- {// 收集符合條件的課程 符合老師id 或是 符合助理人選
- courseIds.Add(x.courseId);
- }
- });
- }
- // 3. 整合出最後資料
- if (courseIds.Any())
- {
- string sqlCourse = $"select distinct c.id, c.name from c where c.code='CourseBase' and ( c.creatorId='{tmdid}' or c.id in ({string.Join(",", courseIds.Select(b => $"'{b}'"))}))";
- var result = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<CourseBase>(sqlCourse, $"CourseBase");
- if (result.list.IsNotEmpty())
- {
- foreach (var item in result.list)
- {
- idNames.Add(new IdName { name = item.name, id = item.id });
- }
- }
- }
- #endregion
- return Ok(new { code = 200, result = idNames });
- }
- catch (Exception ex)
- {
- await _dingDing.SendBotMsg($"{_option.Location},课程处理异常,{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
- return Ok(new { code = 500, msg = ex.Message });
- }
- }
- /// <summary>
- /// 更新課程名單 API
- /// </summary>
- /// <param name="request"></param>
- /// <returns></returns>
- [Authorize(Roles = "HiTeach")]
- [ProducesDefaultResponseType]
- [HttpPost("hiteach-upsert-grouplist")]
- public async Task<IActionResult> UpsertGroupList(JsonElement request)
- {
- try
- {
- string id_token = HttpContext.GetXAuth("IdToken");
- if (string.IsNullOrEmpty(id_token)) return BadRequest();
- var jwt = new JwtSecurityToken(id_token);
- if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.OrdinalIgnoreCase)) return BadRequest();
- if (!request.TryGetProperty("id", out JsonElement _id)) return BadRequest();
- if (!request.TryGetProperty("limitCount", out JsonElement _limitCount)) return BadRequest();
- if (!request.TryGetProperty("isOptionalSeat", out JsonElement _isOptionalSeat)) return BadRequest();
- if (!request.TryGetProperty("joinLock", out JsonElement _joinLock)) return BadRequest();
- if (!request.TryGetProperty("review", out JsonElement _review)) return BadRequest();
- var clientTeacher = _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher);
- // 先撈指定id的資料
- GroupList groupList = await clientTeacher.ReadItemAsync<GroupList>(_id.GetString(), new PartitionKey($"GroupList"));
- //設定需更新的欄位值
- groupList.limitCount = _limitCount.GetInt32();
- //groupList.isOptionalSeat = isOptionalSeat.GetString();
- int optNo = 0;
- if (_isOptionalSeat.ValueKind.Equals(JsonValueKind.True))
- {
- optNo = 1;
- }
- groupList.optNo = optNo;
- groupList.joinLock = _joinLock.GetInt32();
- groupList.review = _review.GetInt32();
- //更新
- groupList = await clientTeacher.ReplaceItemAsync(groupList, $"{groupList.id}", new PartitionKey(groupList.code));
- return Ok(new { code = 200 });
- }
- catch (Exception ex)
- {
- await _dingDing.SendBotMsg($"{_option.Location},课程处理异常,{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
- return Ok(new { code = 500, msg = ex.Message });
- }
- }
- /// <summary>
- /// 取得課程名單QRcode API
- /// </summary>
- /// <param name="request"></param>
- /// <returns></returns>
- [Authorize(Roles = "HiTeach")]
- [ProducesDefaultResponseType]
- [HttpPost("hiteach-get-courseqrcode")]
- public async Task<IActionResult> GetCourseQrcode(JsonElement request)
- {
- try
- {
- #region === 驗證身分 ===
- string id_token = HttpContext.GetXAuth("IdToken");
- if (string.IsNullOrEmpty(id_token)) return BadRequest();
- var jwt = new JwtSecurityToken(id_token);
- if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.OrdinalIgnoreCase)) return BadRequest();
- #endregion
- if (!request.TryGetProperty("courseName", out JsonElement _courseName)) return BadRequest();
- if (!request.TryGetProperty("teacherName", out JsonElement _teacherName)) return BadRequest();
- if (!request.TryGetProperty("groupListId", out JsonElement _groupListId)) return BadRequest();
- if (!request.TryGetProperty("courseTaskId", out JsonElement _courseTaskId)) return BadRequest();
- var clientTeacher = _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher);
- GroupList groupList = await clientTeacher.ReadItemAsync<GroupList>(_groupListId.GetString(), new PartitionKey($"GroupList"));
- #region === 網址轉換 ===
- string apiUrl = this.Request.GetRequestUrlAddress();
- // 解析URL
- Uri uri = new Uri(apiUrl);
- // 获取包含协议的主机部分
- string hostWithProtocol = uri.GetLeftPart(UriPartial.Authority);
- string longUrl = $"{hostWithProtocol}/joinclass?listName={groupList.name}&cusDesc=暫無資料&cusId={_courseTaskId.GetString()}&tName={_teacherName.GetString()}" +
- $"&listNo={groupList.no}&cusName={_courseName.GetString()}&m=前往加入課程:{_courseName.GetString()}{groupList.name}&o=1";
- string shortUrl = await GetShortUrl(Uri.EscapeUriString(longUrl));
- #endregion
- return Ok(new
- {
- code = 200,
- shortUrl = shortUrl,
- longUrl = $"{hostWithProtocol}/joinclass?listName={groupList.name}&cusId={_courseTaskId.GetString()}&tName={_teacherName.GetString()}&listNo={groupList.no}&cusName={_courseName.GetString()}&m=前往加入課程:{_courseName.GetString()}{groupList.name}&o=1",
- joinLock = groupList.joinLock,
- limitCount = groupList.limitCount,
- review = groupList.review,
- isOptionalSeat = groupList.optNo == 1 ? true : false,
- });
- }
- catch (Exception ex)
- {
- await _dingDing.SendBotMsg($"{_option.Location},API异常,{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
- return Ok(new { code = 500, msg = ex.Message });
- }
- }
- #endregion
- private string setActor(string school, string id)
- {
- if (!string.IsNullOrWhiteSpace(school))
- {
- return $"Local-{school.Trim()},{id}";
- }
- else
- {
- return id;
- }
- }
- /// <summary>
- /// 設定學習記錄互動的內容
- /// </summary>
- /// <param name="lessonBase"></param>
- /// <param name="school"></param>
- /// <param name="lessonId"></param>
- /// <param name="iRSItem"></param>
- /// <param name="timeLineEvent"></param>
- /// <param name="verb"></param>
- /// <param name="learnRecordItems"></param>
- /// <returns></returns>
- private async Task SetPopQuesLoadContent(ScoreLessonBase lessonBase, string school, string lessonId, IRSItem iRSItem, TimeLineEventPg timeLineEvent, string verb, List<LearnRecordItem> learnRecordItems, GroupList groupList)
- {
- for (int k = 0; k < lessonBase.student.Count; k++)
- {
- LearnRecordItem learnRecordItem = new();
- if (lessonBase.student[k].type == 2)
- {
- await getSchoolCode(school, lessonId, lessonBase.student[k].id, learnRecordItem, groupList);
- }
- else
- {// 非校內帳號
- learnRecordItem.actor = setActor(school, lessonBase.student[k].id);
- }
- string[] arrymd = lessonBase.summary.date.Split('.');
- string[] arrhms = lessonBase.summary.startTime.Split(':');
- DateTime dt = new DateTime(int.Parse(arrymd[0]), int.Parse(arrymd[1]), int.Parse(arrymd[2]), int.Parse(arrhms[0]), int.Parse(arrhms[1]), int.Parse(arrhms[2]));
- dt = dt.AddSeconds(timeLineEvent.Time);
- learnRecordItem.verb = verb;
- learnRecordItem.time = dt.ToUnixTimestamp();
- learnRecordItem.ID = timeLineEvent.Pgid;
- if (iRSItem.question.item[0].question == "_popquiz_" || iRSItem.question.item[0].question == "")
- {
- learnRecordItem.Desc = "隨堂問答";
- }
- else
- {
- learnRecordItem.Desc = iRSItem.question.item[0].question;
- }
- learnRecordItem.Points = iRSItem.question.exercise.knowledges;
- await setCorrectChoices(iRSItem, learnRecordItem);
- learnRecordItem.ExamQuesQty = null;
- learnRecordItem.TotalScore = null;
- iRSItem.clientAnswers.TryGetProperty("0", out JsonElement anwersArr);
- if (anwersArr.ValueKind == JsonValueKind.Undefined)
- {// 沒有作答
- return;
- }
- else
- {
- List<List<string>> clientAnswersarr = anwersArr.ToJsonString().ToObject<List<List<string>>>();
- if (iRSItem.question.exercise.answer.SequenceEqual(clientAnswersarr[k]))
- {
- learnRecordItem.Success = true;
- }
- else
- {
- learnRecordItem.Success = false;
- }
- learnRecordItems.Add(learnRecordItem);
- }
- }
- }
- /// <summary>
- /// 取得學校簡碼
- /// </summary>
- /// <param name="school"></param>
- /// <param name="lessonId"></param>
- /// <param name="studentId"></param>
- /// <param name="learnRecordItem"></param>
- /// <returns></returns>
- private async Task getSchoolCode(string school, string lessonId, string studentId, LearnRecordItem learnRecordItem, GroupList groupList)
- {
- if (string.IsNullOrWhiteSpace(school))
- {// 如果沒有學校代碼 需要用lessonId去DB取學校代碼
-
- if (!string.IsNullOrWhiteSpace(groupList.school))// 如果沒有撈到schoolid防呆
- {
- learnRecordItem.actor = $"Base-{groupList.school.Trim()},{studentId}";
- }
- else
- {
- learnRecordItem.actor = studentId;
- }
- }
- else
- {// 如果有學校代碼 校內帳號用組合的 "Base-hbgl,473891247381"
- learnRecordItem.actor = $"Base-{school.Trim()},{studentId}";
- }
- }
- /// <summary>
- /// 設定CorrectChoices的邏輯
- /// </summary>
- /// <param name="iRSItems"></param>
- /// <param name="learnRecordItem"></param>
- /// <returns></returns>
- private async Task setCorrectChoices(IRSItem iRSItem, LearnRecordItem learnRecordItem)
- {
- #region === Correct Choices ===
- #region === 是非題邏輯 ===
- if (iRSItem.question.exercise.type == "judge" && iRSItem.question.exercise.answer.Count > 0)
- {// 如果是是非題 正確答案要用true false的方式設定
- if (iRSItem.question.exercise.answer[0] == "A")
- {
- learnRecordItem.Correct = new string[] { "true" };
- }
- else
- {
- learnRecordItem.Correct = new string[] { "false" };
- }
- }
- else
- {
- learnRecordItem.Correct = iRSItem.question.exercise.answer;
- }
- #endregion
- if (iRSItem.question.item[0].option.Count > 0)
- {// 如果有選項資料 記錄起來
- foreach (var option in iRSItem.question.item[0].option)
- {
- ChoicesItem item = new();
- item.id = option.code;
- if (iRSItem.question.exercise.type == "judge")
- {// 如果是是非題 固定選項
- if (option.code == "A")
- {
- item.description.zhTW = "是";
- }
- else
- {
- item.description.zhTW = "否";
- }
- }
- else
- {
- if (string.IsNullOrWhiteSpace(option.value))
- {
- item.description.zhTW = $"選項{option.code}";
- }
- else
- {
- item.description.zhTW = option.value;
- }
- }
- learnRecordItem.Choices.Add(item);
- }
- }
- #endregion
- }
- /// <summary>
- /// 创建课堂开课记录(新版)
- /// </summary>
- /// <param name="request"></param>
- /// <returns></returns>
- #if !DEBUG
- [Authorize(Roles = "HiTeach")]
- #endif
- [ProducesDefaultResponseType]
- [HttpPost("create-lesson")]
- public async Task<IActionResult> CreateLesson(CreateLessondRequest request)
- {
- try
- {
- string id_token = HttpContext.GetXAuth("IdToken");
- //判斷ID Token
- if (string.IsNullOrWhiteSpace(id_token)) return BadRequest();
- var jwt = new JwtSecurityToken(id_token);
- if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.OrdinalIgnoreCase)) return BadRequest();
- var tid = jwt.Payload.Sub;
- //初始化
- var r8 = _azureRedis.GetRedisClient(8);
- var db = _azureCosmos.GetCosmosClient();
- var sbm = new List<ServiceBusMessage>();
- var sp = request.sp.Equals("school", StringComparison.OrdinalIgnoreCase);
- int size = 0; //學校或個人總空間
- int tsize = 0; //學校分配給老師的總空間
- double usize = 0; //學校或個人已使用空間
- string timezone = string.Empty;
- string schoolArea = string.Empty;
- if (sp)
- {
- //取得學校資訊
- if (string.IsNullOrWhiteSpace(request.school)) return BadRequest();
- await foreach (var item in db.GetContainer(Constant.TEAMModelOS, Constant.School).GetItemQueryStreamIteratorSql(
- queryText: $"SELECT TOP 1 c.id, c.size, c.tsize, c.timeZone FROM c WHERE c.id = '{request.school}'",
- requestOptions: new() { PartitionKey = new("Base") }))
- {
- using var json = await JsonDocument.ParseAsync(item.Content);
- if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
- {
- var school = json.RootElement.GetProperty("Documents").EnumerateArray().First();
- timezone = school.GetProperty("timeZone").GetProperty("value").GetString();
- size = school.GetProperty("size").GetInt32();
- tsize = school.TryGetProperty("tsize", out var tsvalue) ? tsvalue.GetInt32() : 0;
- schoolArea=school.TryGetProperty("areaId", out var areaId) ? $"{areaId}" : string.Empty;
- }
- else return BadRequest();
- }
- }
- else
- {
- Teacher teacher = await db.GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemAsync<Teacher>(tid, new PartitionKey("Base"));
- size = teacher.size;
- foreach (var school in teacher.schools)
- {
- try
- {
- SchoolTeacher st = await db.GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemAsync<SchoolTeacher>(tid, new PartitionKey($"Teacher-{school.schoolId}"));
- size += st.size;
- }
- catch (CosmosException)
- {
- }
- }
- }
- (long usedSize, long teach, long total, long surplus, Dictionary<string, double?> catalog) space = await BlobService.GetSurplusSpace($"{(sp ? request.school : tid)}", request.sp, _option.Location, _azureCosmos, _azureRedis, _azureStorage, _dingDing, _httpTrigger);
- //計算學校或個人的使用空間
- // RedisValue redisValue = r8.HashGet($"Blob:Record", $"{(sp ? request.school : tid)}");
- if (space.usedSize > 0)
- {
- usize = Math.Round(space.usedSize / 1073741824.0 - (sp ? tsize : 0), 2, MidpointRounding.AwayFromZero); //1073741824 1G
- }
- else //如果檢測不到緩存,觸發刷新計算空間
- {
- await BlobService.RefreshBlobRoot(new BlobRefreshMessage { progress = "update", root = "records", name = $"{(sp ? request.school : tid)}" }, _serviceBus, _configuration, _azureRedis);
- }
- //取得學校或個人名單
- (List<RMember> students, _) = await GroupListService.GetMemberByListids(_coreAPIHttpService, db, _dingDing, new List<string>() { request.sid }, request.school);
-
- string imeiType = string.Empty;
- if (_option.Location.Contains("China", StringComparison.OrdinalIgnoreCase))
- {
- //觸發IMEI更新消息
- imeiType = "tianbo";
- if (ThirdIRSController.areaSchools.TryGetValue(request.sid, out (string scope, string imeiType) valg) && valg.scope.Equals("grouplist"))
- {
- imeiType=valg.imeiType;
- }
- else {
- if(!string.IsNullOrWhiteSpace(request.school))
- {
- if (ThirdIRSController.areaSchools.TryGetValue(request.school, out (string scope, string imeiType) vals) && vals.scope.Equals("school"))
- {
- imeiType=vals.imeiType;
- }
- else
- {
- if (ThirdIRSController.areaSchools.TryGetValue(schoolArea, out (string scope, string imeiType) vala) && vala.scope.Equals("area"))
- {
- imeiType=vala.imeiType;
- }
- }
- }
- }
- var stus = students.Select(x => x.id).ToList();
- if (stus.IsNotEmpty() && !string.IsNullOrWhiteSpace(request.school))
- {
- string sql = $"select value count(1) from c where c.stuid in({string.Join (",",stus.Select(x=>$"'{x}'"))}) and c.school='{request.school}' ";
- var result = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Student).GetList<int>(sql, "Imei");
- if (result.list.IsNotEmpty() && result.list[0]>0)
- {
- var imeimsg = new ServiceBusMessage(new { request.channel, userid = request.did, request.school, stus, imeiType }.ToJsonString());
- imeimsg.ApplicationProperties.Add("name", "Imei");
- sbm.Add(imeimsg);
- }
- else {
- imeiType=string.Empty;
- }
- }
- }
- //開課記錄保存
- LessonRecord lr = new()
- {
- school = request.sp.Equals("school") ? request?.school : null,
- code = request.sp.Equals("school") ? $"LessonRecord-{request.school}" : $"LessonRecord",
- id = _snowflakeId.NextId().ToString(), //取得授課ID
- courseId = request.cid,
- groupIds = new() { request.sid },
- tmdid = tid,
- scope = request.sp,
- pk = "LessonRecord",
- name = request.cname,
- startTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
- };
- await db.GetContainer(Constant.TEAMModelOS, request.sp.Equals("school") ? "School" : "Teacher").CreateItemAsync(lr, new PartitionKey(lr.code));
- //觸發開課統計
- var messageChange = new ServiceBusMessage(lr.ToJsonString());
- messageChange.ApplicationProperties.Add("name", "LessonRecordEvent");
- sbm.Add(messageChange);
- //批量發送消息
- await _serviceBus.GetServiceBusClient().SendBatchMessageAsync(_configuration.GetValue<string>("Azure:ServiceBus:ActiveTask"), sbm);
- if (sp && usize > size)
- {
- ////处理学校开课,空间不足时。检查是否有 当前教师tid,强制保存save<>1,没有标记未删除status<>404,没有被收藏favorite<=0 ,时间最旧的一条记录startTime
- LessonRecord lessonRecord = null;
- string sql = $"SELECT top 1 value(c) FROM c where ( c.expire<=0 or IS_DEFINED(c.expire) = false ) and c.tmdid='{tid}' and c.save<>1 and c.status<>404 and c.favorite<=0 order by c.startTime ";
- await foreach (var item in db.GetContainer(Constant.TEAMModelOS, Constant.School).GetItemQueryIteratorSql<LessonRecord>(
- queryText: sql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"LessonRecord-{request.school}") }))
- {
- lessonRecord = item;
- break;
- }
- if (lessonRecord != null)
- {
- lessonRecord.status = 404;
- await db.GetContainer(Constant.TEAMModelOS, Constant.School).ReplaceItemAsync(lessonRecord, lessonRecord.id, new PartitionKey(lessonRecord.code));
- var ActiveTask = _configuration.GetValue<string>("Azure:ServiceBus:ActiveTask");
- var messageChangeEvent = new ServiceBusMessage(request.ToJsonString());
- messageChangeEvent.ApplicationProperties.Add("name", "LessonRecordEvent");
- await _serviceBus.GetServiceBusClient().SendMessageAsync(ActiveTask, messageChangeEvent);
- //保证客户端可以正常开课。
- usize -= 1;
- }
- else
- { //没有找到匹配当前 教师tid,save<>1,status<>404,没有被收藏,时间最旧的一条记录。无法手动再继续 usize -= 1;,则不能继续开课。
- }
- }
- return Ok(new { status = 200, lr.id, students, size, usize, imeiType });
- }
- catch (Exception ex)
- {
- await _dingDing.SendBotMsg($"IES5,{_option.Location}, hiteach/create-lesson:()\n{ex.Message}\n{ex.StackTrace}{request.ToJsonString()}", GroupNames.醍摩豆服務運維群組);
- return BadRequest();
- }
- }
- /// <summary>
- /// 创建课堂开课记录(舊版,已被CreateLesson取代)
- /// </summary>
- /// <param name="request"></param>
- /// <returns></returns>
- [Authorize(Roles = "HiTeach")]
- [ProducesDefaultResponseType]
- [HttpPost("create-lesson-record")]
- public async Task<IActionResult> CreateLessonRecord(JsonElement request)
- {
- if (!request.TryGetProperty("lesson", out JsonElement _lesson)) return BadRequest();
- var client = _azureCosmos.GetCosmosClient();
- LessonRecord lessonRecord = _lesson.ToObject<LessonRecord>();
- int blobTotal = 0;
- long teach = 0;
- string blobName = "";
- if (!string.IsNullOrEmpty(lessonRecord.scope) && !string.IsNullOrEmpty(lessonRecord.tmdid) && !string.IsNullOrEmpty(lessonRecord.id))
- {
- string tbname = null;
- if (lessonRecord.scope.Equals("school") && !string.IsNullOrEmpty(lessonRecord.school))
- {
- School school = await client.GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemAsync<School>(lessonRecord.school, new PartitionKey("Base"));
- lessonRecord.code = $"LessonRecord-{lessonRecord.school}";
- tbname = "School";
- blobTotal = school.size;
- //计算分配给学校教师的空间
- await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIteratorSql(queryText: $"SELECT sum(c.size) as size FROM c ",
- requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Teacher-{lessonRecord.school}") }))
- {
- var json = await JsonDocument.ParseAsync(item.Content);
- foreach (var elmt in json.RootElement.GetProperty("Documents").EnumerateArray())
- {
- if (elmt.TryGetProperty("size", out JsonElement _size) && _size.ValueKind.Equals(JsonValueKind.Number))
- {
- teach = _size.GetInt32();
- break;
- }
- }
- }
- blobName = lessonRecord.school;
- }
- if (lessonRecord.scope.Equals("private"))
- {
- lessonRecord.code = $"LessonRecord";
- tbname = "Teacher";
- Teacher teacher = await client.GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemAsync<Teacher>(lessonRecord.tmdid, new PartitionKey("Base"));
- blobTotal = teacher.size;
- foreach (var school in teacher.schools)
- {
- SchoolTeacher st = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<SchoolTeacher>(lessonRecord.tmdid, new PartitionKey($"Teacher-{school.schoolId}"));
- blobTotal += st.size;
- }
- blobName = lessonRecord.tmdid;
- }
- RedisValue redisValue = _azureRedis.GetRedisClient(8).HashGet($"Blob:Record", $"{blobName}");
- long blobsize = 0;
- if (redisValue != default && !redisValue.IsNullOrEmpty)
- {
- JsonElement record = redisValue.ToString().ToObject<JsonElement>();
- if (record.TryGetInt64(out blobsize))
- {
- }
- }
- else
- {
- await BlobService.RefreshBlobRoot(new BlobRefreshMessage { progress = "update", root = "records", name = $"{blobName}" }, _serviceBus, _configuration, _azureRedis);
- }
- double blobUsed = blobsize / 1073741824.0 + teach; //1073741824 1G
- if (tbname == null)
- {
- return BadRequest("参数异常:scope应为school或private,scope=school ,school字段不能为空");
- }
- if (lessonRecord.startTime == 0)
- {
- lessonRecord.startTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
- }
- lessonRecord.pk = "LessonRecord";
- try
- {
- await client.GetContainer(Constant.TEAMModelOS, tbname).CreateItemAsync(lessonRecord, new PartitionKey(lessonRecord.code));
- var ActiveTask = _configuration.GetValue<string>("Azure:ServiceBus:ActiveTask");
- var messageChange = new ServiceBusMessage(lessonRecord.ToJsonString());
- messageChange.ApplicationProperties.Add("name", "LessonRecordEvent");
- await _serviceBus.GetServiceBusClient().SendMessageAsync(ActiveTask, messageChange);
- return Ok(new { status = 200, blobTotal, blobUsed });
- }
- catch (Exception ex)
- {
- await _dingDing.SendBotMsg($"IES5,{_option.Location}, hiteach/create-lesson-record:()\n{ex.Message}\n{ex.StackTrace}{request.ToJsonString()}", GroupNames.醍摩豆服務運維群組);
- return BadRequest();
- }
- }
- else
- {
- return BadRequest();
- }
- }
- [Authorize(Roles = "HiTeach")]
- [ProducesDefaultResponseType]
- [HttpPost("get-teacher-info")]
- public async Task<IActionResult> GetTeacherInfo()
- {
- //Debug
- //string json = System.Text.Json.JsonSerializer.Serialize(id_token);
- try
- {
- string id_token = HttpContext.GetXAuth("IdToken");
- (string ip, string region) = await LoginService.LoginIp(HttpContext, _searcher);
- if (string.IsNullOrEmpty(id_token)) return BadRequest();
- var jwt = new JwtSecurityToken(id_token);
- if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.OrdinalIgnoreCase)) return BadRequest();
- var id = jwt.Payload.Sub;
- jwt.Payload.TryGetValue("name", out object name);
- jwt.Payload.TryGetValue("picture", out object picture);
- List<object> schools = new List<object>();
- string defaultschool = null;
- //TODK 取得Teacher 個人相關數據(課程清單、虛擬教室清單、歷史紀錄清單等),學校數據另外API處理,多校切換時不同
- var client = _azureCosmos.GetCosmosClient();
- var response = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemStreamAsync(id, new PartitionKey("Base"));
- if (response.StatusCode==System.Net.HttpStatusCode.OK)
- {
- var jsonsc = await JsonDocument.ParseAsync(response.Content);
- if (jsonsc.RootElement.TryGetProperty("schools", out JsonElement value))
- {
- GetTeacherInfoApiSchool schoolExtobj;
- foreach (var obj in value.EnumerateArray())
- {
- string statusNow = obj.GetProperty("status").ToString();
- if (statusNow.Equals("join")) //成為老師的才放入
- {
- var schoolJson = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync($"{obj.GetProperty("schoolId")}", new PartitionKey("Base"));
- if (schoolJson.StatusCode==System.Net.HttpStatusCode.OK)
- {
- var school = await JsonDocument.ParseAsync(schoolJson.Content);
- schoolExtobj = new GetTeacherInfoApiSchool();
- schoolExtobj.schoolId = Convert.ToString(obj.GetProperty("schoolId"));
- schoolExtobj.name = Convert.ToString(school.RootElement.GetProperty("name"));
- schoolExtobj.status = Convert.ToString(obj.GetProperty("status"));
- schoolExtobj.picture = Convert.ToString(school.RootElement.GetProperty("picture"));
- schools.Add(schoolExtobj);
- var sctch = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(id, new PartitionKey($"Teacher-{obj.GetProperty("schoolId")}"));
- if (sctch.StatusCode==System.Net.HttpStatusCode.OK && sctch != null && sctch.Content != null)
- {
- var jsonDoc = await JsonDocument.ParseAsync(sctch.Content);
- SchoolTeacher schoolTeacher = jsonDoc.RootElement.ToObject<SchoolTeacher>();
- }
- }
- }
- }
- }
- //預設學校ID
- if (jsonsc.RootElement.TryGetProperty("defaultSchool", out JsonElement valueD) && !string.IsNullOrEmpty(valueD.ToString()))
- {
- defaultschool = valueD.ToString();
- }
- }
- else
- {
- //如果沒有,則初始化Teacher基本資料到Cosmos
- Teacher teacher = new Teacher
- {
- createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
- id = id,
- pk = "Base",
- code = "Base",
- name = name?.ToString(),
- picture = picture?.ToString(),
- //创建账号并第一次登录IES5则默认赠送1G
- size = 1,
- defaultSchool = null,
- schools = new List<Teacher.TeacherSchool>(),
- };
- teacher = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync<Teacher>(teacher, new PartitionKey("Base"));
- }
- //老師個人課程清單 [新架構 Todo]
- List<GetTeacherInfoApiCourse> courses = new List<GetTeacherInfoApiCourse>();
- List<KeyValuePair<string, CourseTask>> privateTeacherTask = new List<KeyValuePair<string, CourseTask>>(); //老師的課程安排Dictionary key:courseId val:CourseTask
- List<KeyValuePair<string, CourseTask>> privateAssistantTask = new List<KeyValuePair<string, CourseTask>>();
- HashSet<string> courseIds = new HashSet<string>(); //有被安排的課程ID
- List<string> groupIds = new List<string>(); //班級團體ID
- List<CourseDto> teahcerCourses = new List<CourseDto>();
- string sqlCoursePrivate = $"select value c.id from c where c.creatorId='{id}'";
- var resultCourseBasePrivate = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<string>(sqlCoursePrivate, $"CourseBase"); //CourseID列表
- string sqlprivate = $"SELECT distinct value c FROM c join b in c.schedules where c.pk='CourseTask' and (ARRAY_CONTAINS(b.assistants,'{id}') or b.teacherId ='{id}' )";
- var resultTeacher = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<CourseTask>(sqlprivate, $"CourseTask");
- if (resultTeacher.list.IsNotEmpty())
- {
- resultTeacher.list.ForEach(x =>
- {
- var schedulesTeacher = x.schedules.Where(z => !string.IsNullOrWhiteSpace(z.teacherId) && z.teacherId.Equals(id));
- if (schedulesTeacher.Any())
- {
- courseIds.Add(x.courseId);
- CourseTask courseTask = x.ToJsonString().ToObject<CourseTask>();
- courseTask.schedules = schedulesTeacher.ToList();
- privateTeacherTask.Add(new KeyValuePair<string, CourseTask>(x.courseId, courseTask));
- groupIds.AddRange(schedulesTeacher.Where(z => !string.IsNullOrWhiteSpace(z.groupId)).Select(x => x.groupId));
- }
- var schedulesAssistant = x.schedules.Where(z => z.assistants.Contains(id));
- if (schedulesAssistant.Any())
- {
- courseIds.Add(x.courseId);
- CourseTask courseTask = x.ToJsonString().ToObject<CourseTask>();
- courseTask.schedules = schedulesAssistant.ToList();
- privateAssistantTask.Add(new KeyValuePair<string, CourseTask>(x.courseId, courseTask));
- groupIds.AddRange(schedulesAssistant.Where(z => !string.IsNullOrWhiteSpace(z.groupId)).Select(x => x.groupId));
- }
- });
- }
- //班級團體人數Dic
- Dictionary<string, GroupListMemberCnt> groupCntDic = new Dictionary<string, GroupListMemberCnt>();
- if (groupIds.Any())
- {
- string sqlGroup = $"SELECT c.code, c.id, c.name, c.scope, ARRAY_LENGTH(c.members) as memberCount FROM c WHERE c.id in ({string.Join(",", groupIds.Select(b => $"'{b}'"))})";
- var resultGroup = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<GroupListMemberCnt>(sqlGroup, $"GroupList");
- if (resultGroup.list.IsNotEmpty())
- {
- foreach (GroupListMemberCnt groupData in resultGroup.list)
- {
- groupCntDic.Add(groupData.id, groupData);
- }
- }
- }
- if (courseIds.Any())
- {
- GetTeacherInfoApiCourse courseExtobj;
- List<GetTeacherInfoApiCourseClass> classes;
- string sqlCourse = $"select value c from c where c.id in ({string.Join(",", courseIds.Select(b => $"'{b}'"))})";
- //string sqlCourse = $"select value c from c where c.creatorId='{id}' and c.id in ({string.Join(",", courseIds.Select(b => $"'{b}'"))})";
- var result = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<CourseBase>(sqlCourse, $"CourseBase");
- if (result.list.IsNotEmpty())
- {
- foreach (var item in result.list)
- {
- courseExtobj = new GetTeacherInfoApiCourse();
- courseExtobj.id = item.id;
- courseExtobj.name = item.name;
- courseExtobj.scope = item.scope;
- classes = new List<GetTeacherInfoApiCourseClass>();
- //任教教師
- //List<CourseTaskDto> courseTaskDtos = new List<CourseTaskDto>();
- var teacher = privateTeacherTask.Where(x => x.Key.Equals(item.id)).Select(z => new CourseTaskDto { courseTask = z.Value, type = "teacher" });
- if (teacher.Any())
- {
- List<CourseTaskDto> teacherList = teacher.ToList();
- foreach (CourseTaskDto teacherTaskDto in teacherList)
- {
- List<ScheduleTask> schedules = teacherTaskDto.courseTask.schedules;
- foreach (ScheduleTask schedule in schedules)
- {
- GetTeacherInfoApiCourseClass classExtobj = new GetTeacherInfoApiCourseClass();
- classExtobj.code = null;
- classExtobj.scope = (groupCntDic.ContainsKey(schedule.groupId)) ? groupCntDic[schedule.groupId].scope : string.Empty; ;
- classExtobj.name = (groupCntDic.ContainsKey(schedule.groupId)) ? groupCntDic[schedule.groupId].name : string.Empty;
- classExtobj.stuListId = schedule.groupId;
- classExtobj.teacher = new GetTeacherInfoApiSimlpeBase() { id = id, name = name?.ToString() };
- classExtobj.stuCnt = (groupCntDic.ContainsKey(schedule.groupId)) ? groupCntDic[schedule.groupId].memberCount : 0;
- classExtobj.grpCnt = 0;
- classExtobj.gradeId = null;
- classExtobj.year = 0;
- classes.Add(classExtobj);
- }
- }
- }
- //協同教師
- var assistant = privateAssistantTask.Where(x => x.Key.Equals(item.id)).Select(z => new CourseTaskDto { courseTask = z.Value, type = "assistant" });
- if (assistant.Any())
- {
- List<CourseTaskDto> assistantList = assistant.ToList();
- foreach (CourseTaskDto assistantTaskDto in assistantList)
- {
- List<ScheduleTask> schedules = assistantTaskDto.courseTask.schedules;
- foreach (ScheduleTask schedule in schedules)
- {
- GetTeacherInfoApiCourseClass classExtobj = new GetTeacherInfoApiCourseClass();
- classExtobj.code = null;
- classExtobj.scope = (groupCntDic.ContainsKey(schedule.groupId)) ? groupCntDic[schedule.groupId].scope : string.Empty; ;
- classExtobj.name = (groupCntDic.ContainsKey(schedule.groupId)) ? groupCntDic[schedule.groupId].name : string.Empty;
- classExtobj.stuListId = schedule.groupId;
- classExtobj.teacher = new GetTeacherInfoApiSimlpeBase() { id = id, name = name?.ToString() };
- classExtobj.stuCnt = (groupCntDic.ContainsKey(schedule.groupId)) ? groupCntDic[schedule.groupId].memberCount : 0;
- classExtobj.grpCnt = 0;
- classExtobj.gradeId = null;
- classExtobj.year = 0;
- classes.Add(classExtobj);
- }
- }
- }
- courseExtobj.classes = classes;
- courses.Add(courseExtobj);
- }
- }
- }
- //老師個人課程清單 [舊架構]
- //await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryStreamIteratorSql(queryText: $"SELECT c.id, c.name, c.schedule, c.scope FROM c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Course-{id}") }))
- //{
- // var jsontcs = await JsonDocument.ParseAsync(item.Content);
- // if (jsontcs.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
- // {
- // GetTeacherInfoApiCourse courseExtobj;
- // List<GetTeacherInfoApiCourseClass> classes;
- // foreach (var obj in jsontcs.RootElement.GetProperty("Documents").EnumerateArray())
- // {
- // courseExtobj = new GetTeacherInfoApiCourse();
- // courseExtobj.id = Convert.ToString(obj.GetProperty("id"));
- // courseExtobj.name = Convert.ToString(obj.GetProperty("name"));
- // courseExtobj.scope = Convert.ToString(obj.GetProperty("scope"));
- // classes = new List<GetTeacherInfoApiCourseClass>();
- // if (obj.TryGetProperty("schedule", out JsonElement schedule))
- // {
- // GetTeacherInfoApiCourseClass classExtobj;
- // foreach (var scheduleobj in schedule.EnumerateArray())
- // {
- // classExtobj = new GetTeacherInfoApiCourseClass();
- // classExtobj.id = null;
- // classExtobj.code = null;
- // classExtobj.teacher = null;
- // if (scheduleobj.TryGetProperty("teacherId", out JsonElement teacherId) && !string.IsNullOrWhiteSpace(Convert.ToString(teacherId)))
- // {
- // await foreach (var teaitem in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryStreamIteratorSql(queryText: $"SELECT c.id, c.name FROM c WHERE c.id = '{teacherId}'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base") }))
- // {
- // var jsontea = await JsonDocument.ParseAsync(teaitem.Content);
- // foreach (var teaobj in jsontea.RootElement.GetProperty("Documents").EnumerateArray())
- // {
- // classExtobj.teacher = new GetTeacherInfoApiSimlpeBase();
- // classExtobj.teacher = teaobj.ToObject<GetTeacherInfoApiSimlpeBase>();
- // }
- // }
- // }
- // classExtobj.scope = "private";
- // int stuCount = 0;
- // string stuListId = Convert.ToString(scheduleobj.GetProperty("stulist"));
- // classExtobj.stuListId = stuListId;
- // await foreach (var stuitem in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryStreamIteratorSql(queryText: $"SELECT c.id, c.name, c.tcount, c.scount FROM c WHERE c.id = '{stuListId}'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("GroupList") }))
- // {
- // //取得學生總數
- // var jsonstu = await JsonDocument.ParseAsync(stuitem.Content);
- // foreach (var stuobj in jsonstu.RootElement.GetProperty("Documents").EnumerateArray())
- // {
- // classExtobj.name = Convert.ToString(stuobj.GetProperty("name"));
- // stuCount += stuobj.GetProperty("scount").GetInt32();
- // stuCount += stuobj.GetProperty("tcount").GetInt32();
- // }
- // }
- // classExtobj.stuCnt = stuCount;
- // classExtobj.grpCnt = 0;
- // classExtobj.gradeId = null;
- // classExtobj.year = 0;
- // classes.Add(classExtobj);
- // }
- // }
- // courseExtobj.classes = classes;
- // courses.Add(courseExtobj);
- // }
- // }
- //}
- //取得老師個人評測
- List<object> exams = new List<object>();
- //取得評測ID List (HiTeach只取source='1'(課中评量) && progress = 'going'(進行中))
- List<string> examIdList = new List<string>();
- await foreach (var exam in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryStreamIteratorSql(queryText: $"SELECT c.id FROM c where (c.status<>404 or IS_DEFINED(c.status) = false ) and c.source = '1' AND c.progress = 'going'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Exam-{id}") }))
- {
- using var json = await JsonDocument.ParseAsync(exam.Content);
- if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
- {
- foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
- {
- examIdList.Add(obj.GetProperty("id").GetString());
- }
- }
- }
- //取得有作答的評測班級
- Dictionary<string, List<string>> examClassFinDic = new Dictionary<string, List<string>>();
- await foreach (var exam in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryStreamIteratorSql(queryText: $"SELECT c.examId, c.info.id as classId FROM c where (c.status<>404 or IS_DEFINED(c.status) = false ) and ARRAY_CONTAINS({JsonSerializer.Serialize(examIdList)}, c.examId) AND c.progress=true", requestOptions: new QueryRequestOptions() { }))
- {
- var jsonecr = await JsonDocument.ParseAsync(exam.Content);
- if (jsonecr.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
- {
- foreach (var obj in jsonecr.RootElement.GetProperty("Documents").EnumerateArray())
- {
- string examId = obj.GetProperty("examId").ToString();
- string classId = obj.GetProperty("classId").ToString();
- if (examClassFinDic.ContainsKey(examId) && !examClassFinDic[examId].Contains(classId))
- {
- examClassFinDic[examId].Add(classId);
- }
- else
- {
- List<string> classIdList = new List<string>();
- classIdList.Add(classId);
- examClassFinDic.Add(examId, classIdList);
- }
- }
- }
- }
- //取得評測資料
- await foreach (var exam in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryStreamIteratorSql(queryText: $"SELECT c.code, c.id, c.name, c.createTime, c.startTime, c.endTime ,c.year, c.source, c.type, c.progress, c.stuCount, c.scope, c.owner, c.period, c.grades, c.subjects, c.classes, c.stuLists, ARRAY(SELECT p.id, p.code, p.name, p.blob, p.scope FROM p IN c.papers) AS papers FROM c WHERE ARRAY_CONTAINS({JsonSerializer.Serialize(examIdList)}, c.id)", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Exam-{id}") }))
- {
- var jsonex = await JsonDocument.ParseAsync(exam.Content);
- if (jsonex.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
- {
- dynamic examExtobj;
- foreach (var obj in jsonex.RootElement.GetProperty("Documents").EnumerateArray())
- {
- examExtobj = new ExpandoObject();
- string examId = obj.GetProperty("id").GetString();
- examExtobj.code = obj.GetProperty("code");
- examExtobj.id = examId;
- examExtobj.name = obj.GetProperty("name");
- examExtobj.createTime = obj.GetProperty("createTime");
- examExtobj.startTime = obj.GetProperty("startTime");
- examExtobj.endTime = obj.GetProperty("endTime");
- examExtobj.year = obj.GetProperty("year");
- examExtobj.source = obj.GetProperty("source");
- examExtobj.type = obj.GetProperty("type");
- examExtobj.progress = obj.GetProperty("progress");
- examExtobj.stuCount = obj.GetProperty("stuCount");
- examExtobj.scope = obj.GetProperty("scope");
- examExtobj.owner = obj.GetProperty("owner");
- examExtobj.period = obj.GetProperty("period");
- examExtobj.grades = obj.GetProperty("grades");
- examExtobj.subjects = obj.GetProperty("subjects");
- examExtobj.classes = (obj.TryGetProperty("classes", out JsonElement classes)) ? classes.ToObject<List<string>>() : new List<string>();
- examExtobj.stuLists = (obj.TryGetProperty("stuLists", out JsonElement stuLists)) ? stuLists.ToObject<List<string>>() : new List<string>();
- examExtobj.finishClasses = (examClassFinDic.ContainsKey(examId)) ? examClassFinDic[examId] : new List<string>();
- examExtobj.papers = obj.GetProperty("papers");
- //examExtobj = obj.ToObject<object>();
- exams.Add(examExtobj);
- }
- }
- }
- //用户在线记录
- //try
- //{
- // _ = _httpTrigger.RequestHttpTrigger(new { school = defaultschool, scope = $"{Constant.ScopeTeacher}", id = $"{id}", ip = $"{ip}", expire = 1 }, _option.Location, "online-record");
- //}
- //catch { }
- //取得Teacher Blob 容器位置及SAS
- var container = _azureStorage.GetBlobContainerClient(id);
- await container.CreateIfNotExistsAsync(PublicAccessType.None); //嘗試創建Teacher私有容器,如存在則不做任何事,保障容器一定存在
- var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(id, BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Delete);
- var (blob_uri_read, blob_sas_read) = _azureStorage.GetBlobContainerSAS(id, BlobContainerSasPermissions.Read);
- var (blob_uri_write, blob_sas_write) = _azureStorage.GetBlobContainerSAS(id, BlobContainerSasPermissions.Write);
- await SystemService.RecordAccumulateData(_azureRedis, _dingDing, new SDK.Models.Dtos.Accumulate { client = "hiteach", count = 1, id = "ies", key = "tmd_login", name = "醍摩豆账号登录", scope = "ies", target = "ies" });
- return Ok(new { blob_uri, blob_sas, blob_sas_read, blob_sas_write, schools, defaultschool, courses, exams });
- }
- catch (Exception ex)
- {
- await _dingDing.SendBotMsg($"IES5,{_option.Location},hiteach/GetTeacherInfo()\n{ex.Message}\n{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
- return BadRequest();
- }
- }
- [Authorize(Roles = "HiTeach")]
- [ProducesDefaultResponseType]
- [HttpPost("get-school-info")]
- public async Task<IActionResult> GetSchoolInfo(JsonElement request)
- {
- try
- {
- DateTime nowDate = DateTime.Now;
- string id_token = HttpContext.GetXAuth("IdToken");
- (string ip, string region) = await LoginService.LoginIp(HttpContext, _searcher);
- if (string.IsNullOrEmpty(id_token)) return BadRequest();
- if (!request.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
- var jwt = new JwtSecurityToken(id_token);
- if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.Ordinal)) return BadRequest();
- var id = jwt.Payload.Sub;
- string inputPeriodId = (request.TryGetProperty("periodId", out JsonElement _periodId)) ? _periodId.ToString() : string.Empty; //若未輸入periodId,則所有的學段課程都取
- var client = _azureCosmos.GetCosmosClient();
- //取得學校學段、年級、科目、考試類型
- List<object> periods = new List<object>();
- List<object> grades = new List<object>();
- List<object> subjects = new List<object>();
- List<object> examTypes = new List<object>();
- List<string> periodIds = new List<string>(); //學段ID 取得課程時限制用
- string lang = "en-us";
- School school_base = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>($"{school_code}", new PartitionKey("Base"));
- if (!string.IsNullOrWhiteSpace(school_base.id))
- {
- //語系取得
- if (!string.IsNullOrEmpty(school_base.region))
- {
- if (school_base.region.Equals("中国")) lang = "zh-cn";
- else if (school_base.region.Equals("臺灣")) lang = "zh-tw";
- }
- else
- {
- if (_option.Location.Equals("China")) lang = "zh-cn";
- }
- //年級、科目、評測類型取得
- foreach (Period periodinfo in school_base.period)
- {
- if (!string.IsNullOrWhiteSpace(inputPeriodId))
- {
- if (!periodinfo.id.Equals(inputPeriodId)) continue; //若有給periodId,則過濾學段;未給則全取
- }
- periods.Add(new { id = periodinfo.id, name = periodinfo.name, subjects = periodinfo.subjects });
- periodIds.Add(periodinfo.id);
- int gradeIndex = 0;
- foreach (string gradeName in periodinfo.grades)
- {
- grades.Add(new { id = gradeIndex.ToString(), name = gradeName, periodId = periodinfo.id });
- gradeIndex++;
- }
- foreach (Subject subjectinfo in periodinfo.subjects)
- {
- subjects.Add(new { id = subjectinfo.id, name = subjectinfo.name, periodId = periodinfo.id });
- }
- foreach (var examType in periodinfo.analysis.type)
- {
- examTypes.Add(examType);
- }
- }
- }
- else //無此學校資料
- {
- return BadRequest();
- }
- //該老師排定的學校課程
- List<object> courses = new List<object>();
- List<string> classIds = new List<string>(); //班級ID列表 篩選校園評測用
- List<string> groupIds = new List<string>(); //團體ID列表 篩選校園評測用
- //取得所有班级
- (List<Class> school_classes, _) = await SchoolService.DoGraduateClasses(_httpTrigger, _azureCosmos, null, school_base, _option, _dingDing);
- //取得學校安排老師課程
- HashSet<string> courseIds = new HashSet<string>();
- List<KeyValuePair<string, CourseTask>> schoolTeacherTask = new List<KeyValuePair<string, CourseTask>>(); //key:courseId value:CourseTask
- List<KeyValuePair<string, CourseTask>> schoolAssistantTask = new List<KeyValuePair<string, CourseTask>>();
- List<string> periodIdList = new List<string>();
- if (string.IsNullOrWhiteSpace(inputPeriodId)) periodIdList = periodIds;
- else periodIdList.Add(inputPeriodId);
- Dictionary<string, GroupListMemberCnt> groupCntDic = new Dictionary<string, GroupListMemberCnt>(); //班級團體+人數Dic
- foreach (string periodId in periodIdList)
- {
- var period = school_base.period.Find(x => x.id.Equals(periodId));
- (Semester currSemester, int studyYear, DateTimeOffset currSemesterDate, DateTimeOffset date, DateTimeOffset nextSemester) info = SchoolService.GetSemester(period, 0, nowDate.ToString());
- int studyYear = (request.TryGetProperty("year", out JsonElement _year)) ? _year.GetInt32() : info.studyYear;
- string semesterId = (request.TryGetProperty("semesterId", out JsonElement _semesterId)) ? _semesterId.GetString() : info.currSemester.id;
- //string date = SchoolService.GetOpensByStudyYearAndSemester(period.semesters, int.Parse($"{_year}"), $"{_semesterId}");
- string sql = $"SELECT distinct value c FROM c join b in c.schedules where c.pk='CourseTask' and ( b.teacherId ='{id}' OR ARRAY_CONTAINS(b.assistants,'{id}'))";
- sql = $"{sql} and c.year={studyYear} and c.semesterId='{semesterId}'";
- var resultSchool = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).GetList<CourseTask>(sql, $"CourseTask-{school_code}");
- if (resultSchool.list.IsNotEmpty())
- {
- resultSchool.list.ForEach(x =>
- {
- var schedulesTeacher = x.schedules.Where(z => !string.IsNullOrWhiteSpace(z.teacherId) && z.teacherId.Equals(id));
- if (schedulesTeacher.Any())
- {
- courseIds.Add(x.courseId);
- CourseTask courseTask = x.ToJsonString().ToObject<CourseTask>();
- courseTask.schedules = schedulesTeacher.ToList();
- schoolTeacherTask.Add(new KeyValuePair<string, CourseTask>(x.courseId, courseTask));
- groupIds.AddRange(schedulesTeacher.Where(z => !string.IsNullOrWhiteSpace(z.groupId)).Select(x => x.groupId));
- }
- var schedulesAssistant = x.schedules.Where(z => z.assistants.Contains(id));
- if (schedulesAssistant.Any())
- {
- courseIds.Add(x.courseId);
- CourseTask courseTask = x.ToJsonString().ToObject<CourseTask>();
- courseTask.schedules = schedulesAssistant.ToList();
- schoolAssistantTask.Add(new KeyValuePair<string, CourseTask>(x.courseId, courseTask));
- groupIds.AddRange(schedulesAssistant.Where(z => !string.IsNullOrWhiteSpace(z.groupId)).Select(x => x.groupId));
- }
- });
- }
- //班級團體人數Dic
- if (groupIds.Any())
- {
- string sqlGroup = $"SELECT c.code, c.id, c.name, c.scope, c.year, 'teach' as type, ARRAY_LENGTH(c.members) as memberCount FROM c WHERE c.id in ({string.Join(",", groupIds.Select(b => $"'{b}'"))})";
- var resultGroup = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).GetList<GroupListMemberCnt>(sqlGroup, $"GroupList-{school_code}");
- if (resultGroup.list.IsNotEmpty())
- {
- foreach (GroupListMemberCnt groupData in resultGroup.list)
- {
- if (!groupCntDic.ContainsKey(groupData.id))
- {
- groupCntDic.Add(groupData.id, groupData);
- }
- }
- }
- string sqlClass = $"SELECT c.code, c.id, c.name, c.scope, c.year, 'class' as type, 0 as memberCount FROM c WHERE c.id in ({string.Join(",", groupIds.Select(b => $"'{b}'"))})";
- var resultClass = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).GetList<GroupListMemberCnt>(sqlClass, $"Class-{school_code}");
- if (resultClass.list.IsNotEmpty())
- {
- foreach (GroupListMemberCnt groupData in resultClass.list)
- {
- if (!groupCntDic.ContainsKey(groupData.id))
- {
- groupCntDic.Add(groupData.id, groupData);
- }
- }
- }
- //取得學生數
- foreach (KeyValuePair<string, GroupListMemberCnt> groupCntItem in groupCntDic)
- {
- string classId = groupCntItem.Key;
- var sqlStudent = $"SELECT VALUE Count(1) FROM c WHERE c.classId = '{classId}'";
- await foreach (int itemclstc in client.GetContainer(Constant.TEAMModelOS, Constant.Student).GetItemQueryIteratorSql<int>(queryText: sqlStudent, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base-{school_code}") }))
- {
- if (itemclstc > 0)
- {
- groupCntDic[classId].memberCount = itemclstc;
- }
- }
- }
- }
- }
- if (courseIds.Any())
- {
- GetSchoolInfoApiCourse courseExtobj;
- List<GetTeacherInfoApiCourseClass> classes;
- string sqlCourse = $"select value c from c where c.id in ({string.Join(",", courseIds.Select(b => $"'{b}'"))})";
- var result = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).GetList<CourseBase>(sqlCourse, $"CourseBase-{school_code}");
- if (result.list.IsNotEmpty())
- {
- foreach (var item in result.list)
- {
- courseExtobj = new GetSchoolInfoApiCourse();
- courseExtobj.id = item.id;
- courseExtobj.name = item.name;
- courseExtobj.scope = item.scope;
- courseExtobj.subject = new GetTeacherInfoApiSimlpeBase();
- courseExtobj.subject.id = item.subject.id;
- courseExtobj.subject.name = item.subject.name;
- var period = school_base.period.Find(p => p.subjects.Exists(s => s.id.Equals(item.subject.id)));
- classes = new List<GetTeacherInfoApiCourseClass>();
- //任教教師
- //List<CourseTaskDto> courseTaskDtos = new List<CourseTaskDto>();
- var teacher = schoolTeacherTask.Where(x => x.Key.Equals(item.id)).Select(z => new CourseTaskDto { courseTask = z.Value, type = "teacher" });
- if (teacher.Any() && period != null)
- {
- List<CourseTaskDto> teacherList = teacher.ToList();
- foreach (CourseTaskDto teacherTaskDto in teacherList)
- {
- List<ScheduleTask> schedules = teacherTaskDto.courseTask.schedules;
- foreach (ScheduleTask schedule in schedules)
- {
- Class classInfo = school_classes.Where((Class x) => x.id == schedule.groupId).FirstOrDefault();
- GetTeacherInfoApiCourseClass classExtobj = new GetTeacherInfoApiCourseClass();
- classExtobj.code = (groupCntDic.ContainsKey(schedule.groupId)) ? groupCntDic[schedule.groupId].code : string.Empty;
- classExtobj.id = schedule.groupId;
- classExtobj.scope = (groupCntDic.ContainsKey(schedule.groupId)) ? groupCntDic[schedule.groupId].scope : string.Empty;
- classExtobj.name = (groupCntDic.ContainsKey(schedule.groupId)) ? groupCntDic[schedule.groupId].name : string.Empty;
- string classType = (groupCntDic.ContainsKey(schedule.groupId)) ? groupCntDic[schedule.groupId].type : schedule.type; /// class:編制班 teach:選課班
- classExtobj.stuListId = (classType.Equals("teach")) ? schedule.groupId : string.Empty; ///選課班 stuListId才填值
- classExtobj.teacher = new GetTeacherInfoApiSimlpeBase();
- if (classInfo != null && !string.IsNullOrWhiteSpace(classInfo.teacher.id)) classExtobj.teacher.id = classInfo.teacher.id;
- if (classInfo != null && !string.IsNullOrWhiteSpace(classInfo.teacher.name)) classExtobj.teacher.name = classInfo.teacher.name;
- classExtobj.stuCnt = (groupCntDic.ContainsKey(schedule.groupId)) ? groupCntDic[schedule.groupId].memberCount : 0;
- classExtobj.gradeId = null;
- classExtobj.gradeName = null;
- classExtobj.year = (groupCntDic.ContainsKey(schedule.groupId)) ? groupCntDic[schedule.groupId].year : teacherTaskDto.courseTask.year;
- var grpCnt = schedules.GroupBy(c => c.groupId).Select(x => new { Count = x.Count() });
- classExtobj.grpCnt = grpCnt.FirstOrDefault().Count;
- var gradeInfo = getGradeInfoByYear(classExtobj.year, period);
- if (!string.IsNullOrWhiteSpace(gradeInfo.id))
- {
- classExtobj.gradeId = gradeInfo.id;
- if (gradeInfo.name.Equals("graduated")) classExtobj.gradeName = (lang.Equals("zh-cn")) ? "已毕业" : (lang.Equals("zh-tw")) ? "已畢業" : "Graduated";
- else if (gradeInfo.name.Equals("not-enrollment")) classExtobj.gradeName = (lang.Equals("zh-cn")) ? "未到入学时间" : (lang.Equals("zh-tw")) ? "未到入學時間" : "It is not time for enrollment yet";
- else classExtobj.gradeName = gradeInfo.name;
- }
- classes.Add(classExtobj);
- }
- }
- }
- //協同教師
- var assistant = schoolAssistantTask.Where(x => x.Key.Equals(item.id)).Select(z => new CourseTaskDto { courseTask = z.Value, type = "assistant" });
- if (assistant.Any() && period != null)
- {
- List<CourseTaskDto> assistantList = assistant.ToList();
- foreach (CourseTaskDto assistantTaskDto in assistantList)
- {
- List<ScheduleTask> schedules = assistantTaskDto.courseTask.schedules;
- foreach (ScheduleTask schedule in schedules)
- {
- Class classInfo = school_classes.Where((Class x) => x.id == schedule.groupId).FirstOrDefault();
- GetTeacherInfoApiCourseClass classExtobj = new GetTeacherInfoApiCourseClass();
- classExtobj.code = (groupCntDic.ContainsKey(schedule.groupId)) ? groupCntDic[schedule.groupId].code : string.Empty;
- classExtobj.id = schedule.groupId;
- classExtobj.scope = (groupCntDic.ContainsKey(schedule.groupId)) ? groupCntDic[schedule.groupId].scope : string.Empty;
- classExtobj.name = (groupCntDic.ContainsKey(schedule.groupId)) ? groupCntDic[schedule.groupId].name : string.Empty;
- string classType = (groupCntDic.ContainsKey(schedule.groupId)) ? groupCntDic[schedule.groupId].type : schedule.type; /// class:編制班 teach:選課班
- classExtobj.stuListId = (classType.Equals("teach")) ? schedule.groupId : string.Empty; ///選課班 stuListId才填值
- classExtobj.teacher = new GetTeacherInfoApiSimlpeBase();
- if (classInfo != null && !string.IsNullOrWhiteSpace(classInfo.teacher.id)) classExtobj.teacher.id = classInfo.teacher.id;
- if (classInfo != null && !string.IsNullOrWhiteSpace(classInfo.teacher.name)) classExtobj.teacher.name = classInfo.teacher.name;
- classExtobj.stuCnt = (groupCntDic.ContainsKey(schedule.groupId)) ? groupCntDic[schedule.groupId].memberCount : 0;
- classExtobj.gradeId = null;
- classExtobj.gradeName = null;
- classExtobj.year = (groupCntDic.ContainsKey(schedule.groupId)) ? groupCntDic[schedule.groupId].year : assistantTaskDto.courseTask.year;
- var grpCnt = schedules.GroupBy(c => c.groupId).Select(x => new { Count = x.Count() });
- classExtobj.grpCnt = grpCnt.FirstOrDefault().Count;
- var gradeInfo = getGradeInfoByYear(classExtobj.year, period);
- if (!string.IsNullOrWhiteSpace(gradeInfo.id))
- {
- classExtobj.gradeId = gradeInfo.id;
- if (gradeInfo.name.Equals("graduated")) classExtobj.gradeName = (lang.Equals("zh-cn")) ? "已毕业" : (lang.Equals("zh-tw")) ? "已畢業" : "Graduated";
- else if (gradeInfo.name.Equals("not-enrollment")) classExtobj.gradeName = (lang.Equals("zh-cn")) ? "未到入学时间" : (lang.Equals("zh-tw")) ? "未到入學時間" : "It is not time for enrollment yet";
- else classExtobj.gradeName = gradeInfo.name;
- }
- classes.Add(classExtobj);
- }
- }
- }
- courseExtobj.classes = classes;
- courses.Add(courseExtobj);
- }
- }
- }
- #region ====舊課程架構===
- //如果没传,则以当前时间获取学年和学期信息
- //[取得當前學年方法 備用] (Semester currSemester, int studyYear, DateTimeOffset date, DateTimeOffset nextSemester) info = SchoolService.GetSemester(period);
- //var gradeInfo = getGradeInfoByYear(classInfo.year, curPeriod);
- //var query = $"SELECT DISTINCT c.id, c.name, c.scope, c.subject, c.period.id AS periodId, schedule.classId AS scheduleClassId, schedule.stulist AS scheduleStulist, schedule.notice AS scheduleNotice FROM c JOIN schedule IN c.schedule WHERE schedule.teacherId = '{id}'";
- //if(periodIds.Count > 0)
- //{
- // string periodIdsJsonStr = JsonSerializer.Serialize(periodIds);
- // query += $" AND ARRAY_CONTAINS({periodIdsJsonStr}, c.period.id, true)";
- //}
- ////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}'";
- //await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIteratorSql(queryText: query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Course-{school_code}") }))
- //{
- // var jsoncs = await JsonDocument.ParseAsync(item.Content);
- // if (jsoncs.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
- // {
- // foreach (var obj in jsoncs.RootElement.GetProperty("Documents").EnumerateArray())
- // {
- // dynamic classExtobj = new ExpandoObject();
- // classExtobj.id = null;
- // classExtobj.code = null;
- // classExtobj.name = null;
- // classExtobj.scope = null;
- // classExtobj.gradeId = null;
- // classExtobj.gradeName = null;
- // classExtobj.year = 0;
- // classExtobj.teacher = null;
- // classExtobj.stuListId = null;
- // classExtobj.stuCnt = 0;
- // classExtobj.grpCnt = 0;
- // //編制班
- // string classIdNow = string.Empty;
- // if (obj.TryGetProperty("scheduleClassId", out JsonElement scheduleClassId))
- // {
- // classIdNow = Convert.ToString(scheduleClassId);
- // }
- // if (!string.IsNullOrWhiteSpace(classIdNow))
- // {
- // Class classInfo = school_classes.Where((Class x) => x.id == classIdNow).FirstOrDefault();
- // if(classInfo != null && !string.IsNullOrWhiteSpace(classInfo.id))
- // {
- // classIds.Add(classInfo.id);
- // classExtobj.id = classInfo.id;
- // classExtobj.code = classInfo.code;
- // classExtobj.name = classInfo.name;
- // classExtobj.year = classInfo.year;
- // classExtobj.teacher = classInfo.teacher;
- // //取得學生數
- // var queryclstc = $"SELECT Count(1) AS stuCnt FROM c WHERE c.classId = '{classIdNow}'";
- // await foreach (var itemclstc in client.GetContainer(Constant.TEAMModelOS, "Student").GetItemQueryStreamIteratorSql(queryText: queryclstc, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base-{school_code}") }))
- // {
- // var jsonclstc = await JsonDocument.ParseAsync(itemclstc.Content);
- // foreach (var objstc in jsonclstc.RootElement.GetProperty("Documents").EnumerateArray())
- // {
- // classExtobj.stuCnt = objstc.GetProperty("stuCnt").GetInt32();
- // }
- // }
- // //取得分組數
- // var queryclgp = $"SELECT c.groupId FROM c WHERE c.classId = '{classIdNow}' AND IS_NULL(c.groupId)=false GROUP BY c.groupId";
- // await foreach (var itemgp in client.GetContainer(Constant.TEAMModelOS, "Student").GetItemQueryStreamIteratorSql(queryText: queryclgp, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base-{school_code}") }))
- // {
- // var jsongp = await JsonDocument.ParseAsync(itemgp.Content);
- // if (jsongp.RootElement.TryGetProperty("_count", out JsonElement gpcount) && gpcount.GetInt32() > 0)
- // {
- // classExtobj.grpCnt = gpcount.GetInt32();
- // }
- // }
- // //取得年級
- // if (obj.TryGetProperty("periodId", out JsonElement curPeriodIdJson))
- // {
- // string curPeriodId = curPeriodIdJson.GetString();
- // Period curPeriod = school_base.period.Where((Period x) => x.id == curPeriodId).FirstOrDefault();
- // if(curPeriodId != null)
- // {
- // var gradeInfo = getGradeInfoByYear(classInfo.year, curPeriod);
- // if(!string.IsNullOrWhiteSpace(gradeInfo.id))
- // {
- // classExtobj.gradeId = gradeInfo.id;
- // if(gradeInfo.name.Equals("graduated")) classExtobj.gradeName = (lang.Equals("zh-cn")) ? "已毕业" : (lang.Equals("zh-tw")) ? "已畢業" : "Graduated";
- // else if(gradeInfo.name.Equals("not-enrollment")) classExtobj.gradeName = (lang.Equals("zh-cn")) ? "未到入学时间" : (lang.Equals("zh-tw")) ? "未到入學時間" : "It is not time for enrollment yet";
- // else classExtobj.gradeName = gradeInfo.name;
- // }
- // }
- // }
- // }
- // }
- // //選課班 (過期者不選)
- // long nowtime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
- // var stuListId = obj.GetProperty("scheduleStulist");
- // if (!stuListId.ValueKind.Equals(JsonValueKind.Null) && !string.IsNullOrWhiteSpace(stuListId.GetString()))
- // {
- // classExtobj.stuListId = Convert.ToString(stuListId);
- // await foreach (var stuitem in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIteratorSql(queryText: $"SELECT c.code, c.id, c.name, c.year, c.tcount, c.scount FROM c WHERE c.id = '{stuListId}' AND ( c.expire = 0 OR IS_DEFINED(c.expire) = false OR c.expire >={nowtime} )", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"GroupList-{school_code}") }))
- // {
- // var jsonstu = await JsonDocument.ParseAsync(stuitem.Content);
- // foreach (var stuobj in jsonstu.RootElement.GetProperty("Documents").EnumerateArray())
- // {
- // groupIds.Add(Convert.ToString(stuobj.GetProperty("id")));
- // classExtobj.id = Convert.ToString(stuobj.GetProperty("id"));
- // classExtobj.code = Convert.ToString(stuobj.GetProperty("code"));
- // classExtobj.name = Convert.ToString(stuobj.GetProperty("name"));
- // classExtobj.gradeId = null;
- // classExtobj.year = (stuobj.TryGetProperty("year", out JsonElement yearJson)) ? yearJson.GetInt32() : 0;
- // classExtobj.teacher = null;
- // classExtobj.stuCnt += stuobj.GetProperty("tcount").GetInt32();
- // classExtobj.stuCnt += stuobj.GetProperty("scount").GetInt32();
- // }
- // }
- // }
- // //課程
- // string courseIdNow = obj.GetProperty("id").ToString();
- // var courseExist = courses.Where((dynamic x) => x.id == courseIdNow).FirstOrDefault();
- // if (courseExist == null)
- // {
- // dynamic courseExtobj = new ExpandoObject();
- // courseExtobj.id = courseIdNow;
- // courseExtobj.name = obj.GetProperty("name").ToString();
- // courseExtobj.scope = obj.GetProperty("scope").ToString();
- // courseExtobj.classes = new List<object>();
- // courseExtobj.subject = obj.GetProperty("subject");
- // //classExtobj.teacher = scheduleTeacherInfo;
- // if (!string.IsNullOrWhiteSpace(classExtobj.id))
- // {
- // courseExtobj.classes.Add(classExtobj);
- // }
- // courses.Add(courseExtobj);
- // }
- // else
- // {
- // //classExtobj.teacher = scheduleTeacherInfo;
- // if (!string.IsNullOrWhiteSpace(classExtobj.id))
- // {
- // courseExist.classes.Add(classExtobj);
- // }
- // }
- // }
- // }
- //}
- #endregion
- //取得校園評測 (HiTeach只取source='1'(課中评量) && progress = 'going'(進行中)) && 排定的學校課程班級
- List<object> exams = new List<object>();
- string classSqlString = "";
- if (classIds.Count > 0 || groupIds.Count > 0)
- {
- if (classIds.Count > 0)
- {
- foreach (string classId in classIds)
- {
- if (!string.IsNullOrWhiteSpace(classSqlString))
- {
- classSqlString += " OR ";
- }
- classSqlString += $"ARRAY_CONTAINS(c.classes, '{classId}')";
- }
- }
- if (groupIds.Count > 0)
- {
- foreach (string groupId in groupIds)
- {
- if (!string.IsNullOrWhiteSpace(classSqlString))
- {
- classSqlString += " OR ";
- }
- classSqlString += $"ARRAY_CONTAINS(c.classes, '{groupId}')";
- }
- }
- }
- else //無分配任何課程教室,校園評測不取
- {
- classSqlString += "c.id = '0'";
- }
- classSqlString = $"AND ({classSqlString})";
- //取得評測ID List
- List<string> examIdList = new List<string>();
- await foreach (var exam in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryStreamIteratorSql(queryText: $"SELECT c.id FROM c WHERE c.source = '1' AND c.progress = 'going' {classSqlString}", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Exam-{school_code}") }))
- {
- using var json = await JsonDocument.ParseAsync(exam.Content);
- if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
- {
- foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
- {
- examIdList.Add(obj.GetProperty("id").GetString());
- }
- }
- }
- //取得有作答的評測班級、已完成的 評測ID、班級ID、科目ID 列表製作
- List<ExamFinishClassesSubList> examFinClassSubList = new List<ExamFinishClassesSubList>(); //已完成的 評測ID、班級ID、科目ID 列表
- await foreach (var exam in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryStreamIteratorSql(queryText: $"SELECT c.examId, c.info.id as classId, c.subjectId FROM c WHERE ARRAY_CONTAINS({JsonSerializer.Serialize(examIdList)}, c.examId) AND c.progress=true", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"ExamClassResult-{school_code}") }))
- {
- var jsonecr = await JsonDocument.ParseAsync(exam.Content);
- if (jsonecr.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
- {
- foreach (var obj in jsonecr.RootElement.GetProperty("Documents").EnumerateArray())
- {
- string examId = obj.GetProperty("examId").ToString();
- string classId = obj.GetProperty("classId").ToString();
- string subjectId = obj.GetProperty("subjectId").ToString();
- ExamFinishClassesSubList existExamFinishClassesSubRow = examFinClassSubList.Where(e => e.examId == examId && e.classId == classId && e.subjectId == subjectId).FirstOrDefault();
- if (existExamFinishClassesSubRow == null)
- {
- ExamFinishClassesSubList ExamFinishClassesSubRow = new ExamFinishClassesSubList();
- ExamFinishClassesSubRow.examId = examId;
- ExamFinishClassesSubRow.classId = classId;
- ExamFinishClassesSubRow.subjectId = subjectId;
- examFinClassSubList.Add(ExamFinishClassesSubRow);
- }
- }
- }
- }
- //取得評測資料
- await foreach (var exam in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryStreamIteratorSql(queryText: $"SELECT c.code, c.id, c.name, c.createTime, c.startTime, c.endTime ,c.year, c.source, c.type, c.progress, c.stuCount, c.scope, c.owner, c.period, c.grades, c.subjects, c.classes, c.stuLists, ARRAY(SELECT p.id, p.code, p.name, p.blob, p.scope FROM p IN c.papers) AS papers FROM c WHERE ARRAY_CONTAINS({JsonSerializer.Serialize(examIdList)}, c.id)", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Exam-{school_code}") }))
- {
- var jsonex = await JsonDocument.ParseAsync(exam.Content);
- if (jsonex.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
- {
- foreach (var obj in jsonex.RootElement.GetProperty("Documents").EnumerateArray())
- {
- dynamic examExtobj = new ExpandoObject();
- string examId = obj.GetProperty("id").GetString();
- examExtobj.code = obj.GetProperty("code");
- examExtobj.id = examId;
- examExtobj.name = obj.GetProperty("name");
- examExtobj.createTime = obj.GetProperty("createTime");
- examExtobj.startTime = obj.GetProperty("startTime");
- examExtobj.endTime = obj.GetProperty("endTime");
- examExtobj.year = obj.GetProperty("year");
- examExtobj.source = obj.GetProperty("source");
- examExtobj.type = obj.GetProperty("type");
- examExtobj.progress = obj.GetProperty("progress");
- examExtobj.stuCount = obj.GetProperty("stuCount");
- examExtobj.scope = obj.GetProperty("scope");
- examExtobj.owner = obj.GetProperty("owner");
- examExtobj.period = obj.GetProperty("period");
- examExtobj.grades = obj.GetProperty("grades");
- examExtobj.subjects = (obj.TryGetProperty("subjects", out JsonElement subjectsJobj)) ? subjectsJobj.ToObject<List<GetSchInfoExamSubject>>() : new List<GetSchInfoExamSubject>();
- examExtobj.classes = (obj.TryGetProperty("classes", out JsonElement classes)) ? classes.ToObject<List<string>>() : new List<string>();
- examExtobj.stuLists = (obj.TryGetProperty("stuLists", out JsonElement stuLists)) ? stuLists.ToObject<List<string>>() : new List<string>();
- examExtobj.papers = obj.GetProperty("papers");
- //examExtobj = obj.ToObject<object>();
- //須完成列表、已完成班級列表生成
- examExtobj.finishClasses = new List<string>();
- examExtobj.finishClassesSub = new List<GetSchInfoExamFinishClassesSub>();
- List<GetSchInfoExamFinishClassesSub> examClassSubjectList = new List<GetSchInfoExamFinishClassesSub>();
- foreach (string classIdNow in examExtobj.classes)
- {
- GetSchInfoExamFinishClassesSub examClassSubjectRow = examClassSubjectList.Where(x => x.classId == classIdNow).FirstOrDefault();
- if (examClassSubjectRow == null)
- {
- examClassSubjectRow = new GetSchInfoExamFinishClassesSub();
- examClassSubjectRow.classId = classIdNow;
- examClassSubjectRow.subjectIds = new List<string>();
- examClassSubjectRow.finishSubjectIds = new List<string>();
- }
- foreach (GetSchInfoExamSubject subjectNow in examExtobj.subjects)
- {
- string subjectIdNow = subjectNow.id;
- if (!examClassSubjectRow.subjectIds.Contains(subjectIdNow))
- {
- examClassSubjectRow.subjectIds.Add(subjectIdNow);
- }
- ExamFinishClassesSubList existFinClassesSub = examFinClassSubList.Where(e => e.examId == examId && e.classId == classIdNow && e.subjectId == subjectIdNow).FirstOrDefault();
- if (existFinClassesSub != null)
- {
- examClassSubjectRow.finishSubjectIds.Add(subjectIdNow);
- }
- }
- examExtobj.finishClassesSub.Add(examClassSubjectRow);
- if (examClassSubjectRow.subjectIds.Count.Equals(examClassSubjectRow.finishSubjectIds.Count))
- {
- if (!examExtobj.finishClasses.Contains(classIdNow))
- {
- examExtobj.finishClasses.Add(classIdNow);
- }
- }
- }
- exams.Add(examExtobj);
- }
- }
- }
- //用户在线记录
- //try
- //{
- // _ = _httpTrigger.RequestHttpTrigger(new { school = school_code.GetString(), scope = $"{Constant.ScopeTeacher}", id = $"{id}", ip = $"{ip}", expire = 1 }, _option.Location, "online-record");
- //}
- //catch { }
- //取得School Blob 容器位置及SAS
- string school_code_blob = school_code.GetString().ToLower();
- var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(school_code_blob, BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Write); //讀列
- var (blob_uri_read, blob_sas_read) = _azureStorage.GetBlobContainerSAS(school_code_blob, BlobContainerSasPermissions.Read); //讀
- var (blob_uri_write, blob_sas_write) = _azureStorage.GetBlobContainerSAS(school_code_blob, BlobContainerSasPermissions.Write); //寫
- await SystemService.RecordAccumulateData(_azureRedis, _dingDing, new SDK.Models.Dtos.Accumulate { client = "hiteach", count = 1, id = school_base.id, key = "teacher_login", name = "醍摩豆账号登录", scope = "school", target = school_base.id });
- return Ok(new { blob_uri, blob_sas, blob_sas_read, blob_sas_write, periods, grades, subjects, courses, examTypes, exams });
- }
- catch (Exception ex)
- {
- await _dingDing.SendBotMsg($"IES5,{_option.Location},hiteach/GetSchoolInfo()\n{ex.Message}\n{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
- return BadRequest();
- }
- }
- //取得試卷
- [Authorize(Roles = "HiTeach")]
- [ProducesDefaultResponseType]
- [HttpPost("get-paper")]
- public async Task<IActionResult> GetPaperList(JsonElement request)
- {
- try
- {
- //Header驗證
- string id_token = HttpContext.GetXAuth("IdToken");
- if (string.IsNullOrEmpty(id_token)) return BadRequest();
- var jwt = new JwtSecurityToken(id_token);
- if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.Ordinal)) return BadRequest();
- var id = jwt.Payload.Sub;
- var client = _azureCosmos.GetCosmosClient();
- //參數
- if (!request.TryGetProperty("grant_type", out JsonElement grant_type)) return BadRequest();
- string partitionid = string.Empty;
- string container = string.Empty;
- if (grant_type.ToString().Equals("school"))
- {
- if (!request.TryGetProperty("school_code", out JsonElement school_code_json))
- {
- return BadRequest();
- }
- else
- {
- partitionid = school_code_json.ToString();
- container = "School";
- }
- }
- else
- {
- partitionid = id.ToString();
- container = "Teacher";
- }
- //SQL文
- List<object> papers = new List<object>();
- string queryWhere = $" WHERE (( IS_DEFINED(c.secret) = false OR c.secret=0 ) OR ( c.secret=1 AND c.creatorId='{id.ToString()}') )";
- string queryOption = string.Empty;
- //學段
- if (request.TryGetProperty("periodId", out JsonElement periodId) && container.Equals("School"))
- {
- queryWhere += $" AND c.periodId = '{periodId}'";
- }
- //年級
- if (request.TryGetProperty("gradeId", out JsonElement gradeIds) && gradeIds.GetArrayLength() > 0 && container.Equals("School"))
- {
- string queryOptionForGrade = string.Empty;
- for (int i = 0; i < gradeIds.GetArrayLength(); i++)
- {
- if (!string.IsNullOrWhiteSpace(queryOptionForGrade))
- {
- queryOptionForGrade += " OR ";
- }
- queryOptionForGrade += $" ARRAY_CONTAINS(c.gradeIds, '{gradeIds[i]}', true)";
- }
- queryWhere += $" AND ( {queryOptionForGrade} )";
- }
- //科目ID
- if (request.TryGetProperty("subjectId", out JsonElement subjectId) && container.Equals("School"))
- {
- queryWhere += $" AND c.subjectId = '{subjectId}'";
- }
- //科目名稱
- if (request.TryGetProperty("subjectName", out JsonElement subjectName))
- {
- queryWhere += $" AND c.subjectName = '{subjectName}'";
- }
- //試卷ID
- if (request.TryGetProperty("id", out JsonElement paperId))
- {
- queryWhere += $" AND c.id = '{paperId}'";
- }
- int perpage = 0; //每頁幾條
- if (request.TryGetProperty("perpage", out JsonElement perpage_json)) perpage = perpage_json.GetInt32();
- int page = 0; //目前第幾頁
- if (request.TryGetProperty("page", out JsonElement page_json))
- {
- if (page_json.GetInt32() > 0)
- {
- page = page_json.GetInt32() - 1;
- }
- }
- string order = "createTime"; //排序項目
- if (request.TryGetProperty("order", out JsonElement order_json))
- {
- if (order_json.ToString().Equals("useCount"))
- {
- order = order_json.ToString();
- }
- }
- queryOption += $" Order By c." + order + " DESC ";
- if (perpage > 0)
- {
- queryOption += $" OFFSET {perpage * page} LIMIT {perpage}";
- }
- //資料取得
- await foreach (var item in client.GetContainer(Constant.TEAMModelOS, container).GetItemQueryStreamIteratorSql(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, c.scope From c {queryWhere + queryOption}", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Paper-{partitionid}") }))
- {
- using var json = await JsonDocument.ParseAsync(item.Content);
- if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
- {
- foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
- {
- papers.Add(obj.ToObject<object>());
- }
- }
- }
- //總件數
- int totalCount = 0;
- await foreach (var item in client.GetContainer(Constant.TEAMModelOS, container).GetItemQueryStreamIteratorSql(queryText: $"SELECT VALUE COUNT(1) From c {queryWhere}", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Paper-{partitionid}") }))
- {
- using var json = await JsonDocument.ParseAsync(item.Content);
- if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
- {
- foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
- {
- totalCount = obj.GetInt32();
- }
- }
- }
- return Ok(new { papers, totalCount });
- }
- catch (Exception ex)
- {
- return BadRequest();
- }
- }
- //取得試題
- [Authorize(Roles = "HiTeach")]
- [ProducesDefaultResponseType]
- [HttpPost("get-item")]
- public async Task<IActionResult> GetItemList(JsonElement request)
- {
- try
- {
- //Header驗證
- string id_token = HttpContext.GetXAuth("IdToken");
- if (string.IsNullOrEmpty(id_token)) return BadRequest();
- var jwt = new JwtSecurityToken(id_token);
- if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.Ordinal)) return BadRequest();
- var id = jwt.Payload.Sub;
- var client = _azureCosmos.GetCosmosClient();
- //參數
- if (!request.TryGetProperty("grant_type", out JsonElement grant_type)) return BadRequest();
- string partitionid = string.Empty;
- string container = string.Empty;
- if (grant_type.ToString().Equals("school"))
- {
- if (!request.TryGetProperty("school_code", out JsonElement school_code_json))
- {
- return BadRequest();
- }
- else
- {
- partitionid = school_code_json.ToString();
- container = "School";
- }
- }
- else
- {
- partitionid = id.ToString();
- container = "Teacher";
- }
- //SQL文
- List<object> items = new List<object>();
- string queryWhere = " WHERE 1=1 ";
- string queryOption = string.Empty;
- //學段
- if (request.TryGetProperty("periodId", out JsonElement periodId) && container.Equals("School"))
- {
- queryWhere += $" AND c.periodId = '{periodId}'";
- }
- //年級
- if (request.TryGetProperty("gradeId", out JsonElement gradeIds) && gradeIds.GetArrayLength() > 0 && container.Equals("School"))
- {
- string queryOptionForGrade = string.Empty;
- for (int i = 0; i < gradeIds.GetArrayLength(); i++)
- {
- if (!string.IsNullOrWhiteSpace(queryOptionForGrade))
- {
- queryOptionForGrade += " OR ";
- }
- queryOptionForGrade += $" ARRAY_CONTAINS(c.gradeIds, '{gradeIds[i]}', true)";
- }
- queryWhere += $" AND ( {queryOptionForGrade} )";
- }
- //科目ID
- if (request.TryGetProperty("subjectId", out JsonElement subjectId) && container.Equals("school"))
- {
- queryWhere += $" AND c.subjectId = '{subjectId}'";
- }
- //科目名稱
- if (request.TryGetProperty("subjectName", out JsonElement subjectName))
- {
- queryWhere += $" AND c.subjectName = '{subjectName}'";
- }
- //題型
- int dummy = 0;
- if (request.TryGetProperty("type", out JsonElement type))
- {
- queryWhere += $" AND c.type = '{type}'";
- }
- //難度
- dummy = 0;
- if (request.TryGetProperty("level", out JsonElement level) && int.TryParse(level.ToString(), out dummy))
- {
- queryWhere += $" AND c.level = {level}";
- }
- //層次
- if (request.TryGetProperty("field", out JsonElement field) && int.TryParse(field.ToString(), out dummy))
- {
- queryWhere += $" AND c.field = {field}";
- }
- int perpage = 0; //每頁幾條
- if (request.TryGetProperty("perpage", out JsonElement perpage_json)) perpage = perpage_json.GetInt32();
- int page = 0; //目前第幾頁
- if (request.TryGetProperty("page", out JsonElement page_json))
- {
- if (page_json.GetInt32() > 0)
- {
- page = page_json.GetInt32() - 1;
- }
- }
- string order = "createTime"; //排序項目
- if (request.TryGetProperty("order", out JsonElement order_json))
- {
- if (order_json.ToString().Equals("useCount"))
- {
- order = order_json.ToString();
- }
- }
- queryOption += $" Order By c." + order + " DESC ";
- if (perpage > 0)
- {
- queryOption += $" OFFSET {perpage * page} LIMIT {perpage}";
- }
- //資料取得
- await foreach (var item in client.GetContainer(Constant.TEAMModelOS, container).GetItemQueryStreamIteratorSql(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}") }))
- {
- using var json = await JsonDocument.ParseAsync(item.Content);
- if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
- {
- foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
- {
- items.Add(obj.ToObject<object>());
- }
- }
- }
- //總件數
- int totalCount = 0;
- await foreach (var item in client.GetContainer(Constant.TEAMModelOS, container).GetItemQueryStreamIteratorSql(queryText: $"SELECT VALUE COUNT(1) From c {queryWhere}", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{partitionid}") }))
- {
- using var json = await JsonDocument.ParseAsync(item.Content);
- if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
- {
- foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
- {
- totalCount = obj.GetInt32();
- }
- }
- }
- return Ok(new { items, totalCount });
- }
- catch (Exception ex)
- {
- return BadRequest();
- }
- }
- //取得知識點
- [Authorize(Roles = "HiTeach")]
- [ProducesDefaultResponseType]
- [HttpPost("get-knowledge")]
- public async Task<IActionResult> GetKnowledgePointList(JsonElement request)
- {
- var client = _azureCosmos.GetCosmosClient();
- if (!request.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
- //知識點
- List<object> points = new List<object>();
- await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIteratorSql(queryText: $"SELECT c.id, c.name, c.subjectId FROM c WHERE c.type = 'point'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Knowledge-{school_code}") }))
- {
- using var json = await JsonDocument.ParseAsync(item.Content);
- if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
- {
- foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
- {
- points.Add(obj.ToObject<object>());
- }
- }
- }
- return Ok(points);
- }
- //取得課綱
- [Authorize(Roles = "HiTeach")]
- [ProducesDefaultResponseType]
- [HttpPost("get-syllabus")]
- public async Task<IActionResult> GetSyllabusList(JsonElement request)
- {
- //Header驗證
- string id_token = HttpContext.GetXAuth("IdToken");
- if (string.IsNullOrEmpty(id_token)) return BadRequest();
- var jwt = new JwtSecurityToken(id_token);
- if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.OrdinalIgnoreCase)) return BadRequest();
- var id = jwt.Payload.Sub;
- //參數驗證
- if (!request.TryGetProperty("grant_type", out JsonElement grant_type)) return BadRequest();
- string grantType = (grant_type.GetString().Equals("school")) ? "school" : "private";
- JsonElement school_code = new();
- if (grantType == "school" && !request.TryGetProperty("school_code", out school_code)) return BadRequest();
- string dataId = (grantType.Equals("school")) ? school_code.GetString() : id;
- string container = (grantType.Equals("school")) ? "School" : "Teacher";
- string periodId = (request.TryGetProperty("periodId", out JsonElement periodIdJobj)) ? periodIdJobj.GetString() : String.Empty;
- string subjectId = (request.TryGetProperty("subjectId", out JsonElement subjectIdJobj)) ? subjectIdJobj.GetString() : String.Empty;
- string volumeId = (request.TryGetProperty("volumeId", out JsonElement volumeIdJobj)) ? volumeIdJobj.GetString() : String.Empty;
- string syllabusId = (request.TryGetProperty("syllabusId", out JsonElement syllabusIdJobj)) ? syllabusIdJobj.GetString() : String.Empty;
- int display = (request.TryGetProperty("display", out JsonElement displayJobj)) ? displayJobj.GetInt32() : 0;
- var client = _azureCosmos.GetCosmosClient();
- //取得卷前置作業:有給syllabusId,取得該課綱的卷ID
- string volumeIdFromSyllabusId = String.Empty;
- if (!string.IsNullOrWhiteSpace(syllabusId))
- {
- await foreach (string volid in client.GetContainer(Constant.TEAMModelOS, container).GetItemQueryIteratorSql<string>(queryText: $"SELECT value(c.volumeId) FROM c WHERE c.id = '{syllabusId}'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Syllabus-{dataId}") }))
- {
- volumeIdFromSyllabusId = volid;
- }
- }
- //取得卷
- List<object> volumes = new();
- List<Volume> volumeList = new();
- List<string> volumeIdList = new();
- string queryTextVol = string.Empty;
- List<string> WhereVol = new();
- if (!string.IsNullOrWhiteSpace(periodId)) WhereVol.Add($" c.periodId = '{periodId}' ");
- if (!string.IsNullOrWhiteSpace(subjectId)) WhereVol.Add($" c.subjectId = '{subjectId}' ");
- if (!string.IsNullOrWhiteSpace(volumeId)) WhereVol.Add($" c.id = '{volumeId}' ");
- if (!string.IsNullOrWhiteSpace(volumeIdFromSyllabusId)) WhereVol.Add($" c.id = '{volumeIdFromSyllabusId}' ");
- foreach (string Where in WhereVol)
- {
- queryTextVol += (String.IsNullOrWhiteSpace(queryTextVol)) ? $" WHERE {Where} " : $" AND {Where} ";
- }
- queryTextVol = "SELECT * FROM c " + queryTextVol;
- await foreach (var itemv in client.GetContainer(Constant.TEAMModelOS, container).GetItemQueryStreamIteratorSql(queryText: queryTextVol, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Volume-{dataId}") }))
- {
- var jsons = await JsonDocument.ParseAsync(itemv.Content);
- if (jsons.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
- {
- foreach (var obj in jsons.RootElement.GetProperty("Documents").EnumerateArray())
- {
- Volume volExtobj = obj.ToObject<Volume>();
- volumeList.Add(volExtobj);
- volumeIdList.Add(volExtobj.id);
- }
- }
- }
- //取得課綱 ※display=1時不取任何課綱
- List<SyllabusTreeNode> treeNodes = new();
- if (!display.Equals(1))
- {
- string queryTextSyl = $"SELECT value(c) FROM c WHERE ARRAY_CONTAINS({JsonSerializer.Serialize(volumeIdList)}, c.volumeId, true)";
- if (!string.IsNullOrWhiteSpace(syllabusId)) queryTextSyl += $" AND c.id = '{syllabusId}'";
- await foreach (Syllabus items in client.GetContainer(Constant.TEAMModelOS, container).GetItemQueryIteratorSql<Syllabus>(queryText: queryTextSyl, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Syllabus-{dataId}") }))
- {
- List<SyllabusTree> trees = SyllabusService.ListToTree(items.children);
- SyllabusTreeNode tree = new() { id = items.id, scope = items.scope, trees = trees, volumeId = items.volumeId, auth = items.auth, codeval = $"{id}" };
- treeNodes.Add(tree);
- }
- }
- //輸出結果
- foreach (Volume vr in volumeList)
- {
- //对课纲树形结构排序
- List<SyllabusTreeNode> redt = new List<SyllabusTreeNode>();
- if (vr.syllabusIds.IsNotEmpty())
- {
- vr.syllabusIds.ForEach(x =>
- {
- for (int index = 0; index < treeNodes.Count; index++)
- {
- if (treeNodes[index].id == x && treeNodes[index].volumeId == vr.id)
- {
- redt.Add(treeNodes[index]);
- treeNodes.RemoveAt(index);
- }
- }
- });
- }
- //輸出項
- volumes.Add(new
- {
- vr.periodId,
- vr.subjectId,
- vr.id,
- vr.gradeId,
- vr.semesterId,
- vr.name,
- vr.creatorId,
- vr.creatorName,
- vr.school,
- vr.scope,
- vr.syllabusIds,
- vr.auth,
- vr.order,
- syllabus = redt.Where(t => t.volumeId == vr.id).ToList()
- });
- }
- return Ok(volumes);
- }
- //取得被分享的課綱
- [ProducesDefaultResponseType]
- [Authorize(Roles = "HiTeach")]
- [HttpPost("get-share-syllabus")]
- public async Task<IActionResult> GetShareSyllabusList(JsonElement request)
- {
- //Header驗證
- string id_token = HttpContext.GetXAuth("IdToken");
- if (string.IsNullOrEmpty(id_token)) return BadRequest();
- var jwt = new JwtSecurityToken(id_token);
- if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.OrdinalIgnoreCase)) return BadRequest();
- var id = jwt.Payload.Sub;
- //參數驗證
- string volumeId = (request.TryGetProperty("volumeId", out JsonElement volumeIdJobj)) ? volumeIdJobj.GetString() : String.Empty;
- string syllabusId = (request.TryGetProperty("syllabusId", out JsonElement syllabusIdJobj)) ? syllabusIdJobj.GetString() : String.Empty;
- int display = (request.TryGetProperty("display", out JsonElement displayJobj)) ? displayJobj.GetInt32() : 0;
- var client = _azureCosmos.GetCosmosClient();
- //取得分享內容
- Dictionary<string, string> tmidDic = new Dictionary<string, string>();
- List<Volume> volumeList = new List<Volume>();
- StringBuilder queryText = new StringBuilder("SELECT value(c) FROM c WHERE c.type='share' ");
- if (!string.IsNullOrWhiteSpace(volumeId))
- {
- queryText.Append($"AND c.volumeId='{volumeId}'");
- }
- await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIteratorSql<Share>(queryText: queryText.ToString(),
- requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Share-share-{id}") }))
- {
- if (!string.IsNullOrWhiteSpace(syllabusId))
- {
- if (item.id.Equals(syllabusId))
- {
- Volume volumeExist = volumeList.Where((Volume v) => v.id == item.volumeId).FirstOrDefault();
- if (volumeExist == null)
- {
- Volume volume = new Volume();
- volume.id = item.volumeId;
- volume.name = item.volumeName;
- volume.creatorId = item.issuer;
- volume.creatorName = item.issuerName;
- volume.syllabusIds.Add(item.id);
- volumeList.Add(volume);
- var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(item.issuer, BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List);
- if (!tmidDic.ContainsKey(item.issuer)) tmidDic.Add(item.issuer, blob_sas);
- }
- else
- {
- volumeExist.syllabusIds.Add(item.id);
- }
- }
- }
- else
- {
- Volume volumeExist = volumeList.Where((Volume v) => v.id == item.volumeId).FirstOrDefault();
- if (volumeExist == null)
- {
- Volume volume = new Volume();
- volume.id = item.volumeId;
- volume.name = item.volumeName;
- volume.creatorId = item.issuer;
- volume.creatorName = item.issuerName;
- volume.syllabusIds.Add(item.id);
- volumeList.Add(volume);
- var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(item.issuer, BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List);
- if (!tmidDic.ContainsKey(item.issuer)) tmidDic.Add(item.issuer, blob_sas);
- }
- else
- {
- volumeExist.syllabusIds.Add(item.id);
- }
- }
- }
- //取得課綱並輸出回傳值
- List<object> result = new List<object>();
- foreach (Volume volTmp in volumeList)
- {
- List<SyllabusTreeNode> treeNodes = new();
- if (!display.Equals(1))
- {
- string queryTextSyl = $"SELECT value(c) FROM c WHERE ARRAY_CONTAINS({JsonSerializer.Serialize(volTmp.syllabusIds)}, c.id, true)";
- await foreach (Syllabus items in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIteratorSql<Syllabus>(queryText: queryTextSyl, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Syllabus-{volTmp.creatorId}") }))
- {
- List<SyllabusTree> trees = SyllabusService.ListToTree(items.children);
- SyllabusTreeNode tree = new() { id = items.id, scope = items.scope, trees = trees, volumeId = items.volumeId, auth = items.auth, codeval = $"{volTmp.creatorId}" };
- treeNodes.Add(tree);
- }
- }
- result.Add(new
- {
- id = volTmp.id,
- name = volTmp.name,
- creatorId = volTmp.creatorId,
- creatorName = volTmp.creatorName,
- creatorSas = (tmidDic.ContainsKey(volTmp.creatorId)) ? tmidDic[volTmp.creatorId] : null,
- syllabusIds = volTmp.syllabusIds,
- syllabus = treeNodes.ToList(),
- });
- }
- return Ok(result);
- }
- //取得某班級的學生成員
- [Authorize(Roles = "HiTeach")]
- [ProducesDefaultResponseType]
- [HttpPost("get-students-list")]
- public async Task<IActionResult> GetStudentsList(JsonElement request)
- {
- string id_token = HttpContext.GetXAuth("IdToken");
- if (string.IsNullOrWhiteSpace(id_token)) return BadRequest();
- var jwt = new JwtSecurityToken(id_token);
- if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.Ordinal)) return BadRequest();
- var id = jwt.Payload.Sub;
- if (!request.TryGetProperty("grant_type", out JsonElement grant_type)) return BadRequest();
- request.TryGetProperty("class_code", out JsonElement class_code);
- request.TryGetProperty("stulist_id", out JsonElement stulist_id);
- string classId = Convert.ToString(class_code);
- string stulist = Convert.ToString(stulist_id);
- if (string.IsNullOrWhiteSpace(classId) && string.IsNullOrWhiteSpace(stulist)) return BadRequest();
- request.TryGetProperty("school_code", out JsonElement school_code);
- if (grant_type.GetString().Equals("school") && string.IsNullOrWhiteSpace(Convert.ToString(school_code))) return BadRequest();
- var client = _azureCosmos.GetCosmosClient();
- Dictionary<string, string> irsDic = new Dictionary<string, string>(); //key:學生ID或TMID value:irs號碼
- string container = (grant_type.GetString().Equals("school")) ? "School" : "Teacher";
- List<string> listids = new List<string>();
- if (!string.IsNullOrWhiteSpace(stulist))
- {
- listids.Add(stulist);
- }
- else if (!string.IsNullOrWhiteSpace(classId))
- {
- listids.Add(classId);
- }
- (List<RMember> students, List<RGroupList> groupList) = await GroupListService.GetMemberByListids(_coreAPIHttpService, client, _dingDing, listids, $"{school_code}");
- return Ok(new { students });
- }
- /// <summary>
- /// 開始課堂(舊版,已被CreateLesson取代)
- /// </summary>
- /// <param name="request"></param>
- /// <returns></returns>
- [Authorize(Roles = "HiTeach")]
- [ProducesDefaultResponseType]
- [HttpPost("start-lesson")]
- public async Task<IActionResult> StartLesson(JsonElement request)
- {
- //醍摩豆ID驗證
- string teacherId = string.Empty;
- string id_token = HttpContext.GetXAuth("IdToken");
- if (!string.IsNullOrWhiteSpace(id_token))
- {
- var jwt = new JwtSecurityToken(id_token);
- if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.OrdinalIgnoreCase)) return BadRequest();
- teacherId = jwt.Payload.Sub;
- }
- if (string.IsNullOrWhiteSpace(teacherId)) return BadRequest(); //無醍摩豆ID,BadRequest
- //取得授課ID
- string lesson_code = _snowflakeId.NextId().ToString();
- //bool get_lesson_id = (string.IsNullOrWhiteSpace(Convert.ToString(lesson_id)) || Convert.ToString(lesson_id) != lesson_code) ? false : true;
- //string tableName = "TeacherLesson";
- return Ok(new { lesson_code });
- }
- //上傳評測結果
- //錯誤代碼:error = 1001 message = "Paper blob copy failure."
- // error = 1002 message = "Student answers blob upload failure."
- [Authorize(Roles = "HiTeach")]
- [ProducesDefaultResponseType]
- [HttpPost("upd-exam-result")]
- public async Task<IActionResult> UploadExamResult(JsonElement request)
- {
- try
- {
- string message = "";
- int error = 0;
- string id_token = HttpContext.GetXAuth("IdToken");
- if (string.IsNullOrWhiteSpace(id_token)) return BadRequest();
- var jwt = new JwtSecurityToken(id_token);
- if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.Ordinal)) return BadRequest();
- var id = jwt.Payload.Sub;
- if (!request.TryGetProperty("exam", out JsonElement exam)) return BadRequest();
- if (!request.TryGetProperty("examClassResult", out JsonElement examClassResult)) return BadRequest();
- bool blobUploaded = (request.TryGetProperty("blobUploaded", out JsonElement blobUploadedJson)) ? blobUploadedJson.GetBoolean() : false;
- bool recordSwitch = (request.TryGetProperty("recordSwitch", out JsonElement recordSwitchJson)) ? recordSwitchJson.GetBoolean() : false;
- bool cloudas = (request.TryGetProperty("cloudas", out JsonElement cloudasJson)) ? cloudasJson.GetBoolean() : false; //是否啟動cloudas運算
- List<string> blobCopyPath = (request.TryGetProperty("blobCopyPath", out JsonElement blobCopyPathJson)) ? JsonSerializer.Deserialize <List<string>>(blobCopyPathJson.ToJsonString()) : new List<string>();
- //ExamInfo ExamInfoFromReq = exam.ToObject<ExamInfo>();
- string strExam = JsonSerializer.Serialize(exam);
- if (strExam.Contains("\"publish\":\"0\""))
- {
- strExam = strExam.Replace("\"publish\":\"0\"", "\"publish\":0");
- }
- ExamInfo ExamInfoFromReq = JsonSerializer.Deserialize<ExamInfo>(strExam);
- string examId = ExamInfoFromReq.id;
- string excode = ExamInfoFromReq.code;
- string examSubjectId = ExamInfoFromReq.subjects[0].id;
- //ExamInfo dbExamInfo = exam.ToObject<ExamInfo>();
- ExamInfo dbExamInfo = JsonSerializer.Deserialize<ExamInfo>(strExam);
- var queryex = $"SELECT * FROM c WHERE c.id = '{examId}'";
- await foreach (var itemex in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryStreamIteratorSql(queryText: queryex, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{excode}") }))
- {
- var jsonex = await JsonDocument.ParseAsync(itemex.Content);
- if (jsonex.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
- {
- foreach (var obj in jsonex.RootElement.GetProperty("Documents").EnumerateArray())
- {
- string strExamDb = JsonSerializer.Serialize(obj);
- if (strExamDb.Contains("\"publish\":\"0\""))
- {
- strExamDb = strExamDb.Replace("\"publish\":\"0\"", "\"publish\":0");
- }
- dbExamInfo = JsonSerializer.Deserialize<ExamInfo>(strExamDb);
- //dbExamInfo = obj.ToObject<ExamInfo>();
- }
- }
- }
- if (string.IsNullOrWhiteSpace(dbExamInfo.id))
- {
- dbExamInfo = ExamInfoFromReq;
- }
- if (cloudas) dbExamInfo.cloudas = cloudas;
- //Boolean isTestFlg = (_option.Location.Contains("Test") || _option.Location.Contains("Dep")) ? true : false;
- //ExamInfo內容取得、調整 [2021-7-13 廢除,給予HiTeach學校Blob寫入權限,API不再對Blob做搬運]
- //※規則 owner:"school" => 校園評測 "teacher" => 個人評測
- //※規則 scope:"school" => 校本班級 "private" => 個人班級
- //※規則 BLOB容器: scope:"school" => {學校ID}下 scope:"private" => {個人ID}下
- string blobContainer = (!string.IsNullOrWhiteSpace(dbExamInfo.school) && dbExamInfo.scope.Equals("school")) ? dbExamInfo.school : id; //blob容器
- //dbExamInfo.source = "1"; //評測來源固定為 1:課中評量(不應由API擅自變更)
- //試卷List
- List<Dictionary<string, string>> recordPaperInfo = new List<Dictionary<string, string>>();
- int paperIndex = 0;
- foreach (PaperSimple paperInfo in ExamInfoFromReq.papers)
- {
- string paperBlobPath = (!paperInfo.blob.EndsWith("/")) ? paperInfo.blob + "/" : paperInfo.blob;
- paperBlobPath = (paperInfo.blob.StartsWith("/")) ? paperBlobPath.Remove(0, 1) : paperBlobPath;
- //string subjectId = dbExamInfo.subjects[paperIndex].id;
- string subjectId = examSubjectId;
- recordPaperInfo.Add(new Dictionary<string, string>() { { "id", paperInfo.id }, { "blob", paperBlobPath }, { "subjectId", subjectId }, { "itemcount", paperInfo.point.Count.ToString() } });
- paperIndex++;
- }
- //取得課堂紀錄下的試卷資料(blob)、複製到評測紀錄下
- bool paperDataCopyErrFlg = false; //試卷資料拷貝錯誤Flag true:拷貝錯誤 [2021-7-13 (測試站)不再對Blob做搬運 永為false]
- //Blob搬運 (待HiTeach完善後刪除)
- if (!blobUploaded)
- {
- foreach (Dictionary<string, string> recordPaperInfoDic in recordPaperInfo)
- {
- string targetScope = dbExamInfo.scope; //評測對象 school:校本班級 private:私人課程
- var blobPrivateContainer = _azureStorage.GetBlobContainerClient(id);
- string sourceBlobPath = recordPaperInfoDic["blob"];
- string destBlobPath = $"exam/{dbExamInfo.id}/paper/{recordPaperInfoDic["subjectId"]}/"; //拷貝對象路徑 path:exam/{評測ID}/paper/{subjectID}/ ※2022-1-6 式樣變更[原]/paper/{試卷ID}/ [新]/paper/{subjectID}/
- if (targetScope.Equals("school")) //校本
- {
- string schoolId = dbExamInfo.school;
- var blobSchoolContainer = _azureStorage.GetBlobContainerClient(schoolId);
- var sourceBlobContainer = (recordSwitch) ? blobSchoolContainer : blobPrivateContainer;
- Azure.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 blobSchoolContainer.GetBlobClient(destBlobFilePath).StartCopyFromUriAsync(sourceFileUri);
- }
- else
- {
- paperDataCopyErrFlg = true;
- }
- }
- }
- }
- else //私人
- {
- var sourceBlobContainer = blobPrivateContainer;
- Azure.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;
- }
- }
- }
- }
- //替換 Exam.papers.blob
- PaperSimple paperInfoNow = dbExamInfo.papers.Where((PaperSimple p) => p.id == recordPaperInfoDic["id"]).FirstOrDefault();
- string destBlobPathForDocument = (destBlobPath.EndsWith("/")) ? destBlobPath.Remove(destBlobPath.Length - 1, 1) : destBlobPath;
- destBlobPathForDocument = (!destBlobPathForDocument.StartsWith("/")) ? "/" + destBlobPathForDocument : destBlobPathForDocument;
- paperInfoNow.blob = destBlobPathForDocument;
- }
- }
- //ExamClassResult內容調整
- bool studentAnswerCopyErrFlg = false; //學生作答資料拷貝錯誤Flag true:拷貝錯誤 [2021-7-13 不再對Blob做搬運 永為false]
- //Blob搬運 (待HiTeach完善後刪除)
- if (!blobUploaded)
- {
- List<ExamClassResultStudentAnswerArrayOld> dbExamClassResultList = examClassResult.ToObject<List<ExamClassResultStudentAnswerArrayOld>>();
- foreach (ExamClassResultStudentAnswerArrayOld examClassResultRow in dbExamClassResultList)
- {
- //以subjectId及classId(info.id)取得DB中的ExamClassResult
- ExamClassResult examClassResultUpd = new ExamClassResult();
- string exclcode = examClassResultRow.code;
- string classId = examClassResultRow.info.id;
- string subjectId = examClassResultRow.subjectId;
- var querycr = $"SELECT * FROM c WHERE c.examId = '{examId}' AND c.info.id = '{classId}' AND c.subjectId = '{subjectId}'";
- await foreach (var itemcr in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryStreamIteratorSql(queryText: querycr, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{exclcode}") }))
- {
- var jsontcr = await JsonDocument.ParseAsync(itemcr.Content);
- if (jsontcr.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
- {
- foreach (var obj in jsontcr.RootElement.GetProperty("Documents").EnumerateArray())
- {
- examClassResultUpd = obj.ToObject<ExamClassResult>();
- examClassResultUpd.progress = examClassResultRow.progress;
- examClassResultUpd.studentIds = examClassResultRow.studentIds;
- examClassResultUpd.studentAnswers = new List<List<string>>();
- examClassResultUpd.studentScores = examClassResultRow.studentScores;
- examClassResultUpd.status = examClassResultRow.status;
- examClassResultUpd.sum = examClassResultRow.sum;
- }
- }
- }
- //無法取得既有ExamClassResult,新建
- if (string.IsNullOrWhiteSpace(examClassResultUpd.id))
- {
- examClassResultUpd.pk = examClassResultRow.pk;
- examClassResultUpd.code = examClassResultRow.code;
- examClassResultUpd.id = examClassResultRow.id;
- examClassResultUpd.school = examClassResultRow.school;
- examClassResultUpd.examId = examClassResultRow.examId;
- examClassResultUpd.subjectId = examClassResultRow.subjectId;
- examClassResultUpd.gradeId = examClassResultRow.gradeId;
- examClassResultUpd.year = examClassResultRow.year;
- examClassResultUpd.info = examClassResultRow.info;
- examClassResultUpd.progress = examClassResultRow.progress;
- examClassResultUpd.studentIds = examClassResultRow.studentIds;
- examClassResultUpd.studentAnswers = new List<List<string>>(); //學生作答Blob位置
- examClassResultUpd.studentScores = examClassResultRow.studentScores;
- examClassResultUpd.status = examClassResultRow.status;
- examClassResultUpd.scope = examClassResultRow.scope;
- examClassResultUpd.sum = examClassResultRow.sum;
- }
- //examClassResult.studentAnswers (1)將學生答案上傳blob後轉換內容為blob路徑 //[2021-7-13 不再對Blob做搬運] (2)將學生答案放入examClassResult.ans
- if (examClassResultRow.studentIds != null && examClassResultRow.studentIds.Count > 0 && examClassResultRow.studentAnswersArray != null && examClassResultRow.studentAnswersArray.Count > 0)
- {
- for (int i = 0; i < examClassResultRow.studentAnswersArray.Count; i++)
- {
- string studentId = examClassResultRow.studentIds[i];
- string fileName = examId + "/" + subjectId + "/" + studentId;
- string blob = fileName + "/" + "ans.json";
- var uploadFileResult = await _azureStorage.GetBlobContainerClient(blobContainer).UploadFileByContainer(examClassResultRow.studentAnswersArray[i].ToJsonString(), "exam", blob, false);
- if (string.IsNullOrWhiteSpace(uploadFileResult))
- {
- studentAnswerCopyErrFlg = true;
- }
- //studentAnswers
- List<string> studenrAnswerRow = new List<string>();
- studenrAnswerRow.Add(blob);
- examClassResultUpd.studentAnswers.Add(studenrAnswerRow);
- }
- //examClassResult.ans 將學生答案放入
- examClassResultUpd.ans = examClassResultRow.studentAnswersArray;
- }
- //批註欄位處理
- Dictionary<string, string> paperStatusNow = recordPaperInfo.Where((Dictionary<string, string> p) => p.TryGetValue("subjectId", out string paperStatusSubjectId) && paperStatusSubjectId.Equals(subjectId)).FirstOrDefault();
- int itemCount = Convert.ToInt32(paperStatusNow["itemcount"]);
- if (examClassResultUpd.mark.Count != examClassResultUpd.studentIds.Count || (examClassResultUpd.mark.ElementAtOrDefault(0) != null && examClassResultUpd.mark[0].Count != itemCount)) //第一層:學生數不符 OR 第二層:第一位學生批註數!=試卷題數 => 批註格式不符
- {
- examClassResultUpd.mark = this.createEmptyMark(examClassResultUpd.studentIds.Count, itemCount);
- }
- //UPDATE ExamClassResult
- var examClassResultResponse = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Common").UpsertItemAsync(examClassResultUpd, new PartitionKey(examClassResultUpd.code));
- }
- }
- else
- {
- List<ExamClassResultStudentAnswerArray> dbExamClassResultList = examClassResult.ToObject<List<ExamClassResultStudentAnswerArray>>();
- foreach (ExamClassResultStudentAnswerArray examClassResultRow in dbExamClassResultList)
- {
- //以subjectId及classId(info.id)取得DB中的ExamClassResult
- ExamClassResult examClassResultUpd = new ExamClassResult();
- string exclcode = examClassResultRow.code;
- string classId = examClassResultRow.info.id;
- string subjectId = examClassResultRow.subjectId;
- var querycr = $"SELECT * FROM c WHERE c.examId = '{examId}' AND c.info.id = '{classId}' AND c.subjectId = '{subjectId}'";
- await foreach (var itemcr in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryStreamIteratorSql(queryText: querycr, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{exclcode}") }))
- {
- var jsontcr = await JsonDocument.ParseAsync(itemcr.Content);
- if (jsontcr.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
- {
- foreach (var obj in jsontcr.RootElement.GetProperty("Documents").EnumerateArray())
- {
- examClassResultUpd = obj.ToObject<ExamClassResult>();
- examClassResultUpd.progress = examClassResultRow.progress;
- examClassResultUpd.studentIds = examClassResultRow.studentIds;
- examClassResultUpd.studentAnswers = new List<List<string>>();
- examClassResultUpd.studentScores = examClassResultRow.studentScores;
- examClassResultUpd.status = examClassResultRow.status;
- examClassResultUpd.sum = examClassResultRow.sum;
- }
- }
- }
- //無法取得既有ExamClassResult,新建
- if (string.IsNullOrWhiteSpace(examClassResultUpd.id))
- {
- examClassResultUpd.pk = examClassResultRow.pk;
- examClassResultUpd.code = examClassResultRow.code;
- examClassResultUpd.id = examClassResultRow.id;
- examClassResultUpd.school = examClassResultRow.school;
- examClassResultUpd.examId = examClassResultRow.examId;
- examClassResultUpd.subjectId = examClassResultRow.subjectId;
- examClassResultUpd.gradeId = examClassResultRow.gradeId;
- examClassResultUpd.year = examClassResultRow.year;
- examClassResultUpd.info = examClassResultRow.info;
- examClassResultUpd.progress = examClassResultRow.progress;
- examClassResultUpd.studentIds = examClassResultRow.studentIds;
- examClassResultUpd.studentAnswers = new List<List<string>>();
- examClassResultUpd.studentScores = examClassResultRow.studentScores;
- examClassResultUpd.status = examClassResultRow.status;
- examClassResultUpd.scope = examClassResultRow.scope;
- examClassResultUpd.sum = examClassResultRow.sum;
- }
- //學生作答Blob位置[2021-7-13 不再對Blob做搬運 學生答案直接寫入DB]
- examClassResultUpd.studentAnswers = examClassResultRow.studentAnswersArray;
- //學生作答答案 (從blob取得學生答案、放入ans欄位)
- string targetScope = dbExamInfo.scope; //評測對象 school:校本班級 private:私人課程
- var targetBlobContainer = _azureStorage.GetBlobContainerClient(id);
- string blobCntr = id;
- if (targetScope.Equals("school")) //校本
- {
- string schoolId = dbExamInfo.school;
- blobCntr = schoolId;
- }
- targetBlobContainer = _azureStorage.GetBlobContainerClient(blobCntr);
- if (examClassResultRow.studentAnswersArray.Count > 0)
- {
- foreach (List<string> studentAnswerBlobPath in examClassResultRow.studentAnswersArray)
- {
- string stuAnswerBlobPath = studentAnswerBlobPath.FirstOrDefault();
- if (stuAnswerBlobPath != null)
- {
- StringBuilder builder = new StringBuilder();
- builder.Append("exam").Append("/").Append(stuAnswerBlobPath);
- var Download = await targetBlobContainer.GetBlobClient(builder.ToString()).DownloadAsync();
- var json = await JsonDocument.ParseAsync(Download.Value.Content);
- var Record = json.RootElement.ToObject<List<List<string>>>();
- examClassResultUpd.ans.Add(Record);
- }
- }
- }
- //批註欄位處理
- Dictionary<string, string> paperStatusNow = recordPaperInfo.Where((Dictionary<string, string> p) => p.TryGetValue("subjectId", out string subjectId) && subjectId.Equals(examClassResultUpd.subjectId)).FirstOrDefault();
- int itemCount = Convert.ToInt32(paperStatusNow["itemcount"]);
- if (examClassResultUpd.mark.Count != examClassResultUpd.studentIds.Count || (examClassResultUpd.mark.ElementAtOrDefault(0) != null && examClassResultUpd.mark[0].Count != itemCount)) //第一層:學生數不符 OR 第二層:第一位學生批註數!=試卷題數 => 批註格式不符
- {
- examClassResultUpd.mark = this.createEmptyMark(examClassResultUpd.studentIds.Count, itemCount);
- }
- //UPDATE ExamClassResult
- var examClassResultResponse = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Common").UpsertItemAsync(examClassResultUpd, new PartitionKey(examClassResultUpd.code));
- }
- }
- //搬移Blob (blobCopyPath)
- bool blobDataCopyErrFlg = false;
- if (!blobUploaded && blobCopyPath.Count > 0)
- {
- var sourceBlobContainer = _azureStorage.GetBlobContainerClient(blobContainer);
- var destBlobContainer = (dbExamInfo.scope.Equals("school")) ? _azureStorage.GetBlobContainerClient(dbExamInfo.school) : _azureStorage.GetBlobContainerClient(id);
- foreach (string fromBlobPath in blobCopyPath)
- {
- Azure.Pageable<BlobItem> sourceBlobs = sourceBlobContainer.GetBlobs(prefix: fromBlobPath);
- 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(fromBlobPath, "");
- string destBlobPath = $"exam/{dbExamInfo.id}/{examSubjectId}/"; //拷貝對象路徑 path:exam/{評測ID}/paper/{subjectID}/ ※2022-1-6 式樣變更[原]/paper/{試卷ID}/ [新]/paper/{subjectID}/
- if (fileName.StartsWith("/")) fileName = fileName.Remove(0, 1);
- string destBlobFilePath = $"{destBlobPath}{fileName}";
- await destBlobContainer.GetBlobClient(destBlobFilePath).StartCopyFromUriAsync(sourceFileUri);
- }
- else
- {
- blobDataCopyErrFlg = true;
- }
- }
- }
- }
-
- }
- //UPDATE Exam
- await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Common").UpsertItemAsync(dbExamInfo, new PartitionKey(dbExamInfo.code));
- //錯誤處理
- if (paperDataCopyErrFlg) //試卷Blob拷貝失敗
- {
- error = 1001;
- message = "Paper blob copy failure.";
- }
- else if (studentAnswerCopyErrFlg) //學生作答資料上傳blob失敗
- {
- error = 1002;
- message = "Student answers blob upload failure.";
- }
- else if (blobDataCopyErrFlg) //blob拷貝失敗
- {
- error = 1003;
- message = "Blob copy failure.";
- }
- return Ok(new { error, message });
- }
- catch (CosmosException cex)
- {
- return BadRequest(cex.Message);
- }
- //catch (StorageException bex)
- //{
- // return BadRequest(bex.Message);
- //}
- catch (Exception ex)
- {
- return BadRequest(ex.Message);
- }
- }
- /**
- * 根据学年获取年级信息
- * @param year 学年
- * @param Period 学段資料
- */
- private ExamSimple getGradeInfoByYear(int year, Period curPeriod)
- {
- ExamSimple result = new ExamSimple();
- if (year > 0)
- {
- DateTime date = DateTime.UtcNow;
- int curYear = date.Year;
- int month = date.Month;
- Semester semesterStart = curPeriod.semesters.Where((Semester x) => x.start.Equals(1)).FirstOrDefault();
- if (semesterStart != null)
- {
- if (month < semesterStart.month)
- {
- curYear--;
- }
- int gradeIndex = curYear - year;
- result.id = gradeIndex.ToString();
- result.name = (gradeIndex >= curPeriod.grades.Count) ? "graduated" : (gradeIndex >= 0) ? curPeriod.grades[gradeIndex] : "not-enrollment";
- }
- }
- return result;
- }
- private List<List<List<Details>>> createEmptyMark(int studentNum, int itemNum)
- {
- List<List<List<Details>>> mark = new List<List<List<Details>>>();
- for (int i = 0; i < studentNum; i++)
- {
- List<List<Details>> markRow = new List<List<Details>>();
- for (int j = 0; j < itemNum; j++)
- {
- markRow.Add(new List<Details>());
- }
- mark.Add(markRow);
- }
- return mark;
- }
- public class ClassStudents
- {
- public string id { get; set; }
- public string name { get; set; }
- public string no { get; set; }
- public string schoolId { get; set; }
- public string groupId { get; set; }
- public string groupName { get; set; }
- public string irs { get; set; }
- public int type { get; set; } //类型 1 tmdid,2 student
- public string nickname { get; set; }
- }
- public class ClassGroups
- {
- public ClassGroups()
- {
- studentIds = new List<string>();
- }
- public string id { get; set; }
- public string name { get; set; }
- public List<string> studentIds { get; set; }
- }
- //ExamClassResult 學生作答紀錄(舊式 正式站暫時用這個)
- public class ExamClassResultStudentAnswerArrayOld : ExamClassResult
- {
- public List<List<List<string>>> studentAnswersArray { get; set; }
- }
- //ExamClassResult 學生作答紀錄
- public class ExamClassResultStudentAnswerArray : ExamClassResult
- {
- public List<List<string>> studentAnswersArray { get; set; }
- }
- //get-teacher-info API輸出 schools
- private class GetTeacherInfoApiSchool
- {
- public string schoolId { get; set; }
- public string name { get; set; }
- public string status { get; set; }
- public string picture { get; set; }
- }
- //get-teacher-info輸出 courses
- private class GetTeacherInfoApiCourse : GetTeacherInfoApiSimlpeBase
- {
- public string scope { get; set; }
- public List<GetTeacherInfoApiCourseClass> classes { get; set; }
- }
- //get-teacher-info輸出 courses.classes
- private class GetTeacherInfoApiCourseClass : GetTeacherInfoApiSimlpeBase
- {
- public string code { get; set; }
- public GetTeacherInfoApiSimlpeBase teacher { get; set; }
- public string scope { get; set; }
- public string stuListId { get; set; }
- public int stuCnt { get; set; }
- public int grpCnt { get; set; }
- public string gradeId { get; set; }
- public string gradeName { get; set; }
- public int year { get; set; }
- }
- //get-teacher-info輸出 基本class(各class繼承用)
- internal class GetTeacherInfoApiSimlpeBase
- {
- public string id { get; set; }
- public string name { get; set; }
- }
- //get-school-info輸出 exams.finishClassesSub(各班級已完成評測的科目列表)
- private class GetSchInfoExamFinishClassesSub
- {
- public string classId { get; set; } //班級ID
- public List<string> subjectIds { get; set; } //需完成科目ID
- public List<string> finishSubjectIds { get; set; } //已完成科目ID
- }
- //get-school-info輸出 courses
- private class GetSchoolInfoApiCourse : GetTeacherInfoApiSimlpeBase
- {
- public string scope { get; set; }
- public GetTeacherInfoApiSimlpeBase subject { get; set; }
- public List<GetTeacherInfoApiCourseClass> classes { get; set; }
- }
- //get-school-info (中間資料)記錄學生已完成的評測、班級、科目
- private class ExamFinishClassesSubList
- {
- public string examId { get; set; } //評測ID
- public string classId { get; set; } //班級ID
- public string subjectId { get; set; } //科目ID
- }
- //get-school-info輸出 exams.subjects
- private class GetSchInfoExamSubject
- {
- public string id { get; set; }
- public string name { get; set; }
- public int classCount { get; set; }
- }
- private class GroupListMemberCnt
- {
- public string id { get; set; }
- public string code { get; set; }
- public string name { get; set; }
- public string scope { get; set; }
- public string type { get; set; } /// class:編制班 teach:選課班
- public int year { get; set; }
- public int memberCount { get; set; }
- }
- #region ===學習記錄用類別===
- #region ===TimeLine.json===
- private class TimeLineEvents
- {
- public TimeLineEvents()
- {
- events = new List<TimeLineEventPg>();
- }
- public List<TimeLineEventPg> events { get; set; }
- }
- private class TimeLineEventPg
- {
- public double Time { get; set; }
- public string Pgid { get; set; }
- public string Event { get; set; }
- }
- #endregion
- #region ===IRS.json===
- /// <summary>
- /// IRS架構第一層
- /// </summary>
- private class IRSItem
- {
- public IRSItem()
- {
- buzzClients = new List<string>();
- }
- public string pageID { get; set; }
- public IRSQuestion question { get; set; }
- public JsonElement clientAnswers { get; set; }
- public List<string> buzzClients { get; set; }
- public bool isBuzz { get; set; }
- }
- /// <summary>
- /// IRS架構第二層
- /// </summary>
- private class IRSQuestion
- {
- public IRSQuestion()
- {
- item = new List<QuestionItem>();
- }
- public QuestionExercise exercise { get; set; }
- public List<QuestionItem> item { get; set; }
- }
- private class QuestionItem
- {
- public QuestionItem()
- {
- option = new List<OptionItem>();
- }
- public string question { get; set; }
- public List<OptionItem> option { get; set; }
- }
- private class OptionItem
- {
- public string code { get; set; }
- public string value { get; set; }
- }
- /// <summary>
- /// IRS架構第三層
- /// </summary>
- private class QuestionExercise
- {
- public string type { get; set; }
- public List<string> knowledges { get; set; }
- public List<string> answer { get; set; }
- }
- #endregion
- #region ===Task.json===
- private class TaskItem
- {
- public List<ClientWork> clientWorks { get; set; }
- public string pageID { get; set; }
- }
- private class ClientWork
- {
- public int seatID { get; set; }
- public string reciveTime { get; set; }
- }
- #endregion
- private class LessonRecordItemPart
- {
- public string id { get; set; }
- public string tmdid { get; set; }
- public string school { get; set; }
- public string scope { get; set; }
- }
- #region ===取學校代碼===
- private class GroupIdsFromLesson
- {
- public List<string> groupIds { get; set; }
- }
- private class SchoolFromgroupIds
- {
- public string school { get; set; }
- }
- #endregion
- #endregion
- #region ===評量 - 學習記錄用類別===
- private class PaperIndex
- {
- public PaperIndex()
- {
- slides = new List<Slide>();
- }
- public List<Slide> slides { get; set; }
- }
- private class Slide
- {
- /// <summary>
- /// blob 路徑
- /// </summary>
- public string url { get; set; }
- /// <summary>
- /// 題型
- /// </summary>
- public string type { get; set; }
- /// <summary>
- /// scoring
- /// </summary>
- public Scoring scoring { get; set; }
- }
- private class Exercise
- {
- /// <summary>
- /// 题目类型
- /// </summary>
- public string type { get; set; }
- /// <summary>
- /// 难度
- /// </summary>
- public int level { get; set; }
- /// <summary>
- /// 知识点
- /// </summary>
- public List<string> knowledges { get; set; }
- }
- private class Scoring
- {
- /// <summary>
- /// knowledge
- /// </summary>
- public List<string> knowledge { get; set; }
- /// <summary>
- /// 答案
- /// </summary>
- public List<string> ans { get; set; }
- }
- private class StudentAnswers
- {
- /// <summary>
- /// 學生作答 blob 路徑
- /// </summary>
- public List<List<string>> studentAnswers { get; set; }
- /// <summary>
- /// 學生ID
- /// </summary>
- public List<string> studentIds { get; set; } = new();
- }
- private class QuestionData
- {
- public QuestionData()
- {
- item = new List<QuestionItem>();
- }
- public QuestionExercise exercise { get; set; }
- public List<QuestionItem> item { get; set; }
- }
- #endregion
-
- }
- }
|