using HyperCube.Models; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Components.Forms; using Microsoft.AspNetCore.Identity; using Microsoft.JSInterop; using Pullenti.Unitext; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.IO; using System.Linq; using System.Reflection; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; using System.Xml; using Console = HyperCube.Utils.AdvConsole; namespace HyperCube.Pages { public partial class Desktop : ComponentBase { //[Parameter] //public int DocID { get; set; } [Inject] NavigationManager NavigationManager { get; set; } [Inject] AuthenticationStateProvider AuthenticationStateProvider { get; set; } [Inject] UserManager UserManager { get; set; } [Inject] RoleManager RoleManager { get; set; } [Inject] AppData AppData { get; set; } [Inject] public IJSRuntime JsRuntime { get; set; } const string STORAGE_FOLDER_NAME = "articles_storage"; const long MAX_FILE_SIZE = 5120000; //bytes const string ACTIVE_BUTTON_CLASS = "btn_white tab-button active"; const string ACTIVE_TAB_CLASS = "second-block__form visible"; const string BUTTON_CLASS = "btn_white tab-button"; const string TAB_CLASS = "second-block__form"; string _uploadButtonClass = ACTIVE_BUTTON_CLASS; string _uploadTabClass = ACTIVE_TAB_CLASS; string _verifyButtonClass = BUTTON_CLASS; string _verifyTabClass = TAB_CLASS; string _otherButtonClass = BUTTON_CLASS; string _otherTabClass = TAB_CLASS; //int _counter = 1; //string _event = ""; string _status; string _articleDropdownOption = ""; //string _storageFolderPath; MemoryStream _memoryStream; ModalInfo _modalInfo { get; set; } ModalLoading _modalLoading { get; set; } ArticleModel _articleClone; ArticleModel _article; Dictionary _articles = new(); ReportModel _report = new(); UnitextDocument _document; AccountModel _currentAccount; VerificationPoint _verificationPoint = new(); bool loadButtonDisable { get; set; } bool verifyButtonDisable { get; set; } bool rejectReasonDisable { get; set; } = true; protected override async Task OnInitializedAsync() { _currentAccount = (AppData.CurrentAccount != null) ? AppData.CurrentAccount : await GetCurrentAcc(); _currentAccount.LoadRoles(); Console.WriteLine($"Desktop OnInitializedAsync, CurrentAccount: {_currentAccount.Name}"); ///tmp await LoadArticles(); _article = AppData.CurrentArticle ?? (new()); _articleClone = AppData.CurrentArticleClone ?? (new()); } protected override void OnAfterRender(bool firstRender) { if (_verificationPoint.RulesViolation || _verificationPoint.NonExpert || _verificationPoint.AdditionalVerificationRequired || _verificationPoint.Rejected) { if (rejectReasonDisable) { rejectReasonDisable = false; StateHasChanged(); } } if (!_verificationPoint.RulesViolation && !_verificationPoint.NonExpert && !_verificationPoint.AdditionalVerificationRequired && !_verificationPoint.Rejected) { if (!rejectReasonDisable) { rejectReasonDisable = true; StateHasChanged(); } } } void SwitchDesktopTab(int tabIndex) { switch(tabIndex) { case 0: _uploadButtonClass = ACTIVE_BUTTON_CLASS; _uploadTabClass = ACTIVE_TAB_CLASS; _verifyButtonClass = BUTTON_CLASS; _verifyTabClass = TAB_CLASS; _otherButtonClass = BUTTON_CLASS; _otherTabClass = TAB_CLASS; break; case 1: _uploadButtonClass = BUTTON_CLASS; _uploadTabClass = TAB_CLASS; _verifyButtonClass = ACTIVE_BUTTON_CLASS; _verifyTabClass = ACTIVE_TAB_CLASS; _otherButtonClass = BUTTON_CLASS; _otherTabClass = TAB_CLASS; break; case 2: _uploadButtonClass = BUTTON_CLASS; _uploadTabClass = TAB_CLASS; _verifyButtonClass = BUTTON_CLASS; _verifyTabClass = TAB_CLASS; _otherButtonClass = ACTIVE_BUTTON_CLASS; _otherTabClass = ACTIVE_TAB_CLASS; break; } } async Task WidgetMenuClick(string menuname, string elementid) { await JsRuntime.InvokeVoidAsync("WidgetMenuClick", menuname, elementid); //_counter = 1; } async Task HandleUpload(InputFileChangeEventArgs e) { _modalLoading.Open(); IBrowserFile file = e.File; if (file != null) { Stream stream = file.OpenReadStream(MAX_FILE_SIZE); _memoryStream = new(); await stream.CopyToAsync(_memoryStream); _status = $"Finished loading {_memoryStream.Length} bytes from {file.Name}"; Console.WriteLine(_status); /// calculating hash string hash = await CalculateHashSum(_memoryStream); Console.WriteLine($"Hash: {hash}"); /// checking hash MySQLConnector dbCon = MySQLConnector.Instance(); string stringSQL; stringSQL = $"SELECT COUNT(*) FROM articles WHERE file_hash='{hash}'"; int count = await dbCon.SQLSelectCount(stringSQL); if (count < 1) { _report = new(); _report.FileName = file.Name; _report.FileSize = _memoryStream.Length.ToString(); _memoryStream.Position = 0; byte[] content = _memoryStream.ToArray(); _document = UnitextService.CreateDocument(null, content, null); if (_document.ErrorMessage != null) { // скорее всего, этот формат не поддерживается на данный момент Console.WriteLine($"error, sorry: {_document.ErrorMessage}"); _memoryStream.Close(); stream.Close(); _modalLoading.Close(); _modalInfo.Open("Не удается прочитать документ, формат не поддерживается или файл поврежден."); return; } // восстанавливаем имя исходного файла, извлечённого из ресурсов _document.SourceFileName = file.Name; for (int i = file.Name.Length - 7; i > 0; i--) { if (file.Name[i] == '.') { _document.SourceFileName = file.Name.Substring(i + 1); break; } } //// записываем результат в XML //using (FileStream fs = new(doc.SourceFileName + ".xml", FileMode.Create, FileAccess.Write)) //{ // XmlWriterSettings xmlParams = new(); // xmlParams.Encoding = Encoding.UTF8; // xmlParams.Indent = true; // xmlParams.IndentChars = " "; // using (XmlWriter xml = XmlWriter.Create(fs, xmlParams)) // { // xml.WriteStartDocument(); // doc.GetXml(xml); // xml.WriteEndDocument(); // } //} //Console.WriteLine("XML write done"); // получаем плоский текст string plainText = _document.GetPlaintextString(null); if (plainText == null) plainText = "Текст не выделен"; /// todo обработка, если статус != новый _articleClone = DocParse.GetBaseProperties(plainText); _articleClone.Filename = file.Name; _articleClone.HashSum = hash; _articleClone.CharCount = plainText.Length; _article = (ArticleModel)_articleClone.Clone(); ///tmp AppData.CurrentArticle = _article; Console.WriteLine($"Initializing SDK Pullenti ver {Pullenti.Sdk.Version} ({Pullenti.Sdk.VersionDate})... "); Pullenti.Sdk.InitializeAll(); //Console.WriteLine($"OK (by ... ms), version {Pullenti.Ner.ProcessorService.Version}"); List npt_tokens = new(); // запускаем обработку на пустом процессоре (без анализаторов NER) Pullenti.Ner.AnalysisResult are = Pullenti.Ner.ProcessorService.EmptyProcessor.Process(new Pullenti.Ner.SourceOfAnalysis(plainText), null, null); //System.Console.Write("Noun groups: "); // перебираем токены for (Pullenti.Ner.Token t = are.FirstToken; t != null; t = t.Next) { // выделяем именную группу с текущего токена Pullenti.Ner.Core.NounPhraseToken npt = Pullenti.Ner.Core.NounPhraseHelper.TryParse(t, Pullenti.Ner.Core.NounPhraseParseAttr.No, 0, null); // не получилось if (npt == null) continue; // получилось, выводим в нормализованном виде //System.Console.Write($"[{npt.GetSourceText()}=>{npt.GetNormalCaseText(null, Pullenti.Morph.MorphNumber.Singular, Pullenti.Morph.MorphGender.Undefined, false)}] "); //_report.NounGroups += $"[{npt.GetSourceText()}=>{npt.GetNormalCaseText(null, Pullenti.Morph.MorphNumber.Singular, Pullenti.Morph.MorphGender.Undefined, false)}] "; _article.NounGroups += $"[{npt.GetSourceText()}=>{npt.GetNormalCaseText(null, Pullenti.Morph.MorphNumber.Singular, Pullenti.Morph.MorphGender.Undefined, false)}] "; npt_tokens.Add(npt.GetNormalCaseText(null, Pullenti.Morph.MorphNumber.Singular, Pullenti.Morph.MorphGender.Undefined, false)); // указатель на последний токен именной группы t = npt.EndToken; } using (Pullenti.Ner.Processor proc = Pullenti.Ner.ProcessorService.CreateProcessor()) { // анализируем текст Pullenti.Ner.AnalysisResult ar = proc.Process(new Pullenti.Ner.SourceOfAnalysis(plainText), null, null); // результирующие сущности //Console.WriteLine("\r\n==========================================\r\nEntities: "); foreach (Pullenti.Ner.Referent en in ar.Entities) { //Console.WriteLine($"{en.TypeName}: {en}"); //_report.Entities += $"{en.TypeName}: {en}\r\n"; _article.Entities += $"{en.TypeName}: {en}\r\n"; foreach (Pullenti.Ner.Slot s in en.Slots) { //Console.WriteLine($" {s.TypeName}: {s.Value}"); //_report.Entities += $" {s.TypeName}: {s.Value}
"; _article.Entities += $" {s.TypeName}: {s.Value}
"; } } // пример выделения именных групп //Console.WriteLine("\r\n==========================================\r\nNoun groups: "); for (Pullenti.Ner.Token t = ar.FirstToken; t != null; t = t.Next) { // токены с сущностями игнорируем if (t.GetReferent() != null) continue; // пробуем создать именную группу Pullenti.Ner.Core.NounPhraseToken npt = Pullenti.Ner.Core.NounPhraseHelper.TryParse(t, Pullenti.Ner.Core.NounPhraseParseAttr.AdjectiveCanBeLast, 0, null); // не получилось if (npt == null) continue; //Console.WriteLine(npt.ToString()); //_report.EntitiesNounGroups += $"{npt}
"; _article.Morph += $"{npt}
"; // указатель перемещаем на последний токен группы t = npt.EndToken; } } using (Pullenti.Ner.Processor proc = Pullenti.Ner.ProcessorService.CreateSpecificProcessor(Pullenti.Ner.Keyword.KeywordAnalyzer.ANALYZER_NAME)) { Pullenti.Ner.AnalysisResult ar = proc.Process(new Pullenti.Ner.SourceOfAnalysis(plainText), null, null); //Console.WriteLine("\r\n==========================================\r\nKeywords1: "); foreach (Pullenti.Ner.Referent en in ar.Entities) { if (en is Pullenti.Ner.Keyword.KeywordReferent) //Console.WriteLine(en.ToString()); //_report.Keywords1 += $"{en}
"; _article.Keywords1 += $"{en}
"; } //Console.WriteLine("\r\n==========================================\r\nKeywords2: "); for (Pullenti.Ner.Token t = ar.FirstToken; t != null; t = t.Next) { if (t is Pullenti.Ner.ReferentToken) { Pullenti.Ner.Keyword.KeywordReferent kw = t.GetReferent() as Pullenti.Ner.Keyword.KeywordReferent; if (kw == null) continue; string kwstr = Pullenti.Ner.Core.MiscHelper.GetTextValueOfMetaToken(t as Pullenti.Ner.ReferentToken, Pullenti.Ner.Core.GetTextAttr.FirstNounGroupToNominativeSingle | Pullenti.Ner.Core.GetTextAttr.KeepRegister); //Console.WriteLine($"{kwstr} = {kw}"); //_report.Keywords2 += $"{kwstr} = {kw}
"; _article.Keywords2 += $"{kwstr} = {kw}
"; } } } int res = (from x in npt_tokens select x).Distinct().Count(); Console.WriteLine($"npt_tokens.count={npt_tokens.Count}, distinct.Count={res}"); Console.WriteLine("Analysis is over!"); var query = from x in npt_tokens group x by x into g let count1 = g.Count() orderby count1 descending select new { Name = g.Key, Count = count1 }; foreach (var result in query) { _report.NounGroupsSorted += $"{result.Name}, Count: {result.Count}
"; //Console.WriteLine($"Name: {result.Name}, Count: {result.Count}"); } //AppData.Report = _report; } else { _status = $"File duplicate founded, hash: {hash}."; Console.WriteLine(_status); _article = new(); _articleClone = new(); _document = null; _memoryStream.Close(); _modalInfo.Open("Загрузка не удалась, такой документ уже есть в системе."); } file = null; stream.Close(); } _modalLoading.Close(); } async Task NewDocument() { _article = new(); _articleClone = new(); _document = null; _memoryStream = null; _status = "Blank document created"; await JsRuntime.InvokeVoidAsync("WidgetMenuClick", ".block__dropbox", "desktop_menu"); //_counter = 1; } async Task SaveDocument_OnClick(ArticleStatus articleNewStatus) { Console.WriteLine($"SaveDocument_OnClick. DocID: {_article.ID}, Status: {_article.Status}"); if (_article.Name == null || _article.Name.Length == 0) { Console.WriteLine($"SaveDocument, empty article name. DocID: {_article.ID}, Status: {_article.Status}, filename: {_article.Filename}"); _modalInfo.Open( $"Для сохранения документа необходимо ввести название."); return; } if (_article.Status == ArticleStatus.New && _memoryStream == null) { Console.WriteLine($"SaveDocument, empty source file. DocID: {_article.ID}, Status: {_article.Status}, filename: {_article.Filename}"); _modalInfo.Open($"Для сохранения документа необходимо прикрепить исходный файл."); return; } if (_article.Status == ArticleStatus.New && articleNewStatus == ArticleStatus.Verifying || _article.Status == ArticleStatus.AwatingVerify && articleNewStatus == ArticleStatus.Saved || _article.Status == ArticleStatus.Verifying && articleNewStatus == ArticleStatus.Saved || _article.Status == ArticleStatus.Verified && articleNewStatus == ArticleStatus.Saved || _article.Status == ArticleStatus.Verified && articleNewStatus == ArticleStatus.Verifying) { Console.WriteLine($"SaveDocument, wrong status. DocID: {_article.ID}, Status: {_article.Status}"); _modalInfo.Open($"Текущий статус документа не позволяет сохранение.
DocID: {_article.ID}, Status: {GetDisplayName(_article.Status)}"); } else { /// all is fine, continue MySQLConnector dbCon = MySQLConnector.Instance(); long id; string stringSQL; if (_article.Status == ArticleStatus.New) { _modalLoading.Open(); stringSQL = $"INSERT INTO articles (filename, article_name, authors, date_publish, annotation, keywords, file_hash, " + $"doc_noungroups, doc_entities, doc_morph, doc_keywords1, doc_keywords2, char_count) " + $"VALUES ('{_article.Filename}', '{_article.Name}', '{_article.Authors}', '{_article.PublishDate:yyyy-MM-dd}'," + $"'{_article.Annotation}', '{_article.Keywords}', '{_article.HashSum}'," + $"'{_article.NounGroups}', '{_article.Entities}', '{_article.Morph}', '{_article.Keywords1}', '{_article.Keywords2}', '{_article.CharCount}' )"; id = await dbCon.SQLInsert(stringSQL); _article.ID = (int)id; ///todo добавлять новый док в массив AppData.Articles stringSQL = $"INSERT INTO actions_history (article_id, action_type, acc_id) " + $"VALUES ('{id}', '{(int)articleNewStatus}', '{_currentAccount.UUID}')"; await dbCon.SQLInsert(stringSQL); await SaveFiles((int)id); _article.Status = ArticleStatus.Saved; _articleClone = (ArticleModel)_article.Clone(); /// reloading articles await LoadArticles(); //_counter = 1; _modalLoading.Close(); _modalInfo.Open("Документ успешно создан."); } else { await UpdateDocument(articleNewStatus); //await SaveFiles(_article.ID); if (_article.Status == ArticleStatus.AwatingVerify || _article.Status == ArticleStatus.Verifying) await _article.SaveLastVerificationPoint(_verificationPoint, _currentAccount.UUID); } } } async Task LoadDocument(int docid) { ///todo загружать из массива AppData.Articles Console.WriteLine($"LoadDocument, docid: {docid}."); _modalLoading.Open(); if (docid > 0) { MySQLConnector dbCon = MySQLConnector.Instance(); AppData.CurrentArticleClone = await dbCon.SQLSelectArticle(docid); await AppData.CurrentArticleClone.GetVerificationHistory(_currentAccount.UUID); if (AppData.CurrentArticleClone.VerificationHistory.Count > 0) _verificationPoint = AppData.CurrentArticleClone.VerificationHistory.Values.Last(); else _verificationPoint = new(); AppData.CurrentArticle = (ArticleModel)AppData.CurrentArticleClone.Clone(); //string initiator = await _article.GetInitiatorUUID(); //initiatorAcc = AccountModel.Find(initiator); //_status = $"Article ID={DocID} loaded, status: {_article.Status}, initiator: {initiatorAcc.Name}"; _status = $"Article ID={docid} loaded, status: {AppData.CurrentArticle.Status}."; _article = AppData.CurrentArticle ?? (new()); _articleClone = AppData.CurrentArticleClone ?? (new()); } _modalLoading.Close(); } async Task SendToVerify_OnClick() { if (_article.Status == ArticleStatus.New || _article.Status == ArticleStatus.Saved) { Console.WriteLine($"SendToVerify, DocID: {_article.ID}, Status: {_article.Status}"); _modalLoading.Open(); /// form validation List errorFields = ValidateForm(_article); if (errorFields.Count > 0) { _modalLoading.Close(); string invalid_fields = string.Join(", ", errorFields); _modalInfo.Open($"Не заполнены поля: {invalid_fields}"); Console.WriteLine($"SendToVerify. Required fields: '{invalid_fields}' is not filled."); return; } await UpdateDocument(ArticleStatus.AwatingVerify); _modalLoading.Close(); } else { Console.WriteLine($"SendToVerify, wrong status. DocID: {_article.ID}, Status: {_article.Status}"); _modalInfo.Open($"Документ не может быть отправлен на верификацию.
DocID: {_article.ID}, Status: {GetDisplayName(_article.Status)}"); } } async Task Verify_OnClick() { //if (DocID > 0) //{ // status = propDict.Count > 0 ? "All changes saved, article has veryfied." : "Article verifyed without any changes."; // transactionId = await Verify(); // Console.WriteLine("transactionId found " + transactionId); // ///tmp // editsCount = await article.GetEditsCount(currentAcc.UUID); // modalInfo_transac.Open(); //} if (_article.Status == ArticleStatus.AwatingVerify || _article.Status == ArticleStatus.Verifying) { Console.WriteLine($"Verify, DocID: {_article.ID}, Status: {_article.Status}"); _modalLoading.Open(); /// form validation List errorFields = ValidateForm(_article); if (errorFields.Count > 0) { _modalLoading.Close(); string invalid_fields = string.Join(", ", errorFields); _modalInfo.Open($"Не заполнены поля: {invalid_fields}"); Console.WriteLine($"Verify. Required fields: '{invalid_fields}' is not filled."); return; } if (!rejectReasonDisable) { if (_verificationPoint.RejectReason == null || _verificationPoint.RejectReason.Length == 0) { _modalLoading.Close(); _modalInfo.Open($"Не заполнена причина отклонения."); Console.WriteLine($"Verify. Reject reason is not filled."); return; } } var bcMain = await _currentAccount.GetSelectedBlockChain(); var transactionId = await bcMain.Verify(_currentAccount, _article); Console.WriteLine("transactionId found " + transactionId); await UpdateDocument(ArticleStatus.Verified); _modalLoading.Close(); } else { Console.WriteLine($"Verify, wrong status. DocID: {_article.ID}, Status: {_article.Status}"); _modalInfo.Open($"Документ не может быть верифицирован.
DocID: {_article.ID}, Status: {GetDisplayName(_article.Status)}"); } } async Task UpdateDocument(ArticleStatus articleStatus) { _modalLoading.Open(); MySQLConnector dbCon = MySQLConnector.Instance(); string stringSQL; string rating = (_article.Rating == null) ? "NULL" : _article.Rating.ToString(); stringSQL = $"UPDATE articles " + $"SET filename='{_article.Filename}', article_name='{_article.Name}', authors='{_article.Authors}', " + $"date_publish='{_article.PublishDate:yyyy-MM-dd}', annotation='{_article.Annotation}', " + $"keywords='{_article.Keywords}', rating={rating}, file_hash='{_article.HashSum}' " + $"WHERE id={_article.ID}"; await dbCon.SQLInsert(stringSQL); ///todo обновлять док в массиве AppData.Articles stringSQL = $"INSERT INTO actions_history (article_id, action_type, acc_id) " + $"VALUES ('{_article.ID}', '{(int)articleStatus}', '{_currentAccount.UUID}')"; await dbCon.SQLInsert(stringSQL); ///если нужно фиксировать изменение статуса в поле (табл articles_edit_log) //_article.Status = articleStatus; Dictionary propDict = Compare.SimpleCompare(_article, _articleClone); foreach (KeyValuePair prop in propDict) { //Console.WriteLine($"property name: {prop.Key}, value: {prop.Value.GetValue(articleModel, null)}"); stringSQL = $"INSERT INTO articles_edit_log (article_id, acc_id, field_name, field_prevvalue, field_newvalue) " + $"VALUES ('{_article.ID}', '{_currentAccount.UUID}', '{prop.Key}', '{prop.Value.GetValue(_articleClone, null)}', '{prop.Value.GetValue(_article, null)}')"; await dbCon.SQLInsert(stringSQL); } _article.Status = articleStatus; _articleClone = (ArticleModel)_article.Clone(); /// reloading articles await LoadArticles(); _modalLoading.Close(); string message = propDict.Count > 0 ? "Все изменения успешно сохранены." : "Изменения не были найдены при сохранении."; if (_article.Status == ArticleStatus.Verified) message = "Документ успешно валидирован"; _modalInfo.Open(message); } async Task DocSelect_OnChange(ChangeEventArgs e) { int docid = int.Parse(e.Value.ToString()); Console.WriteLine($"DocSelect_OnChange. docid: {docid}"); await LoadDocument(docid); } async Task SaveFiles(int docid) { if (_document != null ) { string fullpath; string htmldirectorypath; string docdirectorypath; #if DEBUG htmldirectorypath = Path.Combine(Environment.CurrentDirectory, "wwwroot", STORAGE_FOLDER_NAME, "html"); docdirectorypath = Path.Combine(Environment.CurrentDirectory, "wwwroot", STORAGE_FOLDER_NAME, "source"); #else htmldirectorypath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "wwwroot", STORAGE_FOLDER_NAME, "html"); docdirectorypath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "wwwroot", STORAGE_FOLDER_NAME, "source"); #endif try { /// получаем html, сохраняем файлы GetHtmlParam htmlParams = new(); htmlParams.OutHtmlAndBodyTags = true; string html = _document.GetHtmlString(htmlParams); ///saving html fullpath = Path.Combine(htmldirectorypath, $"{docid}_{_document.SourceFileName}.html"); Console.WriteLine($"Saving file [{fullpath}]"); Directory.CreateDirectory(htmldirectorypath); File.WriteAllBytes(fullpath, Encoding.UTF8.GetBytes(html)); } catch (Exception ex) { Console.WriteLine($"{ex.GetType()}\r\n{ex.Message}\r\n{ex.StackTrace}"); } ///saving original files fullpath = Path.Combine(docdirectorypath, $"{docid}_{_article.Filename}"); Console.WriteLine($"Saving file [{fullpath}]"); Directory.CreateDirectory(docdirectorypath); FileStream fs = new(fullpath, FileMode.Create, FileAccess.Write); _memoryStream.Position = 0; await _memoryStream.CopyToAsync(fs); _status = $"User has saved new article data: [{docid}_{_article.Filename}], memory size:{_memoryStream.Length}b, file size: {fs.Length}b"; Console.WriteLine(_status); _memoryStream.Close(); fs.Close(); _document = null; } } async Task GetArticleFile(string option) { string fullpath; string htmldirectorypath; string docdirectorypath; #if DEBUG htmldirectorypath = Path.Combine(Environment.CurrentDirectory, "wwwroot", STORAGE_FOLDER_NAME, "html"); docdirectorypath = Path.Combine(Environment.CurrentDirectory, "wwwroot", STORAGE_FOLDER_NAME, "source"); #else htmldirectorypath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "wwwroot", STORAGE_FOLDER_NAME, "html"); docdirectorypath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "wwwroot", STORAGE_FOLDER_NAME, "source"); #endif if (option == "source") { fullpath = Path.Combine(docdirectorypath, $"{_article.ID}_{_article.Filename}"); if (fullpath.Length > 0 && File.Exists(fullpath)) NavigationManager.NavigateTo($"{STORAGE_FOLDER_NAME}/source/{_article.ID}_{_article.Filename}", true); else { Console.WriteLine($"GetArticleFile, file not exists: [{fullpath}]."); _modalInfo.Open("Файл документа не найден."); } } else if (option == "html") { fullpath = Path.Combine(docdirectorypath, $"{_article.ID}_{_article.Filename}.html"); if (fullpath.Length > 0 && File.Exists(fullpath)) NavigationManager.NavigateTo($"{STORAGE_FOLDER_NAME}/html/{_article.ID}_{_article.Filename}.html", true); else { Console.WriteLine($"GetArticleFile, file not exists: [{fullpath}]."); _modalInfo.Open("Файл документа не найден."); } } else { Console.WriteLine($"GetArticleFile, unknown method option: [{option}]."); //return; } } async Task LoadArticles() { /// reloading articles await AppData.LoadArticles(); _articles = new(); ///updating local articles and UI on role claims if (_currentAccount.Roles.Contains(Role.Admin)) { loadButtonDisable = false; verifyButtonDisable = false; int counter = 1; foreach (ArticleModel article in AppData.Articles.Values) { _articles.Add(counter++, article); } } else if (_currentAccount.Roles.Contains(Role.Expert)) { loadButtonDisable = true; verifyButtonDisable = false; int counter = 1; foreach (ArticleModel article in AppData.Articles.Values) { if (article.Status == ArticleStatus.AwatingVerify || article.Status == ArticleStatus.Verifying || article.Status == ArticleStatus.Verified) _articles.Add(counter++, article); } SwitchDesktopTab(1); } else if (_currentAccount.Roles.Contains(Role.Miner)) { loadButtonDisable = false; verifyButtonDisable = true; int counter = 1; foreach (ArticleModel article in AppData.Articles.Values) { if (article.Status == ArticleStatus.New || article.Status == ArticleStatus.Saved || article.Status == ArticleStatus.Verified) _articles.Add(counter++, article); } } else { loadButtonDisable = true; verifyButtonDisable = true; int counter = 1; foreach (ArticleModel article in AppData.Articles.Values) { _articles.Add(counter++, article); } SwitchDesktopTab(2); } } async Task CalculateHashSum(MemoryStream ms) { MD5CryptoServiceProvider md5Provider = new(); ms.Position = 0; byte[] hash = await md5Provider.ComputeHashAsync(ms); return Convert.ToBase64String(hash); } List ValidateForm(T obj) { var props = typeof(T).GetProperties().Where(pi => Attribute.IsDefined(pi, typeof(RequiredAttribute))); List result = new(); foreach (var prop in props) { var val = prop.GetValue(obj, null); if (val == null || val?.ToString().Length == 0) result.Add(prop.Name); //Console.WriteLine($"Required field '{prop.Name}' is not filled."); } return result; } static string GetDisplayName(Enum enumValue) { return enumValue.GetType() .GetMember(enumValue.ToString()) .First() .GetCustomAttribute() .GetName(); } async Task GetCurrentAcc() { Console.WriteLine($"Desktop GetCurrentAcc"); if (_currentAccount == null) { var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync(); var user = authState.User; if (user.Identity.IsAuthenticated) { var currentUser = await UserManager.GetUserAsync(user); var acc = AccountModel.Find(currentUser.Id); if (acc != null) { _currentAccount = AccountModel.Loaded[currentUser.Id]; } else { Dictionary accounts = await MySQLConnector.Instance().SQLSelectASPUsers(); if (accounts.ContainsKey(currentUser.Id)) _currentAccount = accounts[currentUser.Id]; } /// asp roles //var role1 = new IdentityRole { Name = "admin" }; //var result = await RoleManager.CreateAsync(role1); //Console.WriteLine($"RoleManager create result: {result}"); //result = await UserManager.AddToRoleAsync(currentUser, role1.Name); //Console.WriteLine($"RoleManager add role result: {result}"); } } return _currentAccount; } } }