DocEdit.razor.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. using Microsoft.AspNetCore.Components;
  2. using Microsoft.AspNetCore.Components.Authorization;
  3. using Microsoft.AspNetCore.Components.Forms;
  4. using Microsoft.AspNetCore.Identity;
  5. using Microsoft.JSInterop;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.ComponentModel.DataAnnotations;
  9. using System.IO;
  10. using System.Reflection;
  11. using System.Threading.Tasks;
  12. using System.Linq;
  13. using System.Net;
  14. using System.Security.Cryptography;
  15. using HyperCube.Models;
  16. using Console = HyperCube.Utils.AdvConsole;
  17. namespace HyperCube.Pages
  18. {
  19. public partial class DocEdit : ComponentBase
  20. {
  21. [Parameter]
  22. public int DocID { get; set; }
  23. [Inject]
  24. public NavigationManager NavigationManager { get; set; }
  25. [Inject]
  26. public IJSRuntime JsRuntime { get; set; }
  27. [Inject]
  28. public AuthenticationStateProvider AuthenticationStateProvider { get; set; }
  29. [Inject]
  30. public UserManager<IdentityUser> UserManager { get; set; }
  31. const string FOLDER_NAME = "articles_storage";
  32. const long MAX_FILE_SIZE = 5120000; //bytes
  33. string transactionId;
  34. ArticleModel articleClone = new();
  35. ArticleModel article = new();
  36. AccountModel currentAcc = new();
  37. AccountModel initiatorAcc = new();
  38. string status;
  39. string header;
  40. string storageFolderPath;
  41. MemoryStream memoryStream;
  42. ModalInfo modalInfo_error { get; set; }
  43. ModalInfo modalInfo_transac { get; set; }
  44. ModalLoading modalLoading { get; set; }
  45. string fullName { get { return FOLDER_NAME + "/" + article.FilenameReal; } }
  46. int editsCount;
  47. bool IsSubmitDisabled = false;
  48. protected override async Task OnInitializedAsync()
  49. {
  50. currentAcc = await GetCurrentAcc();
  51. string path = AppDomain.CurrentDomain.BaseDirectory+@"wwwroot";
  52. storageFolderPath = (Path.Combine(path, FOLDER_NAME));
  53. Console.WriteLine("docedit OnInitializedAsync storageFolderPath2 " + storageFolderPath);
  54. if (DocID > 0)
  55. {
  56. header = "Проверка материала";
  57. MySQLConnector dbCon = MySQLConnector.Instance();
  58. articleClone = await dbCon.SQLSelectArticle(DocID);
  59. article = (ArticleModel)articleClone.Clone();
  60. string initiator = await article.GetInitiatorUUID(ArticleStatus.Saved);
  61. initiatorAcc = AccountModel.Find(initiator);
  62. status = $"Article ID={DocID} loaded, status: {article.Status}, initiator: {initiatorAcc.Name}";
  63. }
  64. else
  65. header = "Загрузка материала";
  66. //await InitializeAccount();
  67. //int count = await articleModel.GetEditsCount();
  68. //int countbyid = await articleModel.GetEditsCount(currentAcc.UUID);
  69. //header += $", uuid:{currentAcc.UUID}, name: {currentAcc.Name}, edits count:{count}, count by accid: {countbyid}";
  70. }
  71. public async Task<string> NewProjectSmopp(long articleId)
  72. {
  73. WebRequest wrGETURL;
  74. wrGETURL = WebRequest.Create("http://dev.prmsys.net/makeproject.php?pt=232&aid="+ articleId);
  75. var response = await wrGETURL.GetResponseAsync();
  76. Stream dataStream = response.GetResponseStream();
  77. StreamReader reader = new(dataStream);
  78. return reader.ReadToEnd();
  79. }
  80. private async Task HandleSubmit()
  81. {
  82. Console.WriteLine($"HandleSubmit, docID: {DocID}.");
  83. modalLoading.Open();
  84. /// form validation
  85. List<string> errorFields = ValidateForm<ArticleModel>(article);
  86. if (errorFields.Count > 0)
  87. {
  88. modalLoading.Close();
  89. string invalid_fields = string.Join(", ", errorFields);
  90. modalInfo_error.Open($"Не заполнены поля: {invalid_fields}");
  91. Console.WriteLine($"HandleSubmit. Required fields: '{invalid_fields}' is not filled.");
  92. return;
  93. }
  94. /// all is fine, continue
  95. MySQLConnector dbCon = MySQLConnector.Instance();
  96. long id;
  97. string stringSQL;
  98. if (DocID > 0)
  99. {
  100. id = DocID;
  101. stringSQL = $"UPDATE articles " +
  102. $"SET filename='{article.Filename}', article_name='{article.Name}', authors='{article.Authors}', " +
  103. $"date_publish='{article.PublishDate:yyyy-MM-dd}', annotation='{article.Annotation}', " +
  104. $"keywords='{article.Keywords}', rating={article.Rating}, file_hash='{article.HashSum}' " +
  105. $"WHERE id={DocID}";
  106. await dbCon.SQLInsert(stringSQL);
  107. }
  108. else
  109. {
  110. stringSQL = $"INSERT INTO articles (filename, article_name, authors, date_publish, annotation, keywords, file_hash) " +
  111. $"VALUES ('{article.Filename}', '{article.Name}', '{article.Authors}', '{article.PublishDate:yyyy-MM-dd}'," +
  112. $"'{article.Annotation}', '{article.Keywords}', '{article.HashSum}')";
  113. id = await dbCon.SQLInsert(stringSQL);
  114. NewProjectSmopp(id);
  115. }
  116. /// tmp
  117. int action_type = DocID > 0 ? 2 : 1;
  118. stringSQL = $"INSERT INTO actions_history (article_id, action_type, acc_id) " +
  119. $"VALUES ('{id}', '{action_type}', '{currentAcc.UUID}')";
  120. await dbCon.SQLInsert(stringSQL);
  121. Dictionary<string, PropertyInfo> propDict = Compare.SimpleCompare<ArticleModel>(article, articleClone);
  122. foreach (KeyValuePair<string, PropertyInfo> prop in propDict)
  123. {
  124. //Console.WriteLine($"property name: {prop.Key}, value: {prop.Value.GetValue(articleModel, null)}");
  125. stringSQL = $"INSERT INTO articles_edit_log (article_id, acc_id, field_name, field_prevvalue, field_newvalue) " +
  126. $"VALUES ('{id}', '{currentAcc.UUID}', '{prop.Key}', '{prop.Value.GetValue(articleClone, null)}', '{prop.Value.GetValue(article, null)}')";
  127. await dbCon.SQLInsert(stringSQL);
  128. }
  129. //dbCon.Close();
  130. if (DocID > 0)
  131. {
  132. status = propDict.Count > 0 ? "All changes saved, article has veryfied." : "Article verifyed without any changes.";
  133. //transactionId = await Verify();
  134. Console.WriteLine("transactionId found " + transactionId);
  135. ///tmp
  136. editsCount = await article.GetEditsCount(currentAcc.UUID);
  137. modalInfo_transac.Open("");
  138. }
  139. else
  140. {
  141. string fullpath = Path.Combine(storageFolderPath, $"{id}_{article.Filename}");
  142. Directory.CreateDirectory(storageFolderPath);
  143. FileStream fs = new(fullpath, FileMode.Create, FileAccess.Write);
  144. memoryStream.Position = 0;
  145. await memoryStream.CopyToAsync(fs);
  146. Console.WriteLine($"User has saved new article data, {id}_{article.Filename}, memory size:{memoryStream.Length}b, file size: {fs.Length}b");
  147. memoryStream.Close();
  148. fs.Close();
  149. status = "New article data saved.";
  150. bool confirmed = await JsRuntime.InvokeAsync<bool>("confirm", "Хотите загрузить еще статью?");
  151. if (confirmed)
  152. NavigationManager.NavigateTo("docedit", true);
  153. else
  154. NavigationManager.NavigateTo("");
  155. }
  156. /// reloading articles
  157. await AppData.LoadArticles();
  158. }
  159. private async Task HandleSelection(InputFileChangeEventArgs e)
  160. {
  161. modalLoading.Open();
  162. IBrowserFile file = e.File;
  163. if (file != null)
  164. {
  165. Stream stream = file.OpenReadStream(MAX_FILE_SIZE);
  166. memoryStream = new();
  167. await stream.CopyToAsync(memoryStream);
  168. status = $"Finished loading {memoryStream.Length} bytes from {file.Name}";
  169. Console.WriteLine(status);
  170. /// calculating hash
  171. string hash = await CalculateHashSum(memoryStream);
  172. Console.WriteLine($"Hash: {hash}");
  173. /// checking hash
  174. MySQLConnector dbCon = MySQLConnector.Instance();
  175. string stringSQL;
  176. stringSQL = $"SELECT COUNT(*) FROM articles WHERE file_hash='{hash}'";
  177. int count = await dbCon.SQLSelectCount(stringSQL);
  178. //Console.WriteLine($"File duplicate check, founded files: {count}");
  179. if (count < 1)
  180. {
  181. //articleClone = DocParse.GetBaseProperties(memoryStream);
  182. articleClone = DocParse.GetBaseProperties("");
  183. articleClone.Filename = file.Name;
  184. articleClone.HashSum = hash;
  185. article = (ArticleModel)articleClone.Clone();
  186. IsSubmitDisabled = false;
  187. }
  188. else
  189. {
  190. status = $"File duplicate founded, hash: {hash}.";
  191. Console.WriteLine(status);
  192. IsSubmitDisabled = true;
  193. memoryStream.Close();
  194. stream.Close();
  195. modalInfo_error.Open("Загрузка не удалась, такой документ уже есть в системе.");
  196. }
  197. }
  198. modalLoading.Close();
  199. }
  200. private async Task Cancel()
  201. {
  202. bool confirmed = await JsRuntime.InvokeAsync<bool>("confirm", "Вы уверены, что хотите отклонить статью?");
  203. if (confirmed)
  204. {
  205. ///какая-то логика отмены...
  206. NavigationManager.NavigateTo("");
  207. }
  208. }
  209. //public async Task InitializeAccount()
  210. //{
  211. // AccountModel.Current = await GetCurrentAcc();
  212. // Console.WriteLine("InitializeAccount in DocEdit " + AccountModel.Current.Name);
  213. //}
  214. private async Task<AccountModel> GetCurrentAcc()
  215. {
  216. AccountModel account = new();
  217. var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
  218. var user = authState.User;
  219. if (user.Identity.IsAuthenticated)
  220. {
  221. var currentUser = await UserManager.GetUserAsync(user);
  222. account.UUID = currentUser.Id;
  223. //account.Name = currentUser.UserName;
  224. //account.Email = currentUser.Email;
  225. var acc = AccountModel.Find(account.UUID);
  226. if (acc != null)
  227. account = acc;
  228. ///tmp
  229. //account.AccRole = Role.User;
  230. return account;
  231. }
  232. return null;
  233. }
  234. private async Task<string> CalculateHashSum(MemoryStream ms)
  235. {
  236. MD5CryptoServiceProvider md5Provider = new();
  237. ms.Position = 0;
  238. byte[] hash = await md5Provider.ComputeHashAsync(ms);
  239. return Convert.ToBase64String(hash);
  240. }
  241. private List<string> ValidateForm<T>(T obj)
  242. {
  243. var props = typeof(T).GetProperties().Where(pi => Attribute.IsDefined(pi, typeof(RequiredAttribute)));
  244. List<string> result = new();
  245. foreach (var prop in props)
  246. {
  247. var val = prop.GetValue(obj, null);
  248. if (val == null || val?.ToString().Length == 0)
  249. result.Add(prop.Name);
  250. //Console.WriteLine($"Required field '{prop.Name}' is not filled.");
  251. }
  252. return result;
  253. }
  254. }
  255. }