|
@@ -0,0 +1,340 @@
|
|
|
+using Azure.Storage.Blobs.Models;
|
|
|
+using Azure.Storage.Sas;
|
|
|
+using HTEXLib;
|
|
|
+using HTEXLib.Builders;
|
|
|
+using HTEXLib.Helpers.ShapeHelpers;
|
|
|
+using Microsoft.AspNetCore.Hosting;
|
|
|
+using Microsoft.AspNetCore.Http;
|
|
|
+using Microsoft.AspNetCore.Mvc;
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.Globalization;
|
|
|
+using System.IdentityModel.Tokens.Jwt;
|
|
|
+using System.IO;
|
|
|
+using System.Linq;
|
|
|
+using System.Net.Http;
|
|
|
+using System.Text;
|
|
|
+using System.Text.Json;
|
|
|
+using System.Threading.Tasks;
|
|
|
+using TEAMModelOS.SDK.Models;
|
|
|
+using TEAMModelOS.Models.Dto;
|
|
|
+using TEAMModelOS.Models.PowerPoint;
|
|
|
+using TEAMModelOS.SDK;
|
|
|
+using TEAMModelOS.SDK.Context.Constant;
|
|
|
+using TEAMModelOS.SDK.Context.Constant.Common;
|
|
|
+using TEAMModelOS.SDK.DI;
|
|
|
+using TEAMModelOS.SDK.Extension;
|
|
|
+using TEAMModelOS.SDK.Module.AzureBlob.Configuration;
|
|
|
+using TEAMModelOS.SDK.Module.AzureBlob.Container;
|
|
|
+using TEAMModelOS.Services;
|
|
|
+using HTEXLib.Translator;
|
|
|
+using HTEXLib.DOCX.Models;
|
|
|
+
|
|
|
+namespace TEAMModelOS.Controllers
|
|
|
+{
|
|
|
+ [Route("import")]
|
|
|
+ [ApiController]
|
|
|
+ public class ImportController : ControllerBase
|
|
|
+ {
|
|
|
+ public PPTX2HTEXTranslator _PPTX2HTEXTranslator { get; set; }
|
|
|
+ public DOXC2HTMLTranslator _DOXC2HTMLTranslator { get; set; }
|
|
|
+ public HTML2ITEMTranslator _HTML2ITEMTranslator { get; set; }
|
|
|
+ // private readonly IHtexService htexService;
|
|
|
+ private readonly AzureStorageFactory _azureStorage;
|
|
|
+ private readonly IWebHostEnvironment _webHostEnvironment;
|
|
|
+ private List<LangConfig> langConfigs { get; set; }
|
|
|
+ private readonly IHttpClientFactory _clientFactory;
|
|
|
+ public ImportController( AzureStorageFactory azureStorage, IWebHostEnvironment webHostEnvironment,
|
|
|
+ PPTX2HTEXTranslator PPTX2HTEXTranslator, IHttpClientFactory clientFactory,
|
|
|
+ DOXC2HTMLTranslator DOXC2HTMLTranslator, HTML2ITEMTranslator HTML2ITEMTranslator)
|
|
|
+ {
|
|
|
+ _HTML2ITEMTranslator = HTML2ITEMTranslator;
|
|
|
+ _DOXC2HTMLTranslator = DOXC2HTMLTranslator;
|
|
|
+ _clientFactory = clientFactory;
|
|
|
+ this._PPTX2HTEXTranslator = PPTX2HTEXTranslator;
|
|
|
+ _webHostEnvironment = webHostEnvironment;
|
|
|
+ _azureStorage = azureStorage;
|
|
|
+ string path = _webHostEnvironment.ContentRootPath + "/JsonFile/Core/LangConfig.json";
|
|
|
+ FileStream fs = new FileStream(path, System.IO.FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
|
|
+ StreamReader sr = new StreamReader(fs, System.Text.Encoding.UTF8);
|
|
|
+ String line;
|
|
|
+ StringBuilder builder = new StringBuilder();
|
|
|
+ while ((line = sr.ReadLine()) != null)
|
|
|
+ {
|
|
|
+ builder.Append(line.ToString());
|
|
|
+ }
|
|
|
+
|
|
|
+ sr.Close();
|
|
|
+ string text = builder.ToString();
|
|
|
+ langConfigs = text.ToObject<List<LangConfig>>();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// {"url":"https://***.blob.core.cn/xxx/1.pptx"}
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="request"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ [HttpPost("pptx")]
|
|
|
+ [RequestSizeLimit(102_400_000_00)] //最大10000m左右
|
|
|
+ public async Task<IActionResult> ParsePPTX(JsonElement request)
|
|
|
+ {
|
|
|
+ //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;
|
|
|
+
|
|
|
+ request.TryGetProperty("file", out JsonElement code);
|
|
|
+ string azureBlobSAS = System.Web.HttpUtility.UrlDecode(code.ToString(), Encoding.UTF8);
|
|
|
+ (string, string) a = BlobUrlString(azureBlobSAS);
|
|
|
+ string ContainerName = a.Item1;
|
|
|
+ string BlobName = a.Item2;
|
|
|
+ bool flg = IsBlobName(BlobName);
|
|
|
+ var codes = azureBlobSAS.Split("/");
|
|
|
+ var file = codes[codes.Length - 1].Split(".");
|
|
|
+ var FileName = file[0];
|
|
|
+ var ext = file[1];
|
|
|
+ if (flg)
|
|
|
+ {
|
|
|
+ BlobAuth blobAuth = _azureStorage.GetBlobSasUriRead(ContainerName, BlobName);
|
|
|
+ var response = await _clientFactory.CreateClient().GetAsync(new Uri(blobAuth.url));
|
|
|
+ response.EnsureSuccessStatusCode();
|
|
|
+ Stream stream= await response.Content.ReadAsStreamAsync();
|
|
|
+
|
|
|
+ if (ext.ToLower() == "pptx" || ext.ToLower() == "xml")
|
|
|
+ {
|
|
|
+ string index = await PPTXTranslator(ContainerName, FileName, stream);
|
|
|
+ return Ok(new { index = index });
|
|
|
+ }
|
|
|
+ else if (ext.ToLower() == "docx" || ext.ToLower() == "doc")
|
|
|
+ {
|
|
|
+ return Ok(new { index = "" });
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ return BadRequest("不支持该文件类型的解析!");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else { return BadRequest("不是正确的Blob链接!"); }
|
|
|
+ }
|
|
|
+
|
|
|
+ [HttpPost("docx")]
|
|
|
+ [RequestSizeLimit(102_400_000_00)] //最大10000m左右
|
|
|
+ public async Task<IActionResult> ParseDocx(JsonElement request)
|
|
|
+ {
|
|
|
+ return Ok();
|
|
|
+ }
|
|
|
+ private static (string, string) BlobUrlString(string sasUrl)
|
|
|
+ {
|
|
|
+ sasUrl = sasUrl.Substring(8);
|
|
|
+ string[] sasUrls = sasUrl.Split("/");
|
|
|
+ string ContainerName;
|
|
|
+ ContainerName = sasUrls[1].Clone().ToString();
|
|
|
+ string item = sasUrls[0] + "/" + sasUrls[1] + "/";
|
|
|
+ string blob = sasUrl.Replace(item, "");
|
|
|
+ return (ContainerName, blob);
|
|
|
+ }
|
|
|
+ public static bool IsBlobName(string BlobName)
|
|
|
+ {
|
|
|
+ return System.Text.RegularExpressions.Regex.IsMatch(BlobName,
|
|
|
+ @"(?!((^(con)$)|^(con)\\..*|(^(prn)$)|^(prn)\\..*|(^(aux)$)|^(aux)\\..*|(^(nul)$)|^(nul)\\..*|(^(com)[1-9]$)|^(com)[1-9]\\..*|(^(lpt)[1-9]$)|^(lpt)[1-9]\\..*)|^\\s+|.*\\s$)(^[^\\\\\\:\\<\\>\\*\\?\\\\\\""\\\\|]{1,255}$)");
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ ///
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="request"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ [HttpPost("upload-pptx")]
|
|
|
+ [RequestSizeLimit(102_400_000_00)] //最大10000m左右
|
|
|
+ public async Task<IActionResult> UploadPPTX([FromForm] IFormFile file)
|
|
|
+ {
|
|
|
+
|
|
|
+ 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 (FileType.GetExtention(file.FileName).ToLower().Equals("pptx") || FileType.GetExtention(file.FileName).ToLower().Equals("xml"))
|
|
|
+ {
|
|
|
+ string FileName = file.FileName.Split(".")[0];
|
|
|
+ Stream streamFile = file.OpenReadStream();
|
|
|
+ string index = await PPTXTranslator(id, FileName, streamFile);
|
|
|
+ return Ok(new { index = index });
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ return BadRequest("type is not pptx or xml !");
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// docUrl
|
|
|
+ /// folder
|
|
|
+ /// shaCode
|
|
|
+ ///
|
|
|
+ /// UploadWord
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="request"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ [HttpPost("upload-word")]
|
|
|
+ [RequestSizeLimit(102_400_000_00)] //最大10000m左右
|
|
|
+ public IActionResult UploadWord([FromForm] IFormFile file)
|
|
|
+ {
|
|
|
+ // ResponseBuilder responseBuilder = new ResponseBuilder();
|
|
|
+ if (!FileType.GetExtention(file.FileName).ToLower().Equals("docx"))
|
|
|
+ {
|
|
|
+ return BadRequest(new Dictionary<string, object> { {"msg", "type is not docx!" },{ "code",ResponseCode.FAILED} });
|
|
|
+ }
|
|
|
+
|
|
|
+ var doc= _DOXC2HTMLTranslator.Translate(file.OpenReadStream());
|
|
|
+ // Dictionary<string, object> model = await ImportExerciseService.UploadWord(_azureStorage, file);
|
|
|
+ return Ok(doc);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// htmlString AnalyzeHtml
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="request"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ [HttpPost("parse-html")]
|
|
|
+ public IActionResult AnalyzeHtml(JsonElement request)
|
|
|
+ {
|
|
|
+ //ResponseBuilder builder = ResponseBuilder.custom();
|
|
|
+ Dictionary<string, object> dict = new Dictionary<string, object>();
|
|
|
+ var emobj = request.EnumerateObject();
|
|
|
+ while (emobj.MoveNext())
|
|
|
+ {
|
|
|
+ dict[emobj.Current.Name] = emobj.Current.Value;
|
|
|
+ }
|
|
|
+ bool flag = dict.TryGetValue("htmlString", out object htmlString);
|
|
|
+ bool flagLang = dict.TryGetValue("lang", out object lang);
|
|
|
+ if (flag && htmlString != null && !string.IsNullOrEmpty(htmlString.ToString()))
|
|
|
+ {
|
|
|
+ LangConfig langConfig= langConfigs.Where(x => x.Lang == lang.ToString()).FirstOrDefault();
|
|
|
+ var exercises= _HTML2ITEMTranslator.Translate(htmlString.ToString(), langConfig);
|
|
|
+ return Ok(exercises);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return BadRequest();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private async Task<string> PPTXTranslator(string id, string FileName, Stream streamFile)
|
|
|
+ {
|
|
|
+ var status = await _azureStorage.GetBlobServiceClient().DelectBlobs(id, $"res/{FileName}");
|
|
|
+ string shaCode = Guid.NewGuid().ToString("N");
|
|
|
+ HTEXLib.Htex htex = _PPTX2HTEXTranslator.Translate(streamFile);
|
|
|
+ htex.name = FileName;
|
|
|
+ var slides = htex.slides;
|
|
|
+ List<Task> tasks = new List<Task>();
|
|
|
+ HTEX hTEX = new HTEX() { name = FileName, size = htex.size, thumbnail = htex.thumbnail, id = shaCode };
|
|
|
+ Dictionary<string, string> texts = new Dictionary<string, string>();
|
|
|
+ List<string> shas = new List<string>();
|
|
|
+ foreach (var slide in slides)
|
|
|
+ {
|
|
|
+ string text = JsonHelper.ToJson(slide, ignoreNullValue: false);
|
|
|
+ string sha = Guid.NewGuid().ToString("N");
|
|
|
+ texts.Add(sha, text);
|
|
|
+ shas.Add(sha);
|
|
|
+ }
|
|
|
+ Dictionary<string, string> bloburls = new Dictionary<string, string>();
|
|
|
+ foreach (var key in texts.Keys)
|
|
|
+ {
|
|
|
+ tasks.Add(_azureStorage.UploadFileByContainer(id, texts[key], "res", FileName + "/" + key + ".json", false)
|
|
|
+ .ContinueWith((Task<AzureBlobModel> blob) =>
|
|
|
+ {
|
|
|
+ bloburls.Add(key, blob.Result.BlobUrl);
|
|
|
+ })
|
|
|
+ );
|
|
|
+ }
|
|
|
+ await Task.WhenAll(tasks);
|
|
|
+ List<Sld> slds = new List<Sld>();
|
|
|
+ foreach (string sha in shas)
|
|
|
+ {
|
|
|
+ slds.Add(new Sld { type = "normal", url = System.Web.HttpUtility.UrlDecode(bloburls[sha], Encoding.UTF8), scoring = null }); ;
|
|
|
+ }
|
|
|
+ Dictionary<string, Store> dict = new Dictionary<string, Store>();
|
|
|
+ List<Task> tasksFiles = new List<Task>();
|
|
|
+ foreach (var key in htex.stores.Keys)
|
|
|
+ {
|
|
|
+ if (key.EndsWith(".wdp") || key.EndsWith(".xlsx"))
|
|
|
+ {
|
|
|
+ htex.stores.Remove(key);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ var store = htex.stores[key];
|
|
|
+ Store str = new Store() { path = key, contentType = store.contentType, isLazy = store.isLazy };
|
|
|
+ if (!store.isLazy && store.contentType != null && ContentTypeDict.extdict.TryGetValue(store.contentType, out string ext) && store.url.Contains(";base64,"))
|
|
|
+ {
|
|
|
+ string[] strs = store.url.Split(',');
|
|
|
+ Stream stream = new MemoryStream(Convert.FromBase64String(strs[1]));
|
|
|
+ var urlstrs = key.Split("/");
|
|
|
+ var name = urlstrs[urlstrs.Length - 1];
|
|
|
+ tasksFiles.Add(_azureStorage.UploadFileByContainer(id, stream, "res", FileName + "/" + name, false)
|
|
|
+ .ContinueWith((Task<AzureBlobModel> blob) =>
|
|
|
+ {
|
|
|
+ str.url = System.Web.HttpUtility.UrlDecode(blob.Result.BlobUrl, Encoding.UTF8);
|
|
|
+ })
|
|
|
+ );
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ str.url = System.Web.HttpUtility.UrlDecode(store.url, Encoding.UTF8);
|
|
|
+ }
|
|
|
+ dict.TryAdd(key, str);
|
|
|
+ }
|
|
|
+ await Task.WhenAll(tasksFiles);
|
|
|
+ hTEX.stores = dict;
|
|
|
+ hTEX.slides = slds;
|
|
|
+ var blob= await _azureStorage.UploadFileByContainer(id, JsonHelper.ToJson(hTEX, ignoreNullValue: false), "res", FileName + "/" + "index.json", false);
|
|
|
+ return System.Web.HttpUtility.UrlDecode(blob.BlobUrl, Encoding.UTF8);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public class HTEX {
|
|
|
+ public string id { get; set; }
|
|
|
+ public string version { get; set; } = "1.0.20201210";
|
|
|
+ public string name { get; set; }
|
|
|
+ public HTEXLib.HtexSize size { get; set; }
|
|
|
+ public List<Sld> slides { get; set; }
|
|
|
+ //缩略图
|
|
|
+ public string thumbnail { get; set; }
|
|
|
+ // public int page { get; set; }
|
|
|
+ public Dictionary<string, Store> stores { get; set; }
|
|
|
+ public List<string> points { get; set; }
|
|
|
+ public string periodId { get; set; }
|
|
|
+ public List<string> gradeIds { get; set; }
|
|
|
+ public string subjectId { get; set; }
|
|
|
+ public string subjectName { get; set; }
|
|
|
+ public string score { get; set; }
|
|
|
+ public string code { get; set; }
|
|
|
+ public string scope { get; set; }
|
|
|
+ public int? multipleRule { get; set; }
|
|
|
+ }
|
|
|
+ public class Sld {
|
|
|
+ /// <summary>
|
|
|
+ /// normal,普通的hte页面 single 单选题 multiple 多选题 judge 判断题 complete 填空题 subjective 问答题 compose 综合题
|
|
|
+ /// </summary>
|
|
|
+ public string type { get; set; }
|
|
|
+ /// <summary>
|
|
|
+ /// 单页PPTx htex 的解析链接或一个题目的链接
|
|
|
+ /// </summary>
|
|
|
+ public string url { get; set; }
|
|
|
+ /// <summary>
|
|
|
+ /// 题目的配分,如果为type为normal 及compose ,则 scoring=null
|
|
|
+ /// </summary>
|
|
|
+ public Scoring scoring { get; set; }
|
|
|
+ /// <summary>
|
|
|
+ /// 单页PPTx htex 的缩略图
|
|
|
+ /// </summary>
|
|
|
+ public string thumbnail { get; set; }
|
|
|
+ }
|
|
|
+
|
|
|
+ public class Scoring {
|
|
|
+ public double score { get; set; }
|
|
|
+ public List<string> ans { get; set; } = new List<string>();
|
|
|
+ }
|
|
|
+}
|