using Azure.Cosmos; using Azure.Storage.Blobs.Models; using Azure.Storage.Sas; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; using System; using System.Collections.Generic; using System.Dynamic; using System.IdentityModel.Tokens.Jwt; using System.IO; using System.Linq; using System.Text.Json; using System.Threading.Tasks; using TEAMModelOS.Models; using TEAMModelOS.SDK.Models; using TEAMModelOS.SDK.DI; using TEAMModelOS.SDK.Extension; using TEAMModelOS.SDK.Filter; using TEAMModelOS.SDK.Models.Cosmos; using HTEXLib.COMM.Helpers; using TEAMModelOS.SDK.Models.Service; using Microsoft.Extensions.Configuration; using System.Net.Http; using TEAMModelOS.SDK; using static TEAMModelOS.SDK.Models.Teacher; using static TEAMModelOS.SDK.DI.AzureCosmosExtensions; namespace TEAMModelOS.Services { public static class TeacherService { public static async Task TeacherInfoLite(AzureCosmosFactory _azureCosmos, string name, string picture, string id, AzureStorageFactory _azureStorage, Option _option, AzureRedisFactory _azureRedis, string ip, HttpTrigger _httpTrigger, string lang) { Teacher teacher = null; string defaultschool = null; //TODO 取得Teacher 個人相關數據(課程清單、虛擬教室清單、歷史紀錄清單等),學校數據另外API處理,多校切換時不同 var client = _azureCosmos.GetCosmosClient(); try { if (teacher == null) { teacher = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync(id, new PartitionKey("Base")); if (!string.IsNullOrWhiteSpace(lang) && string.IsNullOrWhiteSpace(teacher.lang)) { teacher.lang = lang; } teacher.name = $"{name}"; teacher.picture = $"{picture}"; } else { name = teacher.name; picture = teacher.picture; id = teacher.id; } //处理导入时,在学校名单有该教师加入的,但是基本信息没有的 string schoolJoinTeacher = $"SELECT value c.id FROM c join b in c.teachers where c.code='TeacherImport' and b.tmdid='{teacher.id}' and b.status='join'"; var schoolJoins = await client.GetContainer(Constant.TEAMModelOS, Constant.School).GetList(schoolJoinTeacher, "TeacherImport"); if (schoolJoins.list.IsNotEmpty()) { var notInBase = schoolJoins.list.Except(teacher.schools.Select(z => z.schoolId)); if (notInBase.Any()) { string sqlSchoolBase = $"SELECT value c FROM c where c.id in ({string.Join(",", notInBase.Select(z => $"'{z}'"))})"; var schoolBase = await client.GetContainer(Constant.TEAMModelOS, Constant.School).GetList(sqlSchoolBase, "Base"); if (schoolBase.list.IsNotEmpty()) { var nowtime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); foreach (var school in schoolBase.list) { if (!teacher.schools.Exists(z => z.schoolId.Equals(school.id))) { teacher.schools.Add(new TeacherSchool { schoolId = school.id, areaId = school.areaId, name = school.name, picture = school.picture, status = "join", time = nowtime }); } } } } } //检查是否有加入学校,如果加入学校,则当个人空间size是0G的时候,则免费获得一个G空间,但无论加入多少个学校,只能获取一次 1G的免费空间。没有加入学校则默认0G空间,除非自己购买空间 if (teacher.schools.IsNotEmpty()) { foreach (var sc in teacher.schools) { string statusNow = sc.status != null ? sc.status : ""; if (statusNow.Equals("join")) { var sctch = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(id, new PartitionKey($"Teacher-{sc.schoolId}")); if (sctch.Status == 200 && sctch != null && sctch.ContentStream != null) { var jsonDoc = await JsonDocument.ParseAsync(sctch.ContentStream); SchoolTeacher schoolTeacher = jsonDoc.RootElement.ToObject(); if (schoolTeacher.name == null || schoolTeacher.picture == null || !schoolTeacher.name.Equals($"{name}") || !schoolTeacher.picture.Equals($"{picture}")) { schoolTeacher.name = $"{name}"; schoolTeacher.picture = $"{picture}"; await client.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync(schoolTeacher, id, new PartitionKey($"Teacher-{sc.schoolId}")); } } } } //如果包含任何申请,邀请,加入学校的记录 且个人空间未分配2G 则默认分配个人空间至2G. if (teacher.size < 2 && teacher.schools.Count > 0) { teacher.size = 2; } //如果未包含任何申请,邀请,加入学校的记录 且 个人空间没有分配1G 则默认赠送一个G if (teacher.schools.Count == 0 && teacher.size < 1) { teacher.size = 1; } } if (string.IsNullOrEmpty(teacher.defaultSchool) && teacher.schools.IsNotEmpty()) { var tech = teacher.schools.FindAll(x => x.status.Equals("join")); if (tech.IsNotEmpty()) { teacher.defaultSchool = teacher.schools[0].schoolId; } } if (!string.IsNullOrEmpty(teacher.defaultSchool)) { if (teacher.schools.IsNotEmpty()) { var tech = teacher.schools.FindAll(x => x.status.Equals("join") && x.schoolId.Equals(teacher.defaultSchool)); if (!tech.IsNotEmpty()) { var techde = teacher.schools.FindAll(x => x.status.Equals("join")); if (techde.IsNotEmpty()) { teacher.defaultSchool = techde[0].schoolId; } else { teacher.defaultSchool = null; } } } else { teacher.defaultSchool = null; } } await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync(teacher, id, new PartitionKey("Base")); //預設學校ID defaultschool = teacher.defaultSchool; } catch (CosmosException ex) { if (ex.Status == 404 && teacher == null) { //如果沒有,則初始化Teacher基本資料到Cosmos 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(), lang=lang }; var container = _azureStorage.GetBlobContainerClient(id); await container.CreateIfNotExistsAsync(PublicAccessType.None); //嘗試創建Teacher私有容器,如存在則不做任何事,保障容器一定存在 teacher = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync(teacher, new PartitionKey("Base")); } } catch (Exception ex) { throw new Exception($"{ex.Message}\n{ex.StackTrace}"); } List roles = new List() { "teacher" }; //換取AuthToken,提供給前端 //用户在线记录 try { _ = _httpTrigger.RequestHttpTrigger(new { school = defaultschool, scope = $"{Constant.ScopeTeacher}", id = $"{id}", ip = $"{ip}", expire = 1 }, _option.Location, "online-record"); } catch { } //取得Teacher Blob 容器位置及SAS await _azureStorage.GetBlobContainerClient(id).CreateIfNotExistsAsync(PublicAccessType.None); //嘗試創建Teacher私有容器,如存在則不做任何事,保障容器一定存在 var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(id, BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Delete); return new TeacherInfo { blob_uri = blob_uri, blob_sas = blob_sas, defaultschool = defaultschool, teacher = teacher }; } public static async Task TeacherInfo(AzureCosmosFactory _azureCosmos, Teacher teacher, string name, string picture, string id, AzureStorageFactory _azureStorage, Option _option, AzureRedisFactory _azureRedis, string ip, HttpTrigger _httpTrigger, string lang) { List schools = new List(); List areas = new List(); string defaultschool = null; //TODO 取得Teacher 個人相關數據(課程清單、虛擬教室清單、歷史紀錄清單等),學校數據另外API處理,多校切換時不同 var client = _azureCosmos.GetCosmosClient(); int total = 0; int tsize = 0; List areasDbs = new List(); List areaSettings = new List(); try { if (teacher == null) { teacher = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync(id, new PartitionKey("Base")); if (!string.IsNullOrWhiteSpace(lang) && string.IsNullOrWhiteSpace(teacher.lang)) { teacher.lang = lang; } teacher.name = $"{name}"; teacher.picture = $"{picture}"; } else { name = teacher.name; picture = teacher.picture; id = teacher.id; } ///教师的个人空间 tsize = teacher.size; ///教师的总空间 包含 个人空间和学校赠送的空间累加 total = teacher.size; HashSet areaIds = new HashSet(); if (teacher.areas.IsNotEmpty()) { teacher.areas.ForEach(x => { areaIds.Add(x.areaId); }); } if (teacher.schools.IsNotEmpty()) { teacher.schools.ForEach(x => { if (!string.IsNullOrEmpty(x.areaId)) { areaIds.Add(x.areaId); } }); } if (areaIds.Count > 0) { string queryText = $"select value(c) from c where c.id in ({string.Join(",", areaIds.Select(x => $"'{x}'"))})"; await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Normal").GetItemQueryIterator(queryText: queryText, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base-Area") })) { areasDbs.Add(item); } await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Normal").GetItemQueryIterator(queryText: queryText, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("AreaSetting") })) { areaSettings.Add(item); } } if (teacher.areas.IsNotEmpty()) { foreach (var areat in teacher.areas) { Area area = areasDbs.Find(x => x.id.Equals(areat.areaId)); AreaSetting setting = null; if (area != null) { setting = areaSettings.Find(x => x.id.Equals(areat.areaId)); } int access = 0; if (setting != null && !string.IsNullOrWhiteSpace(setting.accessConfig)) { access = 1; } var container = _azureStorage.GetBlobContainerClient(area?.id); await container.CreateIfNotExistsAsync(PublicAccessType.None); //嘗試創建Teacher私有容器,如存在則不做任何事,保障容器一定存在 var blobArea= _azureStorage.GetBlobContainerSAS(area?.id, blobContainerSasPermissions: BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Delete); //if (setting != null) //{ // setting.accessConfig = null; //} areas.Add(new AreaDto { sas= blobArea.sas,url =blobArea.uri ,areaId = area?.id, name = area?.name, standard = area?.standard, standardName = area?.standardName, setting = setting, access = access ,shortCode=area.shortCode}); } } //处理导入时,在学校名单有该教师加入的,但是基本信息没有的 string schoolJoinTeacher = $"SELECT value c.id FROM c join b in c.teachers where c.code='TeacherImport' and b.tmdid='{teacher.id}' and b.status='join'"; var schoolJoins = await client.GetContainer(Constant.TEAMModelOS, Constant.School).GetList(schoolJoinTeacher, "TeacherImport"); if (schoolJoins.list.IsNotEmpty()) { var notInBase = schoolJoins.list.Except(teacher.schools.Select(z => z.schoolId)); if (notInBase.Any()) { string sqlSchoolBase = $"SELECT value c FROM c where c.id in ({string.Join(",", notInBase.Select(z => $"'{z}'"))})"; var schoolBase = await client.GetContainer(Constant.TEAMModelOS, Constant.School).GetList(sqlSchoolBase, "Base"); if (schoolBase.list.IsNotEmpty()) { var nowtime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); foreach (var school in schoolBase.list) { if (!teacher.schools.Exists(z => z.schoolId.Equals(school.id))) { teacher.schools.Add(new TeacherSchool { schoolId = school.id, areaId = school.areaId, name = school.name, picture = school.picture, status = "join", time = nowtime }); } } } } } //检查是否有加入学校,如果加入学校,则当个人空间size是0G的时候,则免费获得一个G空间,但无论加入多少个学校,只能获取一次 1G的免费空间。没有加入学校则默认0G空间,除非自己购买空间 if (teacher.schools.IsNotEmpty()) { foreach (var sc in teacher.schools) { string statusNow = sc.status != null ? sc.status : ""; if (statusNow.Equals("join") || statusNow.Equals("invite") || statusNow.Equals("request")) { dynamic schoolExtobj = new ExpandoObject(); schoolExtobj.schoolId = sc.schoolId; schoolExtobj.name = sc.name; schoolExtobj.status = sc.status; schoolExtobj.time = sc.time; schoolExtobj.picture = sc.picture; schoolExtobj.areaId = $"{sc.areaId}"; Area area = null; int access = 0; if (!string.IsNullOrEmpty($"{sc.areaId}")) { area = areasDbs.Find(x => x.id.Equals(sc.areaId)); AreaSetting setting = null; if (area != null) { setting = areaSettings.Find(x => x.id.Equals(sc.areaId)); } if (setting != null && !string.IsNullOrWhiteSpace(setting.accessConfig)) { access = 1; } } if (area != null) { schoolExtobj.area = new { area.name, area.id, area.institution, area.provName, area.code, area.cityCode, area.cityName, area.standard, area.provCode, area.pk, access }; } else { schoolExtobj.area = area; } var sctch = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(id, new PartitionKey($"Teacher-{sc.schoolId}")); if (sctch.Status == 200 && sctch != null && sctch.ContentStream != null) { var jsonDoc = await JsonDocument.ParseAsync(sctch.ContentStream); SchoolTeacher schoolTeacher = jsonDoc.RootElement.ToObject(); if (schoolTeacher.name == null || schoolTeacher.picture == null || !schoolTeacher.name.Equals($"{name}") || !schoolTeacher.picture.Equals($"{picture}")) { schoolTeacher.name = $"{name}"; schoolTeacher.picture = $"{picture}"; await client.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync(schoolTeacher, id, new PartitionKey($"Teacher-{sc.schoolId}")); } if (jsonDoc.RootElement.TryGetProperty("size", out JsonElement _size) && _size.ValueKind.Equals(JsonValueKind.Number)) { total += _size.GetInt32(); schoolExtobj.size = _size.GetInt32(); } else { schoolExtobj.size = 0; } } else { schoolExtobj.size = 0; } //if (statusNow.Equals("join")) //{ // await TmdUserService.JoinSchool(client, teacher.id, teacher.picture, teacher.name, sc.schoolId, sc.name); //} schools.Add(schoolExtobj); } } //如果包含任何申请,邀请,加入学校的记录 且个人空间未分配2G 则默认分配个人空间至2G. if (teacher.size < 2 && teacher.schools.Count > 0) { teacher.size = 2; } //如果未包含任何申请,邀请,加入学校的记录 且 个人空间没有分配1G 则默认赠送一个G if (teacher.schools.Count == 0 && teacher.size < 1) { teacher.size = 1; } } if (string.IsNullOrEmpty(teacher.defaultSchool) && teacher.schools.IsNotEmpty()) { var tech = teacher.schools.FindAll(x => x.status.Equals("join")); if (tech.IsNotEmpty()) { teacher.defaultSchool = teacher.schools[0].schoolId; } } if (!string.IsNullOrEmpty(teacher.defaultSchool)) { if (teacher.schools.IsNotEmpty()) { var tech = teacher.schools.FindAll(x => x.status.Equals("join") && x.schoolId.Equals(teacher.defaultSchool)); if (!tech.IsNotEmpty()) { var techde = teacher.schools.FindAll(x => x.status.Equals("join")); if (techde.IsNotEmpty()) { teacher.defaultSchool = techde[0].schoolId; } else { teacher.defaultSchool = null; } } } else { teacher.defaultSchool = null; } } await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync(teacher, id, new PartitionKey("Base")); //預設學校ID defaultschool = teacher.defaultSchool; } catch (CosmosException ex) { if (ex.Status == 404 && teacher == null) { //如果沒有,則初始化Teacher基本資料到Cosmos 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(), lang=lang }; var container = _azureStorage.GetBlobContainerClient(id); await container.CreateIfNotExistsAsync(PublicAccessType.None); //嘗試創建Teacher私有容器,如存在則不做任何事,保障容器一定存在 teacher = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync(teacher, new PartitionKey("Base")); total = teacher.size; tsize = teacher.size; } } catch (Exception ex) { throw new Exception($"{ex.Message}\n{ex.StackTrace}"); } //私人課程 List courses = new List(); await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryStreamIterator(queryText: $"select value(c) from c WHERE c.creatorId = '{id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"CourseBase") })) { 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()); } } } List roles = new List() { "teacher" }; Area areaa = null; if (areas.Count > 0) { roles.Add("area"); if (!string.IsNullOrEmpty($"{areas[0]}")) { areaa = areasDbs.Find(x => x.Equals(areas[0].areaId)); } } //換取AuthToken,提供給前端 var auth_token = JwtAuthExtension.CreateAuthToken(_option.HostName, id, name?.ToString(), picture?.ToString(), _option.JwtSecretKey, Website: "IES", scope: Constant.ScopeTeacher, standard: areaa != null ? areaa.standard : "", roles: roles.ToArray(), expire: 1); //用户在线记录 try { _ = _httpTrigger.RequestHttpTrigger(new { school = defaultschool, scope = $"{Constant.ScopeTeacher}", id = $"{id}", ip = $"{ip}", expire = 1 }, _option.Location, "online-record"); } catch { } //取得Teacher Blob 容器位置及SAS await _azureStorage.GetBlobContainerClient(id).CreateIfNotExistsAsync(PublicAccessType.None); //嘗試創建Teacher私有容器,如存在則不做任何事,保障容器一定存在 var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(id, BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Delete); var (osblob_uri, osblob_sas) = roles.Contains("area") ? _azureStorage.GetBlobContainerSAS("teammodelos", BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Delete) : _azureStorage.GetBlobContainerSAS("teammodelos", BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List); return new TeacherInfo { auth_token = auth_token, blob_uri = blob_uri, blob_sas = blob_sas, schools = schools, defaultschool = defaultschool, courses = courses, total = total, osblob_sas = osblob_sas, osblob_uri = osblob_uri, tsize = tsize, areas = areas, teacher = teacher }; } } public record AreaDto { //areaId = area.id, name = area.name, area.standard, area.standardName public string areaId { get; set; } public string name { get; set; } public string standard { get; set; } public string standardName { get; set; } //public string accessConfig { get; set; } public AreaSetting setting { get; set; } public int access { get; set; } = 0; public string shortCode { get; set; } public string sas { get; set; } public string url { get; set; } } public record TeacherInfo { public string auth_token { get; set; } public string blob_uri { get; set; } public string blob_sas { get; set; } public List schools { get; set; } = new List(); public string defaultschool { get; set; } public string defaultschoolPeriod { get; set; } public List courses { get; set; } = new List(); public int total { get; set; } public string osblob_uri { get; set; } public string osblob_sas { get; set; } public int tsize { get; set; } public List areas { get; set; } = new List(); public Teacher teacher { get; set; } } }