ShareController.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. using Azure.Cosmos;
  2. using HTEXLib.COMM.Helpers;
  3. using Microsoft.AspNetCore.Http;
  4. using Microsoft.AspNetCore.Mvc;
  5. using Microsoft.Extensions.Options;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Linq;
  9. using System.Text;
  10. using System.Text.Json;
  11. using System.Threading.Tasks;
  12. using TEAMModelOS.Filter;
  13. using TEAMModelOS.Models;
  14. using TEAMModelOS.SDK.DI;
  15. using TEAMModelOS.SDK.Extension;
  16. using TEAMModelOS.SDK.Models;
  17. using TEAMModelOS.SDK.Models.Cosmos;
  18. using TEAMModelOS.SDK.Models.Cosmos.Common;
  19. using TEAMModelOS.Services.Common;
  20. namespace TEAMModelOS.Controllers
  21. {
  22. [ProducesResponseType(StatusCodes.Status200OK)]
  23. [ProducesResponseType(StatusCodes.Status400BadRequest)]
  24. //[Authorize(Roles = "IES5")]
  25. [Route("teacher/share")]
  26. [ApiController]
  27. public class ShareController: ControllerBase
  28. {
  29. private readonly AzureCosmosFactory _azureCosmos;
  30. private readonly SnowflakeId _snowflakeId;
  31. private readonly DingDing _dingDing;
  32. private readonly Option _option;
  33. public ShareController(AzureCosmosFactory azureCosmos, SnowflakeId snowflakeId, DingDing dingDing, IOptionsSnapshot<Option> option)
  34. {
  35. _azureCosmos = azureCosmos;
  36. _snowflakeId = snowflakeId;
  37. _dingDing = dingDing;
  38. _option = option?.Value;
  39. }
  40. /*
  41. {
  42. "school": "学校编码",
  43. "scope":"school|private",
  44. "tmdInfo":["tmdid":"id1","tmdname":"name1"],
  45. "coedit":true,
  46. "share":true,
  47. "issuer":"权限颁发者tmdid",
  48. "opt":"add/del/edit"
  49. "syllabusId":"分享的课纲章节id",
  50. "syllabusName":"章节名称",
  51. "volumeId":"册别id",
  52. "volumeName":"册别name"
  53. }
  54. */
  55. /// <summary>
  56. /// 分享及邀请共编,并设置TTL过期时间
  57. /// </summary>
  58. /// <param name="request"></param>
  59. /// <returns></returns>
  60. [ProducesDefaultResponseType]
  61. [HttpPost("to")]
  62. // [AuthToken(Roles = "Teacher")]
  63. public async Task<IActionResult> To(ShareData request) {
  64. // var (id, _, _, _) = HttpContext.GetAuthTokenInfo();
  65. try {
  66. var client = _azureCosmos.GetCosmosClient();
  67. //需要判断id== req.issuer 才能进行授权操作
  68. if (request.scope.Equals("school"))
  69. {
  70. Syllabus syllabusD = await client.GetContainer("TEAMModelOS", "School").ReadItemAsync<Syllabus>(request.syllabusId, new PartitionKey($"Syllabus-{request.volumeId}"));
  71. if (request.opt == "del")
  72. {
  73. if (syllabusD.auth.IsNotEmpty())
  74. {
  75. List<SyllabusAuth> syllabusAuths = new List<SyllabusAuth>();
  76. syllabusD.auth.ForEach(x=> {
  77. if (request.tmdInfo.Select(tmd=>tmd.tmdid).Contains(x.tmdid)) {
  78. syllabusAuths.Add(x);
  79. }
  80. }) ;
  81. syllabusAuths.ForEach(x => {
  82. syllabusD.auth.Remove(x);
  83. });
  84. await client.GetContainer("TEAMModelOS", "School").ReplaceItemAsync<Syllabus>(syllabusD, request.syllabusId, new PartitionKey($"Syllabus-{request.volumeId}"));
  85. request.tmdInfo.ForEach(async x => {
  86. await client.GetContainer("TEAMModelOS", "Teacher").DeleteItemAsync<Share>(request.syllabusId, new PartitionKey($"Share-{x.tmdid}"));
  87. });
  88. }
  89. }
  90. else if (request.opt.Equals("add") || request.opt.Equals("edit"))
  91. {
  92. (Syllabus syllabus, List<Share> shares) = DoAuth(request, syllabusD);
  93. shares.ForEach(async x=> {
  94. await client.GetContainer("TEAMModelOS", "Teacher").UpsertItemAsync<Share>(x, new PartitionKey($"Share-{x.code}"));
  95. });
  96. await client.GetContainer("TEAMModelOS", "School").UpsertItemAsync<Syllabus>(syllabus, new PartitionKey($"Syllabus-{request.volumeId}"));
  97. }
  98. }
  99. else if (request.scope.Equals("private"))
  100. {
  101. Syllabus syllabusD = await client.GetContainer("TEAMModelOS", "Teacher").ReadItemAsync<Syllabus>(request.syllabusId, new PartitionKey($"Syllabus-{request.volumeId}"));
  102. if (request.opt == "del")
  103. {
  104. if (syllabusD.auth.IsNotEmpty())
  105. {
  106. List<SyllabusAuth> syllabusAuths = new List<SyllabusAuth>();
  107. syllabusD.auth.ForEach(x => {
  108. if (request.tmdInfo.Select(tmd=>x.tmdid).Contains(x.tmdid))
  109. {
  110. syllabusAuths.Add(x);
  111. }
  112. });
  113. syllabusAuths.ForEach(x => {
  114. syllabusD.auth.Remove(x);
  115. });
  116. await client.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync<Syllabus>(syllabusD, request.syllabusId, new PartitionKey($"Syllabus-{request.volumeId}"));
  117. request.tmdInfo.ForEach(async x => {
  118. await client.GetContainer("TEAMModelOS", "Teacher").DeleteItemAsync<Share>(request.syllabusId, new PartitionKey($"Share-{x.tmdid}"));
  119. });
  120. }
  121. }
  122. else if (request.opt.Equals("add") || request.opt.Equals("edit"))
  123. {
  124. (Syllabus vlm, List<Share> shares) = DoAuth(request, syllabusD);
  125. shares.ForEach(async x => {
  126. await client.GetContainer("TEAMModelOS", "Teacher").UpsertItemAsync<Share>(x, new PartitionKey($"Share-{x.code}"));
  127. });
  128. await client.GetContainer("TEAMModelOS", "Teacher").UpsertItemAsync<Syllabus>(syllabusD, new PartitionKey($"Syllabus-{request.volumeId}"));
  129. }
  130. }
  131. return Ok(new { code=200});
  132. }
  133. catch (Exception ex ) {
  134. await _dingDing.SendBotMsg($"OS,{_option.Location},teacher/share/to\n{ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
  135. }
  136. return Ok(new { code = 500 });
  137. }
  138. private (Syllabus, List<Share>) DoAuth(ShareData request, Syllabus syllabus)
  139. {
  140. long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  141. List<Share> shares = new List<Share>();
  142. request.tmdInfo.ForEach(xmd => {
  143. var share = new Share
  144. {
  145. id = request.syllabusId,
  146. volumeId = request.volumeId,
  147. volumeName = request.volumeName,
  148. syllabusName = request.syllabusName,
  149. code = $"Share-{xmd.tmdid}",
  150. pk = "Share",
  151. ttl = -1,
  152. issuer = request.issuer,
  153. createTime = now,
  154. school = request.school,
  155. scope = request.scope,
  156. coedit = request.coedit,
  157. share = request.share
  158. };
  159. shares.Add(share);
  160. });
  161. if (syllabus.auth.IsNotEmpty())
  162. {
  163. request.tmdInfo.ForEach(xmd => {
  164. bool flag = false;
  165. int indx = 0;
  166. for (int index = 0; index < syllabus.auth.Count; index++)
  167. {
  168. if (syllabus.auth[index].tmdid == xmd.tmdid)
  169. {
  170. flag = true;
  171. indx = index;
  172. break;
  173. }
  174. }
  175. ///更新位置上的授权信息
  176. if (flag)
  177. {
  178. syllabus.auth[indx] = new SyllabusAuth
  179. {
  180. tmdid = xmd.tmdid,
  181. tmdname = xmd.tmdname,
  182. coedit = request.coedit,
  183. share = request.share,
  184. };
  185. }
  186. //新增
  187. else
  188. {
  189. syllabus.auth.Add(new SyllabusAuth
  190. {
  191. tmdid = xmd.tmdid,
  192. tmdname = xmd.tmdname,
  193. coedit = request.coedit,
  194. share = request.share,
  195. });
  196. }
  197. });
  198. }
  199. else
  200. {
  201. request.tmdInfo.ForEach(xmd => {
  202. syllabus.auth = new List<SyllabusAuth>() {
  203. new SyllabusAuth {
  204. tmdid = xmd.tmdid,
  205. tmdname = xmd.tmdname,
  206. coedit=request.coedit,
  207. share=request.share,
  208. }
  209. };
  210. });
  211. }
  212. return (syllabus, shares);
  213. }
  214. /// <summary>
  215. /// {"code":"教师编码","type":"coedit/share"}
  216. /// 教师拉取自己收到的分享及共编
  217. /// </summary>
  218. /// <param name="request"></param>
  219. /// <returns></returns>
  220. [ProducesDefaultResponseType]
  221. [HttpPost("find")]
  222. // [AuthToken(Roles = "Teacher")]
  223. public async Task<IActionResult> Find(JsonElement request)
  224. {
  225. try
  226. {
  227. List<Share> shares = new List<Share>();
  228. if (!request.TryGetProperty("code", out JsonElement code)) { return BadRequest(); }
  229. if (!request.TryGetProperty("type", out JsonElement type)) { return BadRequest(); }
  230. if (!request.TryGetProperty("id", out JsonElement id)) { return BadRequest(); }
  231. var client = _azureCosmos.GetCosmosClient();
  232. StringBuilder queryText = new StringBuilder("select value(c) from c");
  233. if (type.ValueKind.Equals(JsonValueKind.String) && type.GetString() == "coedit")
  234. {
  235. queryText.Append(" where c.coedit=true");
  236. }
  237. else if (type.ValueKind.Equals(JsonValueKind.String) && type.GetString() == "share")
  238. {
  239. queryText.Append(" where c.share=true");
  240. }
  241. else {
  242. await _dingDing.SendBotMsg($"OS,{_option.Location},teacher/share/find()\n type== coedit|share 参数必选一个", GroupNames.醍摩豆服務運維群組);
  243. return BadRequest();
  244. }
  245. if (id.ValueKind.Equals(JsonValueKind.String) && !string.IsNullOrEmpty(id.GetString())) {
  246. queryText.Append($" and c.id='{id}'");
  247. }
  248. await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher").GetItemQueryIterator<Share>(queryText: queryText.ToString(),
  249. requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Share-{code}") }))
  250. {
  251. shares.Add(item);
  252. }
  253. var sharesGp = shares.GroupBy(x => new {id= x.volumeId ,code=x.scope=="school"?x.school:x.issuer}).Select(y=>new { id=y.Key.id,code=y.Key.code,list=y.ToList()});
  254. return Ok(new { shares = sharesGp });
  255. }
  256. catch (Exception ex)
  257. {
  258. await _dingDing.SendBotMsg($"OS,{_option.Location},teacher/share/find()\n{ex.Message}{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
  259. return BadRequest();
  260. }
  261. }
  262. public record ShareView
  263. {
  264. public string scope { get; set; }
  265. // public string code { get; set; }
  266. public string school { get; set; }
  267. public string issuer { get; set; }
  268. public string volumeId { get; set; }
  269. public List<string> syllabusId { get; set; }
  270. }
  271. /*
  272. {
  273. "scope": "school/private",
  274. "school": "学校编码",
  275. "issuer": "权限颁发者",
  276. "volumeId": "册别id",
  277. "syllabusId": ["id1课纲章节节点id","id2课纲章节节点id"],
  278. }
  279. */
  280. /// <summary>
  281. /// 查看分享
  282. /// </summary>
  283. /// <param name="request"></param>
  284. /// <returns></returns>
  285. [ProducesDefaultResponseType]
  286. [HttpPost("view-share")]
  287. // [AuthToken(Roles = "Teacher")]
  288. public async Task<IActionResult> View(ShareView request)
  289. {
  290. try
  291. {
  292. List<SyllabusTreeNode> treeNodes = new List<SyllabusTreeNode>();
  293. Volume volume;
  294. var client = _azureCosmos.GetCosmosClient();
  295. string code = null;
  296. List<string> sid = new List<string>();
  297. request.syllabusId.ForEach(x => { sid.Add($"'{x}'"); });
  298. var sidSql= string.Join(",", sid);
  299. if (request.scope == "school")
  300. {
  301. code = request.school;
  302. var queryslt = $"SELECT value(c) FROM c where c.id in ({sidSql})";
  303. await foreach (var item in client.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<Syllabus>(queryText: queryslt, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Syllabus-{request.volumeId}") }))
  304. {
  305. List<SyllabusTree> trees = SyllabusService.ListToTree(item.children);
  306. SyllabusTreeNode tree = new SyllabusTreeNode() { id = item.id, scope = item.scope, trees = trees, volumeId = item.volumeId, auth = item.auth };
  307. treeNodes.Add(tree);
  308. }
  309. volume = await client.GetContainer("TEAMModelOS", "School").ReadItemAsync<Volume>(request.volumeId, new PartitionKey($"Volume-{code}"));
  310. }
  311. else if (request.scope == "private")
  312. {
  313. code = request.issuer;
  314. var queryslt = $"SELECT value(c) FROM c where c.id in ({sidSql})";
  315. await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher").GetItemQueryIterator<Syllabus>(queryText: queryslt, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Syllabus-{request.volumeId}") }))
  316. {
  317. List<SyllabusTree> trees = SyllabusService.ListToTree(item.children);
  318. SyllabusTreeNode tree = new SyllabusTreeNode() { id = item.id, scope = item.scope, trees = trees, volumeId = item.volumeId, auth = item.auth };
  319. treeNodes.Add(tree);
  320. }
  321. volume = await client.GetContainer("TEAMModelOS", "Teacher").ReadItemAsync<Volume>(request.volumeId, new PartitionKey($"Volume-{code}"));
  322. }
  323. else
  324. {
  325. return BadRequest();
  326. }
  327. return Ok(new { volume,tree= treeNodes });
  328. }
  329. catch (Exception ex) {
  330. await _dingDing.SendBotMsg($"OS,{_option.Location},teacher/share/view()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
  331. return BadRequest();
  332. }
  333. }
  334. /// <summary>
  335. ///二维码扫码方式
  336. /// </summary>
  337. /// <param name="request"></param>
  338. /// <returns></returns>
  339. [ProducesDefaultResponseType]
  340. [HttpPost("qrcode")]
  341. //[AuthToken(Roles = "Teacher")]
  342. public async Task<IActionResult> Qrcode(Favorite request)
  343. {
  344. return Ok();
  345. }
  346. }
  347. }