123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Dynamic;
- using System.IdentityModel.Tokens.Jwt;
- using System.IO;
- using System.Linq;
- using System.Net;
- using System.Text;
- using System.Text.Json;
- using System.Threading.Tasks;
- using Azure;
- using Azure.Cosmos;
- using Azure.Messaging.ServiceBus;
- using Azure.Storage.Sas;
- using HTEXLib.COMM.Helpers;
- using Microsoft.AspNetCore.Authorization;
- using Microsoft.AspNetCore.Cryptography.KeyDerivation;
- using Microsoft.AspNetCore.Mvc;
- using Microsoft.Extensions.Configuration;
- using Microsoft.Extensions.Options;
- using Microsoft.Identity.Client;
- using TEAMModelOS.Filter;
- using TEAMModelOS.Models;
- using TEAMModelOS.SDK;
- using TEAMModelOS.SDK.DI;
- using TEAMModelOS.SDK.Extension;
- using TEAMModelOS.SDK.Models;
- using TEAMModelOS.SDK.Models.Cosmos;
- using TEAMModelOS.SDK.Models.Cosmos.Common;
- using TEAMModelOS.SDK.Models.Service;
- using static TEAMModelOS.SDK.StudentService;
- namespace TEAMModelOS.Controllers
- {
- [Route("student")]
- [ApiController]
- public class StudentController : Controller
- {
- private readonly AzureCosmosFactory _azureCosmos;
- private readonly AzureStorageFactory _azureStorage;
- private readonly AzureRedisFactory _azureRedis;
- private readonly DingDing _dingDing;
- private readonly Option _option;
- private readonly IPSearcher _searcher;
- private readonly HttpTrigger _httpTrigger;
- public IConfiguration _configuration { get; set; }
- private readonly AzureServiceBusFactory _serviceBus;
- public StudentController(AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage, AzureRedisFactory azureRedis, DingDing dingDing, IPSearcher searcher, IOptionsSnapshot<Option> option,IConfiguration configuration, AzureServiceBusFactory serviceBus, HttpTrigger httpTrigger
- )
- {
- _searcher = searcher;
- _azureCosmos = azureCosmos;
- _azureStorage = azureStorage;
- _azureRedis = azureRedis;
- _dingDing = dingDing;
- _option = option?.Value;
- _configuration = configuration;
- _serviceBus = serviceBus;
- _httpTrigger = httpTrigger;
- }
- /// <summary>
- /// 學生帳號管理
- /// </summary>
- /// <param name="request"></param>
- /// <returns></returns>
- [HttpPost("student-manage")]
- [Authorize(Roles = "IES")]
- [AuthToken(Roles = "admin,student,teacher")]
- public async Task<IActionResult> StudentManage(JsonElement request)
- {
- try
- {
- //TODO : 權限檢查、學校檢查。
- if (!request.TryGetProperty("grant_type", out JsonElement grant_type) || !request.TryGetProperty("schoolId", out JsonElement schoolId)) return BadRequest();
- List<Student> preStudents = null;
- List<Student> webStudents = null;
- var (stuid, _, _, school) = HttpContext.GetAuthTokenInfo();
- switch (grant_type.GetString())
- {
- case "create":
- //單人創建 創建學生->將學生加入教室 檢查學生ID是否重複,欲加入的班級存不存在,座號是否重複。
- //id pw name classId no year
- //retrun 如果有重複則回{ existNo } , 成功則{ id, name, year, classId, no }
- var importStuds = request.GetProperty("students").EnumerateArray();
- Dictionary<string, GroupChange> dictChange = new Dictionary<string, GroupChange>();
- while (importStuds.MoveNext())
- {
- JsonElement currStud = importStuds.Current;
- string id = null, name = null, pw = null, no = null, classId = null, periodId = null, imei = null ;
- List<StudentGuardian> guardians = null;
- int year = 0;
- //讀取輸入的資料
- if (!currStud.TryGetProperty("id", out var tmpId) || !currStud.TryGetProperty("name", out var tmpName)) continue;
- id = tmpId.GetString();
- name = tmpName.GetString();
- if (currStud.TryGetProperty("pw", out var tmpPw)) pw = tmpPw.GetString();
- if (currStud.TryGetProperty("year", out var tmpYear)) year = tmpYear.GetInt32();
- if (currStud.TryGetProperty("no", out var tmpNo)) no = tmpNo.GetString();
- if (currStud.TryGetProperty("classId", out var tmpClassId)) classId = tmpClassId.GetString();
- if (currStud.TryGetProperty("imei", out var tmpImei)) imei = $"{tmpImei}";
- if (currStud.TryGetProperty("guardians", out var tmpGuardians)) {
- guardians = tmpGuardians.Deserialize<List<StudentGuardian>>();
- }
- //要檢查座號使否已被使用
- var existNo = await StudentService.checkStudNo(_azureCosmos, _dingDing, _option, schoolId.GetString(), classId, new List<string>() { id });
- if (existNo.Count != 0) return this.Ok(new { code = $"Base-{schoolId.GetString()}", existNo = existNo.Select(o => o.id).ToList() });
- if (currStud.TryGetProperty("periodId", out var tempPeriodId)) periodId = tempPeriodId.GetString();
- //建立學生
- studCreateInfo studCreateInfo = new studCreateInfo(id, name, "M", year, pw, classId, no, periodId,imei,guardians);
- var isCreateSuc = await createStudent(_azureCosmos, _dingDing, _option, schoolId.GetString(), studCreateInfo);
- if (isCreateSuc)
- {
- if (dictChange.ContainsKey(classId))
- {
- dictChange[classId].stujoin.Add(
- new Member
- {
- id = id,
- code = $"{schoolId.GetString()}",
- type = 2,
- });
- }
- else
- {
- GroupChange change = new GroupChange
- {
- scope = "school",
- school = schoolId.GetString(),
- type = "student",
- originCode = schoolId.GetString(),
- listid = classId,
- stujoin = new List<Member>
- {
- new Member
- {
- id= id,
- code=schoolId.GetString(),
- type=2,
- }
- }
- };
- dictChange.Add(classId, change);
- }
- foreach (var changed in dictChange.Keys)
- {
- var change = dictChange[changed];
- if (change.stujoin.Count != 0 || change.stuleave.Count != 0)
- {
- var messageChange = new ServiceBusMessage(change.ToJsonString());
- messageChange.ApplicationProperties.Add("name", "GroupChange");
- var ActiveTask = _configuration.GetValue<string>("Azure:ServiceBus:ActiveTask");
- await _serviceBus.GetServiceBusClient().SendMessageAsync(ActiveTask, messageChange);
- }
- }
- return this.Ok(new { code = $"Base-{schoolId.GetString()}", id, name, year, classId, no, periodId });
- }
- else return this.Ok(new { code = $"Base-{schoolId.GetString()}", errorId = id });
- }
- break;
- case "import":
- //只有ClassNo可以比對
- webStudents = request.GetProperty("students").ToObject<List<Student>>();
- preStudents = await StudentService.GeStudentData(_azureCosmos, schoolId.GetString(), webStudents?.Select(x => x.id));
- var retUpsert = await StudentService.upsertStudents(_azureCosmos, _dingDing, _option, schoolId.GetString(), request.GetProperty("students").EnumerateArray());
- await CheckStudent(_serviceBus, _configuration, _azureCosmos, schoolId.GetString(), webStudents, preStudents);
- return this.Ok(new { code = $"Base-{schoolId.GetString()}", students = retUpsert.studs, retUpsert.classDuplNos, retUpsert.errorIds });
- case "read":
- //讀取該間學校所有的學生資訊
- var students = await StudentService.getAllStudent(_azureCosmos, _dingDing, _option, schoolId.GetString());
- return this.Ok(new { code = $"Base-{schoolId.GetString()}", students });
- case "update":
- //更新學生資料,批量密碼重置,基本資訊更新(姓名、教室ID、性別、學年及座號)
- webStudents = request.GetProperty("students").ToObject<List<Student>>();
- var cleanImei = false;
-
- if (request.GetProperty("cleanImei").ValueKind.Equals(JsonValueKind.True))
- {
- cleanImei = true;
- }
-
- preStudents = await StudentService.GeStudentData(_azureCosmos, schoolId.GetString(), webStudents?.Select(x => x.id));
- var retUpdate = await StudentService.updateStudents(_azureCosmos, _dingDing, _option, schoolId.GetString(), request.GetProperty("students").EnumerateArray(), cleanImei);
- await StudentService.CheckStudent(_serviceBus, _configuration, _azureCosmos, schoolId.GetString(), webStudents, preStudents);
- return this.Ok(new { code = $"Base-{schoolId.GetString()}", students = retUpdate.studs, retUpdate.classDuplNos, retUpdate.nonexistentIds, retUpdate.errorNos, retUpdate.errorClassId });
- case "delete":
- //刪除學生資料及從教室學生名單內移除該學生
- webStudents = request.GetProperty("students").ToObject<List<Student>>();
- preStudents = await StudentService.GeStudentData(_azureCosmos, schoolId.GetString(), webStudents?.Select(x => x.id));
- var sucDelIds = await StudentService.deleteStudents(_azureCosmos, _dingDing, _option, schoolId.GetString(), request.GetProperty("students").EnumerateArray());
- await StudentService.CheckStudent(_serviceBus, _configuration, _azureCosmos, schoolId.GetString(), webStudents, preStudents);
- return this.Ok(new { code = $"Base-{schoolId.GetString()}", ids = sucDelIds });
- case "remove":
- //將學生基本資料內的classId、no、groupId及groupName寫入null
- List<string> stus = request.GetProperty("students").ToObject<List<string>>();
- webStudents = new List<Student>();
- foreach (string idstu in stus)
- {
- webStudents.Add(new Student { id = idstu, code = $"Base-{schoolId}" });
- }
- preStudents = await StudentService.GeStudentData(_azureCosmos, schoolId.GetString(), webStudents?.Select(x => x.id));
- (List<string> studs, List<string> nonexistentIds, List<string> errorIds) retRemove = await StudentService.removeStudentClassInfo(
- _azureCosmos, _dingDing, _option,
- schoolId.GetString(), request.GetProperty("students").EnumerateArray());
- await StudentService.CheckStudent(_serviceBus, _configuration, _azureCosmos, schoolId.GetString(), webStudents, preStudents);
- return Ok(new { code = $"Base-{schoolId.GetString()}", ids = retRemove.studs, retRemove.nonexistentIds, retRemove.errorIds });
- case "avatar":
- if (request.TryGetProperty("avatar", out JsonElement _avatar) && _avatar.ValueKind.Equals(JsonValueKind.Array))
- {
- List<StudentInfo> avatars = _avatar.ToObject<List<StudentInfo>>();
- if (avatars.IsNotEmpty())
- {
- List<Student> studentsp = new List<Student>();
- string insql = string.Join(',', avatars.Select(x => $"'{x.studentId}'"));
- string sql = $"select value(c) from c where c.id in ({insql}) ";
- await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student")
- .GetItemQueryIterator<Student>(sql, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey($"Base-{schoolId}") }))
- {
- studentsp.Add(item);
- }
- (string url, string sas) = _azureStorage.GetBlobContainerSAS99Year($"{schoolId}", BlobContainerSasPermissions.Read);
- foreach (Student student in studentsp)
- {
- StudentInfo avatar = avatars.Find(x => x.studentId.Equals(student.id));
- student.picture = avatar != null ? $"{avatar.picture}?{sas}" : null;
- await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student").ReplaceItemAsync<Student>(student, student.id, new PartitionKey(student.code));
- }
- return Ok(new { students = studentsp.Select(x => new { x.id, x.picture, x.code, x.name }) });
- }
- else
- {
- return BadRequest();
- }
- }
- else
- {
- return BadRequest();
- }
- case "update-self-info":
- if (request.TryGetProperty("studentInfo", out JsonElement _studentInfo))
- {
- var studentInfo = _studentInfo.ToObject<StudentInfo>();
- if (studentInfo.studentId.Equals(stuid) && school.Equals($"{schoolId}"))
- {
- Student student = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student")
- .ReadItemAsync<Student>(studentInfo.studentId, new PartitionKey($"Base-{schoolId}"));
- student.mail = string.IsNullOrEmpty(studentInfo.mail) ? student.mail : studentInfo.mail;
- student.mobile = string.IsNullOrEmpty(studentInfo.mobile) ? student.mobile : studentInfo.mobile;
- student.name = string.IsNullOrEmpty(studentInfo.name) ? student.name : studentInfo.name;
- (string url, string sas) = _azureStorage.GetBlobContainerSAS99Year($"{schoolId}", BlobContainerSasPermissions.Read);
- student.picture = string.IsNullOrEmpty(studentInfo.picture) ? student.picture : $"{studentInfo.picture}?{sas}";
- student.gender = string.IsNullOrEmpty(studentInfo.gender) ? student.gender : studentInfo.gender;
- await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student")
- .ReplaceItemAsync<Student>(student, studentInfo.studentId, new PartitionKey($"Base-{schoolId}"));
- return Ok(new { studentInfo });
- }
- else
- {
- return Ok(new { error = false, status = false, msg = "修改的不是自己的信息" });
- }
- }
- else
- {
- return BadRequest();
- }
- case "update-self-password":
- if (request.TryGetProperty("newpwd", out JsonElement _newpwd) &&
- request.TryGetProperty("oldpwd", out JsonElement _oldpwd) &&
- request.TryGetProperty("studentId", out JsonElement _studentId))
- {
- if ($"{_studentId}".Equals(stuid) && school.Equals($"{schoolId}"))
- {
- try
- {
- Student student = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student")
- .ReadItemAsync<Student>($"{_studentId}", new PartitionKey($"Base-{schoolId}"));
- var HashedPW = Utils.HashedPassword($"{_oldpwd}", student.salt);
- if (HashedPW.Equals(student.pw))
- {
- student.pw = Utils.HashedPassword($"{_newpwd}", student.salt);
- await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student")
- .ReplaceItemAsync<Student>(student, student.id, new PartitionKey($"Base-{schoolId}"));
- return Ok(new { status = true });
- }
- else
- {
- return Ok(new { error = false, status = false, msg = "密码不一致" });
- }
- }
- catch (Exception ex)
- {
- await _dingDing.SendBotMsg($"IES5,{_option.Location},StudentController/StudentManage()\n{ex.Message}\n{ex.StackTrace}\n{request.ToJsonString()}", GroupNames.醍摩豆服務運維群組);
- return Ok(new { error = false, status = false, msg = "账号不存在" });
- }
- }
- else
- {
- return Ok(new { error = false, status = false, msg = "修改的不是自己的密码" });
- }
- }
- else
- {
- return BadRequest();
- }
- case "read-self-info":
- if (request.TryGetProperty("studentId", out JsonElement __studentId))
- {
- try
- {
- Student student = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Student")
- .ReadItemAsync<Student>($"{__studentId}", new PartitionKey($"Base-{schoolId}"));
- return Ok(new { student.mail, student.mobile, student.name, student.picture, student.gender, student.id, student.schoolId, student.year, student.no, student.classId, student.periodId, irs = student.irs });
- }
- catch (Exception ex)
- {
- await _dingDing.SendBotMsg($"IES5,{_option.Location},StudentController/StudentManage()\n{ex.Message}\n{ex.StackTrace}\n{request.ToJsonString()}", GroupNames.醍摩豆服務運維群組);
- }
- return Ok();
- }
- else
- {
- return BadRequest();
- }
- default:
- return BadRequest();
- }
- }
- catch (Exception ex)
- {
- await _dingDing.SendBotMsg($"IES5,{_option.Location},StudentController/StudentManage()\n{ex.Message}\n{ex.StackTrace}\n{request.ToJsonString()}", GroupNames.醍摩豆服務運維群組);
- }
- return BadRequest();
- }
- [HttpPost("get-student-info")]
- [Authorize(Roles = "IES")]
- public async Task<IActionResult> GetStudentInfo(JsonElement request)
- {
- var client = _azureCosmos.GetCosmosClient();
- var schoolClient = client.GetContainer(Constant.TEAMModelOS, "School");
- var teacherClient = client.GetContainer(Constant.TEAMModelOS, "Teacher");
- var studentClient = client.GetContainer(Constant.TEAMModelOS, "Student");
- if (!request.TryGetProperty("id_token", out JsonElement id_token)) return BadRequest();
- var jwt = new JwtSecurityToken(id_token.GetString());
- var id = jwt.Payload.Sub;
- string school_code = jwt.Payload.Azp;
- //權限token
- jwt.Payload.TryGetValue("name", out object _name);
- jwt.Payload.TryGetValue("picture", out object _picture);
- (string ip, string region) = await LoginService.LoginIp(HttpContext, _searcher);
- School school = await schoolClient.ReadItemAsync<School>($"{school_code}", new PartitionKey("Base"));
- var response = await studentClient.ReadItemStreamAsync(id, new PartitionKey($"Base-{school_code.ToLower()}"));
- if (response.Status == 200)
- {
- var rjson = await JsonDocument.ParseAsync(response.ContentStream);
- Student student = rjson.ToObject<Student>();
- rjson.RootElement.TryGetProperty("salt", out JsonElement salt);
- rjson.RootElement.TryGetProperty("pw", out JsonElement dbpw);
- rjson.RootElement.TryGetProperty("name", out JsonElement name);
- rjson.RootElement.TryGetProperty("picture", out JsonElement picture);
- rjson.RootElement.TryGetProperty("classId", out JsonElement classId);
- rjson.RootElement.TryGetProperty("no", out JsonElement no);
- rjson.RootElement.TryGetProperty("groupId", out JsonElement groupId);
- rjson.RootElement.TryGetProperty("groupName", out JsonElement groupName);
- (string auth_token, string blob_uri, string blob_sas, object classinfo, List<object> courses, AuthenticationResult token) = await StudentCheck($"{id}", $"{classId}", $"{school_code}", $"{picture}", $"{name}", schoolClient, teacherClient, school.areaId, ip, client, student);
- return Ok(new { location = _option.Location, error = 0, auth_token, blob_uri, blob_sas, classinfo, courses, token = new { access_token = token.AccessToken, expires_in = token.ExpiresOn, id_token = auth_token, token_type = token.TokenType } });
- }
- else
- {
- return Ok(new { error = 2, message = "無此帳號存在" });
- }
- }
- /// <summary>
- /// 學生登入
- /// </summary>
- /// <param name = "request" ></ param >
- [AllowAnonymous]
- [HttpPost("login")]
- public async Task<IActionResult> Login(JsonElement request)
- {
- try
- {
- var client = _azureCosmos.GetCosmosClient();
- var schoolClient = client.GetContainer(Constant.TEAMModelOS, "School");
- var teacherClient = client.GetContainer(Constant.TEAMModelOS, "Teacher");
- var studentClient = client.GetContainer(Constant.TEAMModelOS, "Student");
- //參數取得
- if (!request.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
- if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
- if (!request.TryGetProperty("pw", out JsonElement pw)) return BadRequest();
- (string ip, string region) = await LoginService.LoginIp(HttpContext, _searcher);
- School school = await schoolClient.ReadItemAsync<School>($"{school_code}", new PartitionKey("Base"));
- var response = await studentClient.ReadItemStreamAsync(id.GetString(), new PartitionKey($"Base-{school_code.GetString().ToLower()}"));
- if (response.Status == 200)
- {
- var rjson = await JsonDocument.ParseAsync(response.ContentStream);
- Student student = rjson.ToObject<Student>();
- rjson.RootElement.TryGetProperty("salt", out JsonElement salt);
- rjson.RootElement.TryGetProperty("pw", out JsonElement dbpw);
- rjson.RootElement.TryGetProperty("name", out JsonElement name);
- rjson.RootElement.TryGetProperty("picture", out JsonElement picture);
- rjson.RootElement.TryGetProperty("classId", out JsonElement classId);
- rjson.RootElement.TryGetProperty("no", out JsonElement no);
- rjson.RootElement.TryGetProperty("groupId", out JsonElement groupId);
- rjson.RootElement.TryGetProperty("groupName", out JsonElement groupName);
- var HashedPW = Utils.HashedPassword(pw.ToString(), salt.ToString());
- if (HashedPW.Equals(dbpw.GetString()))
- {
- (string auth_token, string blob_uri, string blob_sas, object classinfo, List<object> courses, AuthenticationResult token) = await StudentCheck($"{id}", $"{classId}", $"{school_code}", $"{picture}", $"{name}", schoolClient, teacherClient, school.areaId,ip, client, student);
- return Ok(new { location = _option.Location, error = 0, auth_token, blob_uri, blob_sas, classinfo, courses, token = new { access_token = token.AccessToken, expires_in = token.ExpiresOn, id_token = auth_token, token_type = token.TokenType } });
- }
- else
- {
- return Ok(new { error = 1, message = "账号或密码错误" });
- }
- }
- else
- {
- return Ok(new { error = 2, message = "無此帳號存在" });
- }
- }
- catch (Exception ex)
- {
- await _dingDing.SendBotMsg($"IES5,{_option.Location},StudentController/login()\n{ex.Message}\n{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
- return BadRequest();
- }
- }
- private async Task<(string auth_token, string blob_uri, string blob_sas, object classinfo, List<object> courses, AuthenticationResult token)> StudentCheck(string id, string classId, string school_code, string picture, string name, CosmosContainer schoolClient, CosmosContainer teacherClient, string areaId,string ip,CosmosClient cosmosClient,Student student)
- {
- //班級課程
- object classinfo = null;
- List<object> courses = new List<object>();
- ////校本
- //取得所屬預設班級信息
- if (!string.IsNullOrWhiteSpace(classId))
- {
- var query = $"SELECT c.code, c.id, c.name, c.periodId, c.gradeId FROM c WHERE c.id = '{classId}'";
- await foreach (var item in schoolClient.GetItemQueryStreamIterator(queryText: query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Class-{school_code}") }))
- {
- using var json = await JsonDocument.ParseAsync(item.ContentStream);
- if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
- {
- foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
- {
- classinfo = obj.ToObject<object>();
- }
- }
- }
- }
- //取得該學生跑班課名單ID
- List<string> stulistidsSch = new List<string>();
- var querysl = $"SELECT c.id FROM c JOIN members IN c.members WHERE members.id = '{id}' AND members.code = '{school_code}'";
- await foreach (var item in schoolClient.GetItemQueryStreamIterator(queryText: querysl, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"GroupList-{school_code}") }))
- {
- using var json = await JsonDocument.ParseAsync(item.ContentStream);
- if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
- {
- foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
- {
- stulistidsSch.Add(obj.GetProperty("id").ToString());
- }
- }
- }
- //取得該學生的學校課程名單
- var queryc = $"SELECT DISTINCT c.id, c.name, schedule.class, schedule.time, schedule.notice, c.scope FROM c JOIN schedule IN c.schedule WHERE (schedule.class.id = '{classId}' AND schedule.stulist = null) OR (ARRAY_CONTAINS({JsonSerializer.Serialize(stulistidsSch)}, schedule.stulist, true))";
- await foreach (var item in schoolClient.GetItemQueryStreamIterator(queryText: queryc, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Course-{school_code}") }))
- {
- using var json = await JsonDocument.ParseAsync(item.ContentStream);
- if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
- {
- foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
- {
- courses.Add(obj.ToObject<object>());
- }
- }
- }
- ////個人
- //取得該學生跑班課名單ID
- Dictionary<string, Dictionary<string, string>> stulistidsTea = new Dictionary<string, Dictionary<string, string>>();
- var queryslt = $"SELECT c.id, c.course.id as courseId, c.course.code as courseCode FROM c JOIN members IN c.members WHERE members.id = '{id}' AND members.code = '{school_code}'";
- await foreach (var item in teacherClient.GetItemQueryStreamIterator(queryText: queryslt, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("GroupList") }))
- {
- using var json = await JsonDocument.ParseAsync(item.ContentStream);
- var js = json.RootElement.ToJsonString();
- if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
- {
- foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
- {
- string courseCode = "";
- if (obj.TryGetProperty("courseCode", out var code))
- {
- courseCode = code.GetString();
- }
- string courseId = "";
- if (obj.TryGetProperty("courseId", out var cosid))
- {
- courseId = cosid.GetString();
- }
- string stulistId = "";
- if (obj.TryGetProperty("id", out var listId))
- {
- stulistId = listId.GetString();
- }
- if (!string.IsNullOrEmpty(courseCode))
- {
- if (!stulistidsTea.ContainsKey(courseCode))
- {
- Dictionary<string, string> pCourseIdDic = new Dictionary<string, string>();
- pCourseIdDic.Add(courseId, stulistId);
- stulistidsTea.Add(courseCode, pCourseIdDic);
- }
- else
- {
- if (!stulistidsTea[courseCode].ContainsKey(courseId))
- {
- stulistidsTea[courseCode].Add(courseId, stulistId);
- }
- }
- }
- }
- }
- }
- //取得該學生的老師個人課程名單
- foreach (KeyValuePair<string, Dictionary<string, string>> item in stulistidsTea)
- {
- string courseCode = item.Key;
- Dictionary<string, string> courseIdDic = item.Value;
- string stucourseWhere = string.Empty;
- foreach (KeyValuePair<string, string> itemDic in courseIdDic)
- {
- string courseId = itemDic.Key;
- string stuListId = itemDic.Value;
- if (!string.IsNullOrWhiteSpace(stucourseWhere))
- {
- stucourseWhere += " OR ";
- }
- stucourseWhere += $"( c.id = '{courseId}' AND schedule.stulist = '{stuListId}' )";
- }
- var querycst = $"SELECT DISTINCT c.id, c.name, schedule.class, schedule.time, schedule.notice, c.scope FROM c JOIN schedule IN c.schedule WHERE {stucourseWhere}";
- await foreach (var itemcs in teacherClient.GetItemQueryStreamIterator(queryText: querycst, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{courseCode}") }))
- {
- using var json = await JsonDocument.ParseAsync(itemcs.ContentStream);
- if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
- {
- foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
- {
- courses.Add(obj.ToObject<object>());
- }
- }
- }
- }
- // BLOB(學校,唯讀)
- var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(school_code.ToLower(), BlobContainerSasPermissions.Read);
- //換取AuthToken,提供給前端
- var auth_token = JwtAuthExtension.CreateAuthToken(_option.HostName, id, name, picture, _option.JwtSecretKey, scope: Constant.ScopeStudent, Website: "IES", areaId: areaId, schoolID: school_code, roles: new[] { "student" }, expire: 1);
- //用户在线记录
- try
- {
- _ = _httpTrigger.RequestHttpTrigger(new { school = school_code, scope = $"{Constant.ScopeStudent}", id = $"{id}", ip = $"{ip}", expire = 1 }, _option.Location, "online-record");
- }
- catch {}
- await cosmosClient.GetContainer("TEAMModelOS", "Student").ReplaceItemAsync<Student>(student, id, new PartitionKey($"Base-{school_code}"));
- var clientID = _configuration.GetValue<string>("HaBookAuth:CoreService:clientID");
- var clientSecret = _configuration.GetValue<string>("HaBookAuth:CoreService:clientSecret");
- var token = await CoreTokenExtensions.CreateAccessToken(clientID, clientSecret, _option.Location.Replace("-Dep", "").Replace("-Test", ""));
- return (auth_token, blob_uri, blob_sas, classinfo, courses, token);
- }
- //查询学生名单详情
- [ProducesDefaultResponseType]
- //[AuthToken(Roles = "teacher")]
- [HttpPost("get-summary-student")]
- [Authorize(Roles = "IES")]
- public async Task<IActionResult> getSummary(JsonElement requert)
- {
- try
- {
- requert.TryGetProperty("students", out JsonElement students);
- requert.TryGetProperty("tmdIds", out JsonElement tmdIds);
- List<TmdInfo> tmdinfos = new List<TmdInfo>();
- List<object> stus = new List<object>();
- var client = _azureCosmos.GetCosmosClient();
- if (students.ValueKind.Equals(JsonValueKind.Array))
- {
- List<Students> stuList = students.ToObject<List<Students>>();
- if (stuList.IsNotEmpty())
- {
- foreach (Students stu in stuList)
- {
- var query = $"select c.id,c.name,c.picture,c.classId,c.code,c.groupId,c.groupName,c.no from c where c.id = '{stu.id}'";
- await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Student").GetItemQueryStreamIterator(queryText: query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{stu.code}") }))
- {
- using var json = await JsonDocument.ParseAsync(item.ContentStream);
- if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
- {
- foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
- {
- stus.Add(obj.ToObject<object>());
- }
- }
- }
- }
- }
- }
- if (tmdIds.ValueKind.Equals(JsonValueKind.Array))
- {
- List<string> tmdids = tmdIds.ToObject<List<string>>();
- if (tmdids.IsNotEmpty())
- {
- List<string> inids = new List<string>();
- tmdids.ForEach(x => { inids.Add($"'{x}'"); });
- var insql = string.Join(",", inids);
- var queryslt = $"SELECT c.id,c.name,c.picture FROM c where c.id in ({insql})";
- await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Student").GetItemQueryIterator<TmdInfo>(queryText: queryslt, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base") }))
- {
- tmdinfos.Add(item);
- }
- }
- }
- return Ok(new { stus, tmdinfos });
- }
- catch (Exception ex)
- {
- await _dingDing.SendBotMsg($"OS,{_option.Location},student/get-summary-student()\n{ex.Message}\n{ex.StackTrace}\n", GroupNames.醍摩豆服務運維群組);
- return BadRequest();
- }
- }
- /// <summary>
- /// 學生簡易登入
- /// </summary>
- /// <param name = "request" ></ param >
- [AllowAnonymous]
- [HttpPost("login-simple")]
- public async Task<IActionResult> LoginSimple(JsonElement request)
- {
- try
- {
- var client = _azureCosmos.GetCosmosClient();
- var schoolClient = client.GetContainer(Constant.TEAMModelOS, "School");
- var studentClient = client.GetContainer(Constant.TEAMModelOS, "Student");
- //參數取得
- if (!request.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
- if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
- if (!request.TryGetProperty("pw", out JsonElement pw)) return BadRequest();
- (string ip, string region) = await LoginService.LoginIp(HttpContext, _searcher);
- var response = await studentClient.ReadItemStreamAsync(id.GetString(), new PartitionKey($"Base-{school_code.GetString().ToLower()}"));
- if (response.Status == 200)
- {
- var rjson = await JsonDocument.ParseAsync(response.ContentStream);
- Student student = rjson.ToObject<Student>();
- rjson.RootElement.TryGetProperty("salt", out JsonElement salt);
- rjson.RootElement.TryGetProperty("pw", out JsonElement dbpw);
- rjson.RootElement.TryGetProperty("name", out JsonElement name);
- rjson.RootElement.TryGetProperty("picture", out JsonElement picture);
- rjson.RootElement.TryGetProperty("classId", out JsonElement classId);
- rjson.RootElement.TryGetProperty("no", out JsonElement no);
- rjson.RootElement.TryGetProperty("groupId", out JsonElement groupId);
- rjson.RootElement.TryGetProperty("groupName", out JsonElement groupName);
- dynamic user = new ExpandoObject();
- user.no = no;
- user.groupId = groupId;
- user.groupName = groupName;
- var HashedPW = Utils.HashedPassword(pw.ToString(), salt.ToString());
- if (HashedPW.Equals(dbpw.GetString()))
- {
- School schoolInfo = await schoolClient.ReadItemAsync<School>($"{school_code}", new PartitionKey("Base"));
- //取得所屬預設班級信息
- object classinfo = null;
- if (!classId.ValueKind.Equals(JsonValueKind.Null) && classId.ValueKind.Equals(JsonValueKind.String))
- {
- var query = $"SELECT c.id, c.no, c.name FROM c WHERE c.id = '{classId.GetString()}'";
- await foreach (var item in schoolClient.GetItemQueryStreamIterator(queryText: query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Class-{school_code}") }))
- {
- using var json = await JsonDocument.ParseAsync(item.ContentStream);
- if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
- {
- foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
- {
- classinfo = obj.ToObject<object>();
- }
- }
- }
- }
- //換取AuthToken,提供給前端
- var auth_token = JwtAuthExtension.CreateAuthToken(_option.HostName, id.GetString(), name.GetString(), picture.GetString(), _option.JwtSecretKey, Website: "IES", areaId: schoolInfo.areaId, scope: Constant.ScopeStudent, schoolID: school_code.GetString(), roles: new[] { "student" }, expire: 1);
-
- //用户在线记录
- try
- {
- _ = _httpTrigger.RequestHttpTrigger(new { school = school_code.GetString(), scope = $"{Constant.ScopeStudent}", id = $"{id}", ip = $"{ip}", expire = 1 }, _option.Location, "online-record");
- }
- catch { }
- //保存学生登录信息
- await client.GetContainer("TEAMModelOS", "Student").ReplaceItemAsync<Student>(student, student.id, new PartitionKey($"{student.code}"));
- //其他訊息
- dynamic school = new ExpandoObject();
- //回傳
- return Ok(new { error = 0, auth_token, classinfo, user });
- }
- else
- {
- return Ok(new { error = 1, message = "Invalid account or password" });
- }
- }
- else
- {
- return Ok(new { error = 2, message = "Invalid account" });
- }
- }
- catch (Exception ex)
- {
- await _dingDing.SendBotMsg($"IES5,{_option.Location},StudentController/login-simple()\n{ex.Message}\n{ex.StackTrace}\n", GroupNames.醍摩豆服務運維群組);
- return BadRequest();
- }
- }
- //TODO 此API需處理對應前端返回的相關數據
- [ProducesDefaultResponseType]
- [AuthToken(Roles = "student,teacher")]
- [HttpPost("get-school-info")]
- public async Task<IActionResult> GetSchoolInfo(JsonElement request)
- {
- try
- {
- var (id, _, _, school) = HttpContext.GetAuthTokenInfo();
- var client = _azureCosmos.GetCosmosClient();
- /// tmdid, schoolid
- var userType = "schoolid";
- if (request.TryGetProperty("userType", out JsonElement usertype))
- {
- if (!usertype.ValueKind.Equals(JsonValueKind.Undefined) && !usertype.ValueKind.Equals(JsonValueKind.Null) && usertype.ValueKind.Equals(JsonValueKind.String))
- {
- userType = usertype.GetString();
- }
- }
- if (string.IsNullOrEmpty(school))
- {
- if (userType.Equals("tmdid"))
- {
- Teacher teacher = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<Teacher>(id, new PartitionKey("Base"));
- if (teacher.schools.IsNotEmpty())
- {
- var tech = teacher.schools.Find(x => x.status.Equals("join"));
- if (tech == null)
- {
- school = teacher.schools[0].schoolId;
- }
- else
- {
- school = tech.schoolId;
- }
- }
- }
- }
- if (!string.IsNullOrEmpty(school))
- {
- object school_base = null;
- var response = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(school, new PartitionKey("Base"));
- if (response.Status == 200)
- {
- using var json = await JsonDocument.ParseAsync(response.ContentStream);
- school_base = json.RootElement.ToObject<object>();
- }
- //取得班级
- List<object> school_classes = new List<object>();
- await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryText: $"SELECT c.id,c.x,c.y,c.name,c.year,c.teacher,c.periodId,c.gradeId,c.room,c.sn,c.no,c.style,c.status,c.openType,c.scope, ARRAY_LENGTH(c.students) AS studCount FROM c", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Class-{school}") }))
- {
- var jsonc = await JsonDocument.ParseAsync(item.ContentStream);
- foreach (var classeinfo in jsonc.RootElement.GetProperty("Documents").EnumerateArray())
- {
- school_classes.Add(classeinfo.ToObject<object>());
- }
- }
- //取得教室
- List<Room> school_rooms = new List<Room>();
- await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<Room>(queryText: $"select value(c) from c ",
- requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Room-{school}") }))
- {
- school_rooms.Add(item);
- }
- return Ok(new { school_base, school_classes, school_rooms, status = 200 });
- }
- else
- {
- return Ok(new { status = 404 }); ;
- }
- }
- catch (CosmosException ex)
- {
- return Ok(new { status = ex.Status }); ;
- }
- catch (Exception ex)
- {
- await _dingDing.SendBotMsg($"IES5,{_option.Location},Student/get-school-info()\n{ex.Message}\n{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
- return BadRequest();
- }
- }
- }
- }
|