Desktop.razor.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. using HyperCube.Models;
  2. using Microsoft.AspNetCore.Components;
  3. using Microsoft.AspNetCore.Components.Authorization;
  4. using Microsoft.AspNetCore.Components.Forms;
  5. using Microsoft.AspNetCore.Identity;
  6. using Microsoft.JSInterop;
  7. using Pullenti.Unitext;
  8. using System;
  9. using System.Collections.Generic;
  10. using System.ComponentModel.DataAnnotations;
  11. using System.IO;
  12. using System.Linq;
  13. using System.Reflection;
  14. using System.Security.Cryptography;
  15. using System.Text;
  16. using System.Threading.Tasks;
  17. using System.Xml;
  18. using Console = HyperCube.Utils.AdvConsole;
  19. namespace HyperCube.Pages
  20. {
  21. public partial class Desktop : ComponentBase
  22. {
  23. [Parameter]
  24. public int DocID { get; set; }
  25. [Inject]
  26. NavigationManager NavigationManager { get; set; }
  27. [Inject]
  28. AuthenticationStateProvider AuthenticationStateProvider { get; set; }
  29. [Inject]
  30. UserManager<IdentityUser> UserManager { get; set; }
  31. [Inject]
  32. AppData AppData { get; set; }
  33. const string STORAGE_FOLDER_NAME = "articles_storage";
  34. const long MAX_FILE_SIZE = 5120000; //bytes
  35. const string ACTIVE_BUTTON_CLASS = "btn_white tab-button active";
  36. const string ACTIVE_TAB_CLASS = "second-block__form visible";
  37. const string BUTTON_CLASS = "btn_white tab-button";
  38. const string TAB_CLASS = "second-block__form";
  39. string _uploadButtonClass = ACTIVE_BUTTON_CLASS;
  40. string _uploadTabClass = ACTIVE_TAB_CLASS;
  41. string _verifyButtonClass = BUTTON_CLASS;
  42. string _verifyTabClass = TAB_CLASS;
  43. string _otherButtonClass = BUTTON_CLASS;
  44. string _otherTabClass = TAB_CLASS;
  45. int _counter = 1;
  46. string _event = "";
  47. string _status;
  48. //string _header;
  49. //string _storageFolderPath;
  50. MemoryStream _memoryStream;
  51. ModalInfo _modalInfo_error { get; set; }
  52. ModalLoading _modalLoading { get; set; }
  53. ArticleModel _articleClone;
  54. ArticleModel _article;
  55. ReportModel _report = new();
  56. UnitextDocument _document;
  57. AccountModel _currentAccount;
  58. protected override async Task OnInitializedAsync()
  59. {
  60. ///tmp
  61. await AppData.LoadArticles();
  62. _article = AppData.CurrentArticle ?? (new());
  63. _articleClone = AppData.CurrentArticleClone ?? (new());
  64. _currentAccount = (AppData.CurrentAccount != null) ? AppData.CurrentAccount : await GetCurrentAcc();
  65. Console.WriteLine($"Desktop OnInitializedAsync, CurrentAccount: {_currentAccount.Name}");
  66. }
  67. protected override void OnAfterRender(bool firstRender) => _counter = 1;
  68. void SwitchDesktopTab(int tabIndex)
  69. {
  70. switch(tabIndex)
  71. {
  72. case 0:
  73. _uploadButtonClass = ACTIVE_BUTTON_CLASS;
  74. _uploadTabClass = ACTIVE_TAB_CLASS;
  75. _verifyButtonClass = BUTTON_CLASS;
  76. _verifyTabClass = TAB_CLASS;
  77. _otherButtonClass = BUTTON_CLASS;
  78. _otherTabClass = TAB_CLASS;
  79. break;
  80. case 1:
  81. _uploadButtonClass = BUTTON_CLASS;
  82. _uploadTabClass = TAB_CLASS;
  83. _verifyButtonClass = ACTIVE_BUTTON_CLASS;
  84. _verifyTabClass = ACTIVE_TAB_CLASS;
  85. _otherButtonClass = BUTTON_CLASS;
  86. _otherTabClass = TAB_CLASS;
  87. break;
  88. case 2:
  89. _uploadButtonClass = BUTTON_CLASS;
  90. _uploadTabClass = TAB_CLASS;
  91. _verifyButtonClass = BUTTON_CLASS;
  92. _verifyTabClass = TAB_CLASS;
  93. _otherButtonClass = ACTIVE_BUTTON_CLASS;
  94. _otherTabClass = ACTIVE_TAB_CLASS;
  95. break;
  96. }
  97. }
  98. async Task HandleUpload(InputFileChangeEventArgs e)
  99. {
  100. _modalLoading.Open();
  101. IBrowserFile file = e.File;
  102. if (file != null)
  103. {
  104. Stream stream = file.OpenReadStream(MAX_FILE_SIZE);
  105. _memoryStream = new();
  106. await stream.CopyToAsync(_memoryStream);
  107. _status = $"Finished loading {_memoryStream.Length} bytes from {file.Name}";
  108. Console.WriteLine(_status);
  109. /// calculating hash
  110. string hash = await CalculateHashSum(_memoryStream);
  111. Console.WriteLine($"Hash: {hash}");
  112. /// checking hash
  113. MySQLConnector dbCon = MySQLConnector.Instance();
  114. string stringSQL;
  115. stringSQL = $"SELECT COUNT(*) FROM articles WHERE file_hash='{hash}'";
  116. int count = await dbCon.SQLSelectCount(stringSQL);
  117. if (count < 1)
  118. {
  119. _report = new();
  120. _report.FileName = file.Name;
  121. _report.FileSize = _memoryStream.Length.ToString();
  122. _memoryStream.Position = 0;
  123. byte[] content = _memoryStream.ToArray();
  124. _document = UnitextService.CreateDocument(null, content, null);
  125. if (_document.ErrorMessage != null)
  126. {
  127. // скорее всего, этот формат не поддерживается на данный момент
  128. Console.WriteLine($"error, sorry: {_document.ErrorMessage}");
  129. _memoryStream.Close();
  130. stream.Close();
  131. _modalLoading.Close();
  132. _modalInfo_error.Open("Не удается прочитать документ, формат не поддерживается или файл поврежден.");
  133. return;
  134. }
  135. // восстанавливаем имя исходного файла, извлечённого из ресурсов
  136. _document.SourceFileName = file.Name;
  137. for (int i = file.Name.Length - 7; i > 0; i--)
  138. {
  139. if (file.Name[i] == '.')
  140. {
  141. _document.SourceFileName = file.Name.Substring(i + 1);
  142. break;
  143. }
  144. }
  145. //// записываем результат в XML
  146. //using (FileStream fs = new(doc.SourceFileName + ".xml", FileMode.Create, FileAccess.Write))
  147. //{
  148. // XmlWriterSettings xmlParams = new();
  149. // xmlParams.Encoding = Encoding.UTF8;
  150. // xmlParams.Indent = true;
  151. // xmlParams.IndentChars = " ";
  152. // using (XmlWriter xml = XmlWriter.Create(fs, xmlParams))
  153. // {
  154. // xml.WriteStartDocument();
  155. // doc.GetXml(xml);
  156. // xml.WriteEndDocument();
  157. // }
  158. //}
  159. //Console.WriteLine("XML write done");
  160. // получаем плоский текст
  161. string plainText = _document.GetPlaintextString(null);
  162. if (plainText == null)
  163. plainText = "Текст не выделен";
  164. _articleClone = DocParse.GetBaseProperties(plainText);
  165. _articleClone.Filename = file.Name;
  166. _articleClone.HashSum = hash;
  167. _article = (ArticleModel)_articleClone.Clone();
  168. ///tmp
  169. AppData.CurrentArticle = _article;
  170. Console.WriteLine($"Initializing SDK Pullenti ver {Pullenti.Sdk.Version} ({Pullenti.Sdk.VersionDate})... ");
  171. Pullenti.Sdk.InitializeAll();
  172. //Console.WriteLine($"OK (by ... ms), version {Pullenti.Ner.ProcessorService.Version}");
  173. List<string> npt_tokens = new();
  174. // запускаем обработку на пустом процессоре (без анализаторов NER)
  175. Pullenti.Ner.AnalysisResult are = Pullenti.Ner.ProcessorService.EmptyProcessor.Process(new Pullenti.Ner.SourceOfAnalysis(plainText), null, null);
  176. //System.Console.Write("Noun groups: ");
  177. // перебираем токены
  178. for (Pullenti.Ner.Token t = are.FirstToken; t != null; t = t.Next)
  179. {
  180. // выделяем именную группу с текущего токена
  181. Pullenti.Ner.Core.NounPhraseToken npt = Pullenti.Ner.Core.NounPhraseHelper.TryParse(t, Pullenti.Ner.Core.NounPhraseParseAttr.No, 0, null);
  182. // не получилось
  183. if (npt == null)
  184. continue;
  185. // получилось, выводим в нормализованном виде
  186. //System.Console.Write($"[{npt.GetSourceText()}=>{npt.GetNormalCaseText(null, Pullenti.Morph.MorphNumber.Singular, Pullenti.Morph.MorphGender.Undefined, false)}] ");
  187. _report.NounGroups += $"[{npt.GetSourceText()}=>{npt.GetNormalCaseText(null, Pullenti.Morph.MorphNumber.Singular, Pullenti.Morph.MorphGender.Undefined, false)}] ";
  188. npt_tokens.Add(npt.GetNormalCaseText(null, Pullenti.Morph.MorphNumber.Singular, Pullenti.Morph.MorphGender.Undefined, false));
  189. // указатель на последний токен именной группы
  190. t = npt.EndToken;
  191. }
  192. using (Pullenti.Ner.Processor proc = Pullenti.Ner.ProcessorService.CreateProcessor())
  193. {
  194. // анализируем текст
  195. Pullenti.Ner.AnalysisResult ar = proc.Process(new Pullenti.Ner.SourceOfAnalysis(plainText), null, null);
  196. // результирующие сущности
  197. //Console.WriteLine("\r\n==========================================\r\nEntities: ");
  198. foreach (Pullenti.Ner.Referent en in ar.Entities)
  199. {
  200. //Console.WriteLine($"{en.TypeName}: {en}");
  201. _report.Entities += $"{en.TypeName}: {en}\r\n";
  202. foreach (Pullenti.Ner.Slot s in en.Slots)
  203. {
  204. //Console.WriteLine($" {s.TypeName}: {s.Value}");
  205. _report.Entities += $" {s.TypeName}: {s.Value}<br>";
  206. }
  207. }
  208. // пример выделения именных групп
  209. //Console.WriteLine("\r\n==========================================\r\nNoun groups: ");
  210. for (Pullenti.Ner.Token t = ar.FirstToken; t != null; t = t.Next)
  211. {
  212. // токены с сущностями игнорируем
  213. if (t.GetReferent() != null)
  214. continue;
  215. // пробуем создать именную группу
  216. Pullenti.Ner.Core.NounPhraseToken npt = Pullenti.Ner.Core.NounPhraseHelper.TryParse(t, Pullenti.Ner.Core.NounPhraseParseAttr.AdjectiveCanBeLast, 0, null);
  217. // не получилось
  218. if (npt == null)
  219. continue;
  220. //Console.WriteLine(npt.ToString());
  221. _report.EntitiesNounGroups += $"{npt}<br>";
  222. // указатель перемещаем на последний токен группы
  223. t = npt.EndToken;
  224. }
  225. }
  226. using (Pullenti.Ner.Processor proc = Pullenti.Ner.ProcessorService.CreateSpecificProcessor(Pullenti.Ner.Keyword.KeywordAnalyzer.ANALYZER_NAME))
  227. {
  228. Pullenti.Ner.AnalysisResult ar = proc.Process(new Pullenti.Ner.SourceOfAnalysis(plainText), null, null);
  229. //Console.WriteLine("\r\n==========================================\r\nKeywords1: ");
  230. foreach (Pullenti.Ner.Referent en in ar.Entities)
  231. {
  232. if (en is Pullenti.Ner.Keyword.KeywordReferent)
  233. //Console.WriteLine(en.ToString());
  234. _report.Keywords1 += $"{en}<br>";
  235. }
  236. //Console.WriteLine("\r\n==========================================\r\nKeywords2: ");
  237. for (Pullenti.Ner.Token t = ar.FirstToken; t != null; t = t.Next)
  238. {
  239. if (t is Pullenti.Ner.ReferentToken)
  240. {
  241. Pullenti.Ner.Keyword.KeywordReferent kw = t.GetReferent() as Pullenti.Ner.Keyword.KeywordReferent;
  242. if (kw == null)
  243. continue;
  244. string kwstr = Pullenti.Ner.Core.MiscHelper.GetTextValueOfMetaToken(t as Pullenti.Ner.ReferentToken, Pullenti.Ner.Core.GetTextAttr.FirstNounGroupToNominativeSingle | Pullenti.Ner.Core.GetTextAttr.KeepRegister);
  245. //Console.WriteLine($"{kwstr} = {kw}");
  246. _report.Keywords2 += $"{kwstr} = {kw}<br>";
  247. }
  248. }
  249. }
  250. int res = (from x in npt_tokens
  251. select x).Distinct().Count();
  252. Console.WriteLine($"npt_tokens.count={npt_tokens.Count}, distinct.Count={res}");
  253. Console.WriteLine("Analysis is over!");
  254. var query = from x in npt_tokens
  255. group x by x into g
  256. let count1 = g.Count()
  257. orderby count1 descending
  258. select new { Name = g.Key, Count = count1 };
  259. foreach (var result in query)
  260. {
  261. _report.NounGroupsSorted += $"{result.Name}, Count: {result.Count}<br>";
  262. //Console.WriteLine($"Name: {result.Name}, Count: {result.Count}");
  263. }
  264. AppData.Report = _report;
  265. }
  266. else
  267. {
  268. _status = $"File duplicate founded, hash: {hash}.";
  269. Console.WriteLine(_status);
  270. _article = new();
  271. _articleClone = new();
  272. _document = null;
  273. _memoryStream.Close();
  274. _modalInfo_error.Open("Загрузка не удалась, такой документ уже есть в системе.");
  275. }
  276. file = null;
  277. stream.Close();
  278. }
  279. _modalLoading.Close();
  280. }
  281. async Task SaveDocument(int action_type = 1)
  282. {
  283. Console.WriteLine($"SaveDocument. DocID: {DocID}, article: {_article.ID}, Status: {_article.Status}");
  284. _modalLoading.Open();
  285. /// all is fine, continue
  286. MySQLConnector dbCon = MySQLConnector.Instance();
  287. long id = 0;
  288. string stringSQL;
  289. if (_article.Status != ArticleStatus.New && _article.Status != ArticleStatus.AwatingVerify)
  290. {
  291. string rating = (_article.Rating == null) ? "NULL" : _article.Rating.ToString();
  292. id = DocID;
  293. stringSQL = $"UPDATE articles " +
  294. $"SET filename='{_article.Filename}', article_name='{_article.Name}', authors='{_article.Authors}', " +
  295. $"date_publish='{_article.PublishDate:yyyy-MM-dd}', annotation='{_article.Annotation}', " +
  296. $"keywords='{_article.Keywords}', rating={rating}, file_hash='{_article.HashSum}' " +
  297. $"WHERE id={DocID}";
  298. await dbCon.SQLInsert(stringSQL);
  299. }
  300. else if (_article.Status == ArticleStatus.New)
  301. {
  302. stringSQL = $"INSERT INTO articles (filename, article_name, authors, date_publish, annotation, keywords, file_hash) " +
  303. $"VALUES ('{_article.Filename}', '{_article.Name}', '{_article.Authors}', '{_article.PublishDate:yyyy-MM-dd}'," +
  304. $"'{_article.Annotation}', '{_article.Keywords}', '{_article.HashSum}')";
  305. id = await dbCon.SQLInsert(stringSQL);
  306. _article.ID = (int)id;
  307. ///todo добавлять новый док в массив AppData.Articles
  308. }
  309. else
  310. {
  311. Console.WriteLine($"SaveDocument, wrong status. DocID: {DocID}, article: {_article.ID}, Status: {_article.Status}");
  312. id = 0;
  313. }
  314. if (id != 0)
  315. {
  316. stringSQL = $"INSERT INTO actions_history (article_id, action_type, acc_id) " +
  317. $"VALUES ('{id}', '{action_type}', '{_currentAccount.UUID}')";
  318. await dbCon.SQLInsert(stringSQL);
  319. Dictionary<string, PropertyInfo> propDict = Compare.SimpleCompare<ArticleModel>(_article, _articleClone);
  320. foreach (KeyValuePair<string, PropertyInfo> prop in propDict)
  321. {
  322. //Console.WriteLine($"property name: {prop.Key}, value: {prop.Value.GetValue(articleModel, null)}");
  323. stringSQL = $"INSERT INTO articles_edit_log (article_id, acc_id, field_name, field_prevvalue, field_newvalue) " +
  324. $"VALUES ('{id}', '{_currentAccount.UUID}', '{prop.Key}', '{prop.Value.GetValue(_articleClone, null)}', '{prop.Value.GetValue(_article, null)}')";
  325. await dbCon.SQLInsert(stringSQL);
  326. }
  327. if (_article.Status != ArticleStatus.New)
  328. {
  329. _status = propDict.Count > 0 ? "All changes saved." : "Article saved without any changes.";
  330. //transactionId = await Verify();
  331. //Console.WriteLine("transactionId found " + transactionId);
  332. ///tmp
  333. //editsCount = await article.GetEditsCount(currentAcc.UUID);
  334. //modalInfo_transac.Open();
  335. }
  336. else
  337. {
  338. // получаем html
  339. GetHtmlParam htmlParams = new();
  340. htmlParams.OutHtmlAndBodyTags = true;
  341. string html = _document.GetHtmlString(htmlParams);
  342. string fullpath;
  343. string htmldirectorypath;
  344. string docdirectorypath;
  345. #if DEBUG
  346. htmldirectorypath = Path.Combine(Environment.CurrentDirectory, "wwwroot", STORAGE_FOLDER_NAME, "html");
  347. docdirectorypath = Path.Combine(Environment.CurrentDirectory, "wwwroot", STORAGE_FOLDER_NAME, "source");
  348. #else
  349. htmldirectorypath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "wwwroot", STORAGE_FOLDER_NAME, "html");
  350. docdirectorypath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "wwwroot", STORAGE_FOLDER_NAME, "source");
  351. #endif
  352. ///saving html
  353. fullpath = Path.Combine(htmldirectorypath, _document.SourceFileName + ".html");
  354. Console.WriteLine($"Saving file [{fullpath}]");
  355. Directory.CreateDirectory(htmldirectorypath);
  356. File.WriteAllBytes(fullpath, Encoding.UTF8.GetBytes(html));
  357. ///saving original files
  358. fullpath = Path.Combine(docdirectorypath, $"{id}_{_article.Filename}");
  359. Console.WriteLine($"Saving file [{fullpath}]");
  360. Directory.CreateDirectory(docdirectorypath);
  361. FileStream fs = new(fullpath, FileMode.Create, FileAccess.Write);
  362. _memoryStream.Position = 0;
  363. await _memoryStream.CopyToAsync(fs);
  364. _status = $"User has saved new article data: [{id}_{_article.Filename}], memory size:{_memoryStream.Length}b, file size: {fs.Length}b";
  365. Console.WriteLine(_status);
  366. _memoryStream.Close();
  367. fs.Close();
  368. }
  369. /// reloading articles
  370. await AppData.LoadArticles();
  371. }
  372. _modalLoading.Close();
  373. if (id == 0)
  374. _modalInfo_error.Open($"Документ не будет сохранен из-за более позднего статуса.<br>DocID: {DocID}, article: {_article.ID}, Status: {GetDisplayName(_article.Status)}");
  375. else
  376. _modalInfo_error.Open("Документ успешно сохранен.");
  377. }
  378. async Task LoadDocument(int docid)
  379. {
  380. Console.WriteLine($"LoadDocument, docid: {docid}.");
  381. _modalLoading.Open();
  382. if (docid > 0)
  383. {
  384. MySQLConnector dbCon = MySQLConnector.Instance();
  385. string stringSQL = $"SELECT articles.id, filename, article_name, authors, date_publish, annotation, keywords, action_type, rating, file_hash " +
  386. $"FROM articles " +
  387. $"JOIN actions_history ON actions_history.article_id = articles.id " +
  388. $"WHERE articles.id={docid} " +
  389. $"ORDER BY actions_history.id DESC LiMIT 1";
  390. //_articleClone = await dbCon.SQLSelectArticle(stringSQL);
  391. //_article = (ArticleModel)_articleClone.Clone();
  392. AppData.CurrentArticleClone = await dbCon.SQLSelectArticle(stringSQL);
  393. AppData.CurrentArticle = (ArticleModel)AppData.CurrentArticleClone.Clone();
  394. //string initiator = await _article.GetInitiatorUUID();
  395. //initiatorAcc = AccountModel.Find(initiator);
  396. //_status = $"Article ID={DocID} loaded, status: {_article.Status}, initiator: {initiatorAcc.Name}";
  397. _status = $"Article ID={docid} loaded, status: {AppData.CurrentArticle.Status}.";
  398. _article = AppData.CurrentArticle ?? (new());
  399. _articleClone = AppData.CurrentArticleClone ?? (new());
  400. DocID = _article.ID;
  401. }
  402. _modalLoading.Close();
  403. }
  404. async Task SendToVerify()
  405. {
  406. if (_article.Status == ArticleStatus.New || _article.Status == ArticleStatus.Saved)
  407. {
  408. Console.WriteLine($"SendToVerify, DocID: {DocID}, article: {_article.ID}, Status: {_article.Status}");
  409. _modalLoading.Open();
  410. /// form validation
  411. List<string> errorFields = ValidateForm<ArticleModel>(_article);
  412. if (errorFields.Count > 0)
  413. {
  414. _modalLoading.Close();
  415. string invalid_fields = string.Join(", ", errorFields);
  416. _modalInfo_error.Open($"Не заполнены поля: {invalid_fields}");
  417. Console.WriteLine($"SendToVerify. Required fields: '{invalid_fields}' is not filled.");
  418. return;
  419. }
  420. await SaveDocument((int)ArticleStatus.AwatingVerify);
  421. _modalLoading.Close();
  422. }
  423. else
  424. {
  425. Console.WriteLine($"SendToVerify, wrong status. DocID: {DocID}, article: {_article.ID}, Status: {_article.Status}");
  426. _modalInfo_error.Open($"Документ уже отправлен на верификацию.<br>DocID: {DocID}, article: {_article.ID}, Status: {GetDisplayName(_article.Status)}");
  427. }
  428. }
  429. async Task<string> CalculateHashSum(MemoryStream ms)
  430. {
  431. MD5CryptoServiceProvider md5Provider = new();
  432. ms.Position = 0;
  433. byte[] hash = await md5Provider.ComputeHashAsync(ms);
  434. return Convert.ToBase64String(hash);
  435. }
  436. List<string> ValidateForm<T>(T obj)
  437. {
  438. var props = typeof(T).GetProperties().Where(pi => Attribute.IsDefined(pi, typeof(RequiredAttribute)));
  439. List<string> result = new();
  440. foreach (var prop in props)
  441. {
  442. var val = prop.GetValue(obj, null);
  443. if (val == null || val?.ToString().Length == 0)
  444. result.Add(prop.Name);
  445. //Console.WriteLine($"Required field '{prop.Name}' is not filled.");
  446. }
  447. return result;
  448. }
  449. static string GetDisplayName(Enum enumValue)
  450. {
  451. return enumValue.GetType()
  452. .GetMember(enumValue.ToString())
  453. .First()
  454. .GetCustomAttribute<DisplayAttribute>()
  455. .GetName();
  456. }
  457. async Task<AccountModel> GetCurrentAcc()
  458. {
  459. Console.WriteLine($"Desktop GetCurrentAcc");
  460. if (_currentAccount == null)
  461. {
  462. var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
  463. var user = authState.User;
  464. if (user.Identity.IsAuthenticated)
  465. {
  466. ///tmp
  467. Dictionary<string, AccountModel> accounts = await MySQLConnector.Instance().SQLSelectASPUsers();
  468. var currentUser = await UserManager.GetUserAsync(user);
  469. if (accounts.ContainsKey(currentUser.Id))
  470. _currentAccount = accounts[currentUser.Id];
  471. }
  472. }
  473. return _currentAccount;
  474. }
  475. }
  476. }