DocEdit.razor 12 KB

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