123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323 |
- using Azure.Cosmos;
- using Microsoft.AspNetCore.Mvc;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Threading.Tasks;
- using TEAMModelOS.SDK;
- using TEAMModelOS.SDK.Helper.Common.CollectionHelper;
- using TEAMModelOS.SDK.Helper.Security.TmdCrypt;
- using TEAMModelOS.SDK.DI;
- using TEAMModelOS.SDK.Helper.Common.ValidateHelper;
- using TEAMModelOS.Models;
- using System.Text.Json;
- using TEAMModelOS.Models.StudentInfo;
- using Microsoft.AspNetCore.Http;
- using TEAMModelOS.SDK.Extension;
- using Microsoft.AspNetCore.Cryptography.KeyDerivation;
- using System.Text;
- using Microsoft.Extensions.Options;
- namespace TEAMModelOS.Controllers
- {
- [ProducesResponseType(StatusCodes.Status200OK)]
- [ProducesResponseType(StatusCodes.Status400BadRequest)]
- //[Authorize(Roles = "IES5")]
- [Route("student/init")]
- [ApiController]
- // [Authorize]
- public class StudentController : ControllerBase
- {
- private readonly AzureCosmosFactory _azureCosmos;
- private readonly Option _option;
- public StudentController(AzureCosmosFactory azureCosmos, IOptionsSnapshot<Option> option)
- {
- _azureCosmos = azureCosmos;
- _option = option?.Value;
- }
- /// <summary>
- /// 保存或更新学生,并维护学生关系表
- /// </summary>
- /// <param name="request"></param>
- /// <returns></returns>
- [ProducesDefaultResponseType]
- //[AuthToken(Roles = "teacher")]
- [HttpPost("upsert")]
- public async Task<BaseResponse> Upsert(Student request)
- {
- ResponseBuilder builder = ResponseBuilder.custom();
- //设置密码 isSet 是否加密 如果加密则不会再次加密
- if (!request.password.isSet)
- {
- request.password.value = TmdCrypt.Encrypt(request.password.value);
- request.password.isSet = true;
- }
- request.id = request.studentId.Replace("#", "-");
- ///假如更新了班级则先获取更新之前的班级
- var olStudent= await _azureCosmos.FindByIdPk<Student>(request.id,request.code);
- if (olStudent!=null && !string.IsNullOrEmpty(olStudent.classroomCode) && ! olStudent.classroomCode.Equals(request.classroomCode) ) {
- //移除之前的原生班级
- IdPk idPk=await _azureCosmos.DeleteAsync<ClassStudent>( olStudent.classroomCode ,olStudent.studentId);
-
- }
- ///新建最新的班级关系表
- ClassStudent classroomStudent = new ClassStudent { id = request.classroomCode, code = request.studentId };
- await _azureCosmos.SaveOrUpdate(classroomStudent);
- Student data = await _azureCosmos.SaveOrUpdate<Student>(request);
- return builder.Data(data).build();
- }
- /// <summary>
- /// 查找学生
- /// </summary>
- /// <param name="request"></param>
- /// <returns></returns>
- [ProducesDefaultResponseType]
- //[AuthToken(Roles = "teacher")]
- [HttpPost("find")]
- public async Task<IActionResult> Find(JsonElement requert)
- {
- var client = _azureCosmos.GetCosmosClient();
- if (!requert.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
- List<object> students = new List<object>();
- await foreach (var item in client.GetContainer("TEAMModelOS", "Student").GetItemQueryStreamIterator(queryText: $"select c.id, c.name,c.mail,c.mobile,c.year,c.schoolId from c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Student-{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())
- {
- students.Add(obj.ToObject<object>());
- }
- }
- }
- return Ok(new { students });
- /* ResponseBuilder builder = ResponseBuilder.custom();
- if (request.TryGetProperty("code", out _))
- {
- List<Student> data = await _azureCosmos.FindByDict<Student>(request);
- return builder.Data(data).build();
- }
- else
- {
- return builder.Error(ResponseCode.PARAMS_ERROR, "code is null !").build();
-
- }*/
- }
- [ProducesDefaultResponseType]
- //[AuthToken(Roles = "teacher")]
- [HttpPost("upsert-all")]
- public async Task<IActionResult> UpsertAll(List<Student> request)
- {
- ResponseBuilder builder = ResponseBuilder.custom();
- if (ValidateHelper.IsValid(request) && request.IsNotEmpty()) {
- ///假如更新了班级则先获取更新之前的班级
- string[] ids = request.Select(x=>x.studentId).ToArray();
- List<Student> oldStudent = await _azureCosmos.FindByDict<Student>(new Dictionary<string, object>() { { "studentId", ids } });
- List<IdPk> idPks = new List<IdPk>();
- ///处理未变动的班级关系
- List<IdPk> unpk = new List<IdPk>();
- oldStudent.ForEach(x=> {
- request.ForEach(m => {
- if (x.studentId.Equals(m.studentId)) {
- if (!x.classroomCode.Equals(m.classroomCode))
- {
- idPks.Add(new IdPk { id = x.classroomCode, pk = x.studentId });
- }
- else {
- unpk.Add(new IdPk { id = x.classroomCode, pk = x.studentId });
- }
- }
- });
- });
- if (idPks.IsNotEmpty()) {
- await _azureCosmos.DeleteAll<ClassStudent>(idPks);
- }
- long createDate = DateTimeOffset.UtcNow.Ticks;
- request.ForEach(
- x => {
- x.createDate = createDate;
- x.id = x.studentId.Replace("#", "-");
- //设置密码 isSet 是否加密 如果加密则不会再次加密
- if (!x.password.isSet)
- {
- x.password.value = TmdCrypt.Encrypt(x.password.value);
- x.password.isSet = true;
- }
- });
- List<Student> students = await _azureCosmos.SaveOrUpdateAll(request);
- ///更新学生关系表
- List<ClassStudent> classroomStudents = new List<ClassStudent>();
- foreach (var student in students)
- {
- // 处理未变更原生班级的学生
- bool has = false;
- foreach (IdPk idPk in unpk) {
- if (idPk.id.Equals(student.classroomCode) && idPk.pk.Equals(student.studentId)) {
- has = true;
- }
- }
- if (has)
- {
- continue;
- }
- else {
- classroomStudents.Add(new ClassStudent { id = student.classroomCode, code = student.studentId });
- }
- }
- await _azureCosmos.SaveOrUpdateAll(classroomStudents);
- builder.Data(students);
- }
- return Ok();
- }
- /// <summary>
- /// 删除单个学生
- /// </summary>
- /// <param name="request"></param>
- /// <returns></returns>
- [ProducesDefaultResponseType]
- //[AuthToken(Roles = "teacher")]
- [HttpPost("delete")]
- public async Task<IActionResult> Delete(JsonElement requert)
- {
- if (!requert.TryGetProperty("id", out JsonElement id)) return BadRequest();
- if (!requert.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
- var client = _azureCosmos.GetCosmosClient();
- var response = await client.GetContainer("TEAMModelOS", "Student").DeleteItemStreamAsync(id.ToJsonString(), new PartitionKey($"Base-{school_code}"));
- if (response.Status == 200)
- {
- await _azureCosmos.DeleteAll<ClassStudent>(new Dictionary<string, object> { { "code", id.ToJsonString() } });
- }
- else {
- return BadRequest();
- }
- return Ok();
- /*ResponseBuilder builder = ResponseBuilder.custom();
- IdPk data = await _azureCosmos.DeleteAsync<Student>(request.id, request.code);
- ///更新学生关系表
- await _azureCosmos.DeleteAll<ClassStudent>(new Dictionary<string, object> { { "code", request.studentId } });
- return builder.Data(data).build();*/
- }
- /// <summary>
- /// 批量删除并维护关联关系
- /// </summary>
- /// <param name="request"></param>
- /// <returns></returns>
- [ProducesDefaultResponseType]
- //[AuthToken(Roles = "teacher")]
- [HttpPost("bulkDelete")]
- public async Task<IActionResult> BulkDelete(JsonElement request)
- {
- ResponseBuilder builder = ResponseBuilder.custom();
- //Dictionary<string, object> dict = new Dictionary<string, object>();
- var emobj = request.EnumerateObject();
- int keys = 0;
- while (emobj.MoveNext())
- {
- keys++;
- //dict[emobj.Current.Name] = emobj.Current.Value;
- }
- if (keys > 0&& request.TryGetProperty("code",out JsonElement code)) {
- List<Student> students = await _azureCosmos.FindByDict<Student>(request);
- await _azureCosmos.DeleteAll<Student>(students);
- ///更新学生关系表
- await _azureCosmos.DeleteAll<ClassStudent>(new Dictionary<string, object> { {"code",students.Select(x=>x.studentId).ToArray() } });
- builder.Data(students);
- }
- return Ok();
- }
- /// <summary>
- /// 學生登入
- /// </summary>
- /// <param name = "request" ></ param >
- [HttpPost("Login")]
- public async Task<IActionResult> Login(JsonElement request)
- {
- var client = _azureCosmos.GetCosmosClient();
- //參數取得
- 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();
- var response = await client.GetContainer("TEAMModelOS", "Student").ReadItemStreamAsync(id.GetString(), new PartitionKey($"Base-{school_code.ToString().ToLower()}"));
-
- int error = 0;
- string message = "帳號或密碼錯誤";
- string auth_token = "";
- if (response.Status == 200)
- {
- using var json = await JsonDocument.ParseAsync(response.ContentStream);
- // 取得資料庫salt
- json.RootElement.TryGetProperty("salt", out JsonElement salt);
- // 取得資料庫pw
- json.RootElement.TryGetProperty("pw", out JsonElement dbpw);
- // 取得資料庫name
- json.RootElement.TryGetProperty("name", out JsonElement name);
- var HashedPW = HashedPassword(pw.ToString(), salt.ToString());
- if (dbpw.ToString().Equals(HashedPW.ToString()))
- {
- //換取AuthToken,提供給前端
- auth_token = JwtAuthExtension.CreateAuthToken(_option.HostName, id.GetString(), name.GetString(), "", _option.JwtSecretKey, roles: new[] { "student" });
- }
- else
- {
- error = 1;
- }
- }
- else
- {
- error = 1;
- }
- if (error > 0)
- {
- return Ok(
- new
- {
- error,
- message
- }
- );
- }
- else
- {
- return Ok(
- new
- {
- auth_token
- }
- );
- }
- }
- public static string HashedPassword(string password, string salt)
- {
- byte[] hashBytes = KeyDerivation.Pbkdf2(
- password: password,
- salt: Encoding.UTF8.GetBytes(salt), // SHA1鹽(8-20字節), SHA256(32字節)
- prf: KeyDerivationPrf.HMACSHA1,
- iterationCount: 10000, // hash次數,越多次代表破解難度變高,但效能差點
- numBytesRequested: 256 / 8 // 指定得出結果長度
- );
- String hashText = BitConverter.ToString(hashBytes).Replace("-", string.Empty);
- return hashText;
- }
- }
- }
|