DocEdit.razor 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. @page "/docedit"
  2. @page "/docedit/{docID:int}"
  3. @using System.Reflection;
  4. @using HyperCube.Models;
  5. @using Console = HyperCube.Utils.AdvConsole;
  6. @inject NavigationManager NavigationManager;
  7. @inject IJSRuntime JsRuntime;
  8. @attribute [Authorize]
  9. @*@attribute [Authorize(Roles = "admin")]*@
  10. @inject AuthenticationStateProvider AuthenticationStateProvider
  11. @using Microsoft.AspNetCore.Identity;
  12. @inject UserManager<IdentityUser> UserManager;
  13. <p>
  14. ID транзакции: @transactionId
  15. </p>
  16. <EditForm Model="@articleModel">
  17. @*OnValidSubmit="@HandleValidSubmit"
  18. <DataAnnotationsValidator />
  19. <ValidationSummary />*@
  20. <h1>@header</h1>
  21. <br>
  22. <div style="width: 50%;">
  23. @if (docID < 1)
  24. {
  25. <p><InputFile id="inputDefault" OnChange="@HandleSelection" accept="application/pdf" /></p>
  26. //accept="application/pdf, application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document"
  27. }
  28. else
  29. {
  30. <p>Исходный документ: <a href=@FOLDER_NAME download="@articleModel.Filename" target="_top">@articleModel.Filename</a></p>
  31. }
  32. <p><InputText id="article_name" class="form-control" @bind-Value="articleModel.Name" placeholder="Наименование статьи" /></p>
  33. <p><InputDate id="date_publish" class="form-control" @bind-Value="articleModel.PublishDate" placeholder="Дата издания" /></p>
  34. <p><InputText id="author" class="form-control" @bind-Value="articleModel.Authors" placeholder="Автор" /></p>
  35. <p><InputTextArea id="keywords" class="form-control" @bind-Value="articleModel.Keywords" placeholder="Ключевые слова" /></p>
  36. <p><InputTextArea rows="5" id="annotation" class="form-control" @bind-Value="articleModel.Annotation" placeholder="Аннотация" /></p>
  37. <p><InputTextArea rows="10" id="text" class="form-control" @bind-Value="articleModel.Text" placeholder="Текст" /></p>
  38. @if (docID < 1)
  39. {
  40. <p><button class="btn btn-primary" type="submit">Загрузить</button></p>
  41. }
  42. else
  43. {
  44. <p>
  45. <InputRadioGroup @bind-Value="articleModel.Rating">
  46. Оценка:
  47. <br>
  48. @for (int i = 1; i < 6; i++)
  49. {
  50. <InputRadio Value="i" />
  51. @i
  52. <br />
  53. }
  54. </InputRadioGroup>
  55. </p>
  56. <p>
  57. <button class="btn btn-danger" type="button" @onclick="@Cancel">Отклонить</button>
  58. <button class="btn btn-primary" type="button" @onclick="@Submit">Утвердить</button>
  59. @*<button class="btn btn-primary" type="submit">Утвердить</button>*@
  60. </p>
  61. }
  62. <p>Статус: @status</p>
  63. @*<button class="btn btn-primary" @onclick="() => modal.Open()">Modal!</button>*@
  64. <Modal @ref="modal">
  65. <Title>Результат операции</Title>
  66. <Body>
  67. <p>
  68. ID транзакции: @transactionId
  69. </p>
  70. <p>
  71. Инициатор: <mark>@initiatorAcc.Name</mark> Сумма: овердофига <b>ETH</b><br>
  72. Рейтинг статьи: @articleModel.Rating<br>
  73. </p>
  74. <p>
  75. Верификатор: <mark>@currentAcc.Name</mark> Сумма: овердофига <b>ETH</b><br>
  76. Кол-во исправлений: @editsCount
  77. </p>
  78. <p>
  79. Вознаграждение системы: овердофига <b>ETH</b>.
  80. </p>
  81. </Body>
  82. <Footer>
  83. @*<button type="button" class="btn btn-primary">Save changes</button>*@
  84. <button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => modal.Close()">Закрыть</button>
  85. </Footer>
  86. </Modal>
  87. </div>
  88. </EditForm>
  89. @code {
  90. [Parameter]
  91. public int docID { get; set; }
  92. const string FOLDER_NAME = "articles_storage";
  93. const long MAX_FILE_SIZE = 5120000; //bytes
  94. string transactionId;
  95. ArticleModel articleModelClone = new();
  96. ArticleModel articleModel = new();
  97. AccountModel currentAcc = new();
  98. AccountModel initiatorAcc = new();
  99. string status;
  100. string header;
  101. string storageFolderPath;
  102. MemoryStream memoryStream;
  103. Modal modal { get; set; }
  104. int editsCount;
  105. async Task<string> Verify()
  106. {
  107. try
  108. {
  109. VerifyContract verifyContract = SmartContract.Find("Verify") as VerifyContract;
  110. if (verifyContract != null)
  111. {
  112. Console.WriteLine($"VerifyContract found");
  113. transactionId = await verifyContract.Run(articleModel);
  114. return transactionId;
  115. }
  116. else
  117. Console.WriteLine($"VerifyContract null");
  118. }
  119. catch (Exception e)
  120. {
  121. Console.WriteLine(e.Message + "stack trace" + e.StackTrace);
  122. }
  123. return "Verify failed";
  124. }
  125. protected override async Task OnInitializedAsync()
  126. {
  127. currentAcc = await GetCurrentAcc();
  128. string path = AppDomain.CurrentDomain.BaseDirectory;
  129. storageFolderPath = (Path.Combine(path, FOLDER_NAME));
  130. if (docID > 0)
  131. {
  132. header = "Проверка материала";
  133. MySQLConnector dbCon = MySQLConnector.Instance();
  134. string stringSQL = $"SELECT articles.id, filename, article_name, authors, date_publish, annotation, keywords, action_type, rating " +
  135. $"FROM articles " +
  136. $"JOIN actions_history ON actions_history.article_id = articles.id " +
  137. $"WHERE articles.id={docID} " +
  138. $"ORDER BY actions_history.id DESC LiMIT 1";
  139. articleModelClone = await dbCon.SQLSelectArticle(stringSQL);
  140. articleModel = (ArticleModel)articleModelClone.Clone();
  141. string initiator = await articleModel.GetInitiatorUUID();
  142. initiatorAcc = AccountModel.Find(initiator);
  143. status = $"Article ID={docID} loaded, status: {articleModel.Status}, initiator: {initiatorAcc.Name}";
  144. }
  145. else
  146. header = "Загрузка материала";
  147. InitializeAccount();
  148. //int count = await articleModel.GetEditsCount();
  149. //int countbyid = await articleModel.GetEditsCount(currentAcc.UUID);
  150. //header += $", uuid:{currentAcc.UUID}, name: {currentAcc.Name}, edits count:{count}, count by accid: {countbyid}";
  151. }
  152. private async void Submit()
  153. {
  154. MySQLConnector dbCon = MySQLConnector.Instance();
  155. long id = 0;
  156. string stringSQL;
  157. if (docID > 0)
  158. {
  159. id = docID;
  160. stringSQL = $"UPDATE articles " +
  161. $"SET filename='{articleModel.Filename}', article_name='{articleModel.Name}', authors='{articleModel.Authors}', " +
  162. $"date_publish='{articleModel.PublishDate.ToString("yyyy-MM-dd")}', annotation='{articleModel.Annotation}', " +
  163. $"keywords='{articleModel.Keywords}', rating={articleModel.Rating} " +
  164. $"WHERE id={docID}";
  165. dbCon.SQLInsert(stringSQL);
  166. }
  167. else
  168. {
  169. stringSQL = $"INSERT INTO articles (filename, article_name, authors, date_publish, annotation, keywords) " +
  170. $"VALUES ('{articleModel.Filename}', '{articleModel.Name}', '{articleModel.Authors}', '{articleModel.PublishDate.ToString("yyyy-MM-dd")}'," +
  171. $"'{articleModel.Annotation}', '{articleModel.Keywords}')";
  172. id = dbCon.SQLInsert(stringSQL);
  173. }
  174. ///temp
  175. int action_type = docID > 0 ? 2 : 1;
  176. stringSQL = $"INSERT INTO actions_history (article_id, action_type, acc_id) " +
  177. $"VALUES ('{id}', '{action_type}', '{currentAcc.UUID}')";
  178. dbCon.SQLInsert(stringSQL);
  179. Dictionary<string, PropertyInfo> propDict = Compare.SimpleCompare<ArticleModel>(articleModel, articleModelClone);
  180. foreach (KeyValuePair<string, PropertyInfo> prop in propDict)
  181. {
  182. //Console.WriteLine($"property name: {prop.Key}, value: {prop.Value.GetValue(articleModel, null)}");
  183. stringSQL = $"INSERT INTO articles_edit_log (article_id, acc_id, field_name, field_prevvalue, field_newvalue) " +
  184. $"VALUES ('{id}', '{currentAcc.UUID}', '{prop.Key}', '{prop.Value.GetValue(articleModelClone, null)}', '{prop.Value.GetValue(articleModel, null)}')";
  185. dbCon.SQLInsert(stringSQL);
  186. }
  187. dbCon.Close();
  188. if (docID > 0)
  189. {
  190. status = propDict.Count > 0 ? "All changes saved, article has veryfied." : "Article verifyed without any changes.";
  191. transactionId = await Verify();
  192. Console.WriteLine("transactionId found " + transactionId);
  193. ///tmp
  194. editsCount = await articleModel.GetEditsCount(currentAcc.UUID);
  195. modal.Open();
  196. }
  197. else
  198. {
  199. string fullpath = Path.Combine(storageFolderPath, $"{id}_{articleModel.Filename}");
  200. Directory.CreateDirectory(storageFolderPath);
  201. FileStream fs = new(fullpath, FileMode.Create, FileAccess.Write);
  202. memoryStream.Position = 0;
  203. await memoryStream.CopyToAsync(fs);
  204. Console.WriteLine($"User has saved new article data, {id}_{articleModel.Filename}, memory size:{memoryStream.Length}b, file size: {fs.Length}b");
  205. memoryStream.Close();
  206. fs.Close();
  207. status = "New article data saved.";
  208. bool confirmed = await JsRuntime.InvokeAsync<bool>("confirm", "Хотите загрузить еще статью?");
  209. if (confirmed)
  210. NavigationManager.NavigateTo("docedit", true);
  211. else
  212. NavigationManager.NavigateTo("");
  213. }
  214. }
  215. //private async void HandleValidSubmit()
  216. //{
  217. // MySQLConnector dbCon = MySQLConnector.Instance();
  218. // long id = 0;
  219. // string stringSQL;
  220. // if (docID > 0)
  221. // {
  222. // id = docID;
  223. // stringSQL = $"UPDATE articles " +
  224. // $"SET filename='{articleModel.Filename}', article_name='{articleModel.Name}', authors='{articleModel.Authors}', " +
  225. // $"date_publish='{articleModel.PublishDate.ToString("yyyy-MM-dd")}', annotation='{articleModel.Annotation}', " +
  226. // $"keywords='{articleModel.Keywords}', rating={articleModel.Rating} " +
  227. // $"WHERE id={docID}";
  228. // dbCon.SQLInsert(stringSQL);
  229. // }
  230. // else
  231. // {
  232. // stringSQL = $"INSERT INTO articles (filename, article_name, authors, date_publish, annotation, keywords) " +
  233. // $"VALUES ('{articleModel.Filename}', '{articleModel.Name}', '{articleModel.Authors}', '{articleModel.PublishDate.ToString("yyyy-MM-dd")}'," +
  234. // $"'{articleModel.Annotation}', '{articleModel.Keywords}')";
  235. // id = dbCon.SQLInsert(stringSQL);
  236. // }
  237. // ///temp
  238. // int action_type = docID > 0 ? 2 : 1;
  239. // stringSQL = $"INSERT INTO actions_history (article_id, action_type, acc_id) " +
  240. // $"VALUES ('{id}', '{action_type}', '{currentAcc.UUID}')";
  241. // dbCon.SQLInsert(stringSQL);
  242. // Dictionary<string, PropertyInfo> propDict = Compare.SimpleCompare<ArticleModel>(articleModel, articleModelClone);
  243. // foreach (KeyValuePair<string, PropertyInfo> prop in propDict)
  244. // {
  245. // //Console.WriteLine($"property name: {prop.Key}, value: {prop.Value.GetValue(articleModel, null)}");
  246. // stringSQL = $"INSERT INTO articles_edit_log (article_id, acc_id, field_name, field_prevvalue, field_newvalue) " +
  247. // $"VALUES ('{id}', '{currentAcc.UUID}', '{prop.Key}', '{prop.Value.GetValue(articleModelClone, null)}', '{prop.Value.GetValue(articleModel, null)}')";
  248. // dbCon.SQLInsert(stringSQL);
  249. // }
  250. // dbCon.Close();
  251. // if (docID > 0)
  252. // {
  253. // status = propDict.Count > 0 ? "All changes saved, article has veryfied." : "Article verifyed without any changes.";
  254. // transactionId = await Verify();
  255. // Console.WriteLine("transactionId found " + transactionId);
  256. // ///tmp
  257. // editsCount = await articleModel.GetEditsCount(currentAcc.UUID);
  258. // modal.Open();
  259. // }
  260. // else
  261. // {
  262. // string fullpath = Path.Combine(storageFolderPath, $"{id}_{articleModel.Filename}");
  263. // Directory.CreateDirectory(storageFolderPath);
  264. // FileStream fs = new(fullpath, FileMode.Create, FileAccess.Write);
  265. // memoryStream.Position = 0;
  266. // await memoryStream.CopyToAsync(fs);
  267. // Console.WriteLine($"User has saved new article data, {id}_{articleModel.Filename}, memory size:{memoryStream.Length}b, file size: {fs.Length}b");
  268. // memoryStream.Close();
  269. // fs.Close();
  270. // status = "New article data saved.";
  271. // bool confirmed = await JsRuntime.InvokeAsync<bool>("confirm", "Хотите загрузить еще статью?");
  272. // if (confirmed)
  273. // NavigationManager.NavigateTo("docedit", true);
  274. // else
  275. // NavigationManager.NavigateTo("");
  276. // }
  277. //}
  278. private async Task HandleSelection(InputFileChangeEventArgs e)
  279. {
  280. IBrowserFile file = e.File;
  281. if (file != null)
  282. {
  283. Stream stream = file.OpenReadStream(MAX_FILE_SIZE);
  284. memoryStream = new();
  285. await stream.CopyToAsync(memoryStream);
  286. status = $"Finished loading {memoryStream.Length} bytes from {file.Name}";
  287. DocParse docParse = new DocParse();
  288. articleModelClone = DocParse.ReadPDF(memoryStream);
  289. articleModelClone.Filename = file.Name;
  290. articleModel = (ArticleModel)articleModelClone.Clone();
  291. }
  292. }
  293. private async void Cancel()
  294. {
  295. bool confirmed = await JsRuntime.InvokeAsync<bool>("confirm", "Вы уверены, что хотите отклонить статью?");
  296. if (confirmed)
  297. {
  298. ///какая-то логика отмены...
  299. NavigationManager.NavigateTo("");
  300. }
  301. }
  302. public async void InitializeAccount()
  303. {
  304. AccountModel.Current = await GetCurrentAcc();
  305. Console.WriteLine("InitializeAccount in DocEdit " + AccountModel.Current.Name);
  306. }
  307. private async Task<AccountModel> GetCurrentAcc()
  308. {
  309. AccountModel account = new();
  310. var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
  311. var user = authState.User;
  312. if (user.Identity.IsAuthenticated)
  313. {
  314. var currentUser = await UserManager.GetUserAsync(user);
  315. account.UUID = currentUser.Id;
  316. //account.Name = currentUser.UserName;
  317. //account.Email = currentUser.Email;
  318. var acc = AccountModel.Find(account.UUID);
  319. if (acc != null)
  320. account = acc;
  321. ///tmp
  322. account.AccRole = Role.User;
  323. return account;
  324. }
  325. return null;
  326. }
  327. }