|
@@ -21,8 +21,8 @@ namespace HyperCube.Pages
|
|
{
|
|
{
|
|
public partial class Desktop : ComponentBase
|
|
public partial class Desktop : ComponentBase
|
|
{
|
|
{
|
|
- [Parameter]
|
|
|
|
- public int DocID { get; set; }
|
|
|
|
|
|
+ //[Parameter]
|
|
|
|
+ //public int DocID { get; set; }
|
|
|
|
|
|
[Inject]
|
|
[Inject]
|
|
NavigationManager NavigationManager { get; set; }
|
|
NavigationManager NavigationManager { get; set; }
|
|
@@ -78,6 +78,7 @@ namespace HyperCube.Pages
|
|
_currentAccount = (AppData.CurrentAccount != null) ? AppData.CurrentAccount : await GetCurrentAcc();
|
|
_currentAccount = (AppData.CurrentAccount != null) ? AppData.CurrentAccount : await GetCurrentAcc();
|
|
Console.WriteLine($"Desktop OnInitializedAsync, CurrentAccount: {_currentAccount.Name}");
|
|
Console.WriteLine($"Desktop OnInitializedAsync, CurrentAccount: {_currentAccount.Name}");
|
|
}
|
|
}
|
|
|
|
+
|
|
protected override void OnAfterRender(bool firstRender) => _counter = 1;
|
|
protected override void OnAfterRender(bool firstRender) => _counter = 1;
|
|
|
|
|
|
void SwitchDesktopTab(int tabIndex)
|
|
void SwitchDesktopTab(int tabIndex)
|
|
@@ -187,8 +188,9 @@ namespace HyperCube.Pages
|
|
// получаем плоский текст
|
|
// получаем плоский текст
|
|
string plainText = _document.GetPlaintextString(null);
|
|
string plainText = _document.GetPlaintextString(null);
|
|
if (plainText == null)
|
|
if (plainText == null)
|
|
- plainText = "Текст не выделен";
|
|
|
|
|
|
+ plainText = "Текст не выделен";
|
|
|
|
|
|
|
|
+ /// todo обработка, если статус != новый
|
|
_articleClone = DocParse.GetBaseProperties(plainText);
|
|
_articleClone = DocParse.GetBaseProperties(plainText);
|
|
_articleClone.Filename = file.Name;
|
|
_articleClone.Filename = file.Name;
|
|
_articleClone.HashSum = hash;
|
|
_articleClone.HashSum = hash;
|
|
@@ -320,121 +322,73 @@ namespace HyperCube.Pages
|
|
_modalLoading.Close();
|
|
_modalLoading.Close();
|
|
}
|
|
}
|
|
|
|
|
|
- async Task SaveDocument(int action_type = 1)
|
|
|
|
|
|
+ async Task SaveDocument_OnClick(ArticleStatus articleNewStatus)
|
|
{
|
|
{
|
|
- Console.WriteLine($"SaveDocument. DocID: {DocID}, article: {_article.ID}, Status: {_article.Status}");
|
|
|
|
-
|
|
|
|
- _modalLoading.Open();
|
|
|
|
|
|
+ Console.WriteLine($"SaveDocument_OnClick. DocID: {_article.ID}, Status: {_article.Status}");
|
|
|
|
|
|
- /// all is fine, continue
|
|
|
|
- MySQLConnector dbCon = MySQLConnector.Instance();
|
|
|
|
- long id = 0;
|
|
|
|
- string stringSQL;
|
|
|
|
-
|
|
|
|
- if (_article.Status != ArticleStatus.New && _article.Status != ArticleStatus.AwatingVerify)
|
|
|
|
|
|
+ if (_article?.Name == null || _article?.Name.Length == 0)
|
|
{
|
|
{
|
|
- string rating = (_article.Rating == null) ? "NULL" : _article.Rating.ToString();
|
|
|
|
-
|
|
|
|
- id = DocID;
|
|
|
|
- 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={DocID}";
|
|
|
|
- await dbCon.SQLInsert(stringSQL);
|
|
|
|
|
|
+ Console.WriteLine($"SaveDocument, empty article name. DocID: {_article.ID}, Status: {_article.Status}");
|
|
|
|
+ _modalInfo_error.Open($"Для сохранения документа необходимо ввести название.");
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
- else if (_article.Status == ArticleStatus.New)
|
|
|
|
- {
|
|
|
|
- stringSQL = $"INSERT INTO articles (filename, article_name, authors, date_publish, annotation, keywords, file_hash) " +
|
|
|
|
- $"VALUES ('{_article.Filename}', '{_article.Name}', '{_article.Authors}', '{_article.PublishDate:yyyy-MM-dd}'," +
|
|
|
|
- $"'{_article.Annotation}', '{_article.Keywords}', '{_article.HashSum}')";
|
|
|
|
- id = await dbCon.SQLInsert(stringSQL);
|
|
|
|
- _article.ID = (int)id;
|
|
|
|
|
|
|
|
- ///todo добавлять новый док в массив AppData.Articles
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
|
|
+ if (_article.Status == ArticleStatus.New && articleNewStatus == ArticleStatus.Verifying
|
|
|
|
+ || _article.Status == ArticleStatus.AwatingVerify && articleNewStatus == ArticleStatus.Saved
|
|
|
|
+ || _article.Status == ArticleStatus.Verified && articleNewStatus == ArticleStatus.Saved
|
|
|
|
+ || _article.Status == ArticleStatus.Verified && articleNewStatus == ArticleStatus.Verifying)
|
|
{
|
|
{
|
|
- Console.WriteLine($"SaveDocument, wrong status. DocID: {DocID}, article: {_article.ID}, Status: {_article.Status}");
|
|
|
|
- id = 0;
|
|
|
|
|
|
+ Console.WriteLine($"SaveDocument, wrong status. DocID: {_article.ID}, Status: {_article.Status}");
|
|
|
|
+ _modalInfo_error.Open($"Текущий статус документа не позволяет сохранение.<br>DocID: {_article.ID}, Status: {GetDisplayName(_article.Status)}");
|
|
}
|
|
}
|
|
-
|
|
|
|
- if (id != 0)
|
|
|
|
|
|
+ else
|
|
{
|
|
{
|
|
- stringSQL = $"INSERT INTO actions_history (article_id, action_type, acc_id) " +
|
|
|
|
- $"VALUES ('{id}', '{action_type}', '{_currentAccount.UUID}')";
|
|
|
|
- await dbCon.SQLInsert(stringSQL);
|
|
|
|
|
|
+ /// all is fine, continue
|
|
|
|
+ MySQLConnector dbCon = MySQLConnector.Instance();
|
|
|
|
+ long id;
|
|
|
|
+ string stringSQL;
|
|
|
|
|
|
- Dictionary<string, PropertyInfo> propDict = Compare.SimpleCompare<ArticleModel>(_article, _articleClone);
|
|
|
|
- foreach (KeyValuePair<string, PropertyInfo> prop in propDict)
|
|
|
|
|
|
+ if (_article.Status == ArticleStatus.New)
|
|
{
|
|
{
|
|
- //Console.WriteLine($"property name: {prop.Key}, value: {prop.Value.GetValue(articleModel, null)}");
|
|
|
|
|
|
+ _modalLoading.Open();
|
|
|
|
+
|
|
|
|
+ stringSQL = $"INSERT INTO articles (filename, article_name, authors, date_publish, annotation, keywords, file_hash) " +
|
|
|
|
+ $"VALUES ('{_article.Filename}', '{_article.Name}', '{_article.Authors}', '{_article.PublishDate:yyyy-MM-dd}'," +
|
|
|
|
+ $"'{_article.Annotation}', '{_article.Keywords}', '{_article.HashSum}')";
|
|
|
|
+ id = await dbCon.SQLInsert(stringSQL);
|
|
|
|
+ _article.ID = (int)id;
|
|
|
|
+
|
|
|
|
+ ///todo добавлять новый док в массив AppData.Articles
|
|
|
|
|
|
- stringSQL = $"INSERT INTO articles_edit_log (article_id, acc_id, field_name, field_prevvalue, field_newvalue) " +
|
|
|
|
- $"VALUES ('{id}', '{_currentAccount.UUID}', '{prop.Key}', '{prop.Value.GetValue(_articleClone, null)}', '{prop.Value.GetValue(_article, null)}')";
|
|
|
|
|
|
+ stringSQL = $"INSERT INTO actions_history (article_id, action_type, acc_id) " +
|
|
|
|
+ $"VALUES ('{id}', '{(int)articleNewStatus}', '{_currentAccount.UUID}')";
|
|
await dbCon.SQLInsert(stringSQL);
|
|
await dbCon.SQLInsert(stringSQL);
|
|
- }
|
|
|
|
|
|
|
|
- if (_article.Status != ArticleStatus.New)
|
|
|
|
- {
|
|
|
|
- _status = propDict.Count > 0 ? "All changes saved." : "Article saved without any changes.";
|
|
|
|
- //transactionId = await Verify();
|
|
|
|
- //Console.WriteLine("transactionId found " + transactionId);
|
|
|
|
|
|
+ await SaveFiles((int)id);
|
|
|
|
+
|
|
|
|
+ _article.Status = ArticleStatus.Saved;
|
|
|
|
+ _articleClone = (ArticleModel)_article.Clone();
|
|
|
|
|
|
- ///tmp
|
|
|
|
- //editsCount = await article.GetEditsCount(currentAcc.UUID);
|
|
|
|
- //modalInfo_transac.Open();
|
|
|
|
|
|
+ /// reloading articles
|
|
|
|
+ await AppData.LoadArticles();
|
|
|
|
+
|
|
|
|
+ _counter = 1;
|
|
|
|
+
|
|
|
|
+ _modalLoading.Close();
|
|
|
|
+ _modalInfo_error.Open("Документ успешно создан.");
|
|
}
|
|
}
|
|
else
|
|
else
|
|
{
|
|
{
|
|
- // получаем html
|
|
|
|
- GetHtmlParam htmlParams = new();
|
|
|
|
- htmlParams.OutHtmlAndBodyTags = true;
|
|
|
|
- string html = _document.GetHtmlString(htmlParams);
|
|
|
|
- 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
|
|
|
|
- ///saving html
|
|
|
|
- fullpath = Path.Combine(htmldirectorypath, _document.SourceFileName + ".html");
|
|
|
|
- Console.WriteLine($"Saving file [{fullpath}]");
|
|
|
|
- Directory.CreateDirectory(htmldirectorypath);
|
|
|
|
- File.WriteAllBytes(fullpath, Encoding.UTF8.GetBytes(html));
|
|
|
|
-
|
|
|
|
- ///saving original files
|
|
|
|
- fullpath = Path.Combine(docdirectorypath, $"{id}_{_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: [{id}_{_article.Filename}], memory size:{_memoryStream.Length}b, file size: {fs.Length}b";
|
|
|
|
- Console.WriteLine(_status);
|
|
|
|
- _memoryStream.Close();
|
|
|
|
- fs.Close();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /// reloading articles
|
|
|
|
- await AppData.LoadArticles();
|
|
|
|
|
|
+ await UpdateDocument(articleNewStatus);
|
|
|
|
+ await SaveFiles(_article.ID);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
-
|
|
|
|
- _modalLoading.Close();
|
|
|
|
-
|
|
|
|
- if (id == 0)
|
|
|
|
- _modalInfo_error.Open($"Документ не будет сохранен из-за более позднего статуса.<br>DocID: {DocID}, article: {_article.ID}, Status: {GetDisplayName(_article.Status)}");
|
|
|
|
- else
|
|
|
|
- _modalInfo_error.Open("Документ успешно сохранен.");
|
|
|
|
}
|
|
}
|
|
|
|
|
|
async Task LoadDocument(int docid)
|
|
async Task LoadDocument(int docid)
|
|
{
|
|
{
|
|
|
|
+ ///todo загружать из массива AppData.Articles
|
|
|
|
+
|
|
Console.WriteLine($"LoadDocument, docid: {docid}.");
|
|
Console.WriteLine($"LoadDocument, docid: {docid}.");
|
|
_modalLoading.Open();
|
|
_modalLoading.Open();
|
|
|
|
|
|
@@ -460,18 +414,16 @@ namespace HyperCube.Pages
|
|
|
|
|
|
_article = AppData.CurrentArticle ?? (new());
|
|
_article = AppData.CurrentArticle ?? (new());
|
|
_articleClone = AppData.CurrentArticleClone ?? (new());
|
|
_articleClone = AppData.CurrentArticleClone ?? (new());
|
|
-
|
|
|
|
- DocID = _article.ID;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
_modalLoading.Close();
|
|
_modalLoading.Close();
|
|
}
|
|
}
|
|
|
|
|
|
- async Task SendToVerify()
|
|
|
|
|
|
+ async Task SendToVerify_OnClick()
|
|
{
|
|
{
|
|
if (_article.Status == ArticleStatus.New || _article.Status == ArticleStatus.Saved)
|
|
if (_article.Status == ArticleStatus.New || _article.Status == ArticleStatus.Saved)
|
|
{
|
|
{
|
|
- Console.WriteLine($"SendToVerify, DocID: {DocID}, article: {_article.ID}, Status: {_article.Status}");
|
|
|
|
|
|
+ Console.WriteLine($"SendToVerify, DocID: {_article.ID}, Status: {_article.Status}");
|
|
_modalLoading.Open();
|
|
_modalLoading.Open();
|
|
|
|
|
|
/// form validation
|
|
/// form validation
|
|
@@ -485,17 +437,139 @@ namespace HyperCube.Pages
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- await SaveDocument((int)ArticleStatus.AwatingVerify);
|
|
|
|
|
|
+ await UpdateDocument(ArticleStatus.AwatingVerify);
|
|
|
|
|
|
_modalLoading.Close();
|
|
_modalLoading.Close();
|
|
}
|
|
}
|
|
else
|
|
else
|
|
{
|
|
{
|
|
- Console.WriteLine($"SendToVerify, wrong status. DocID: {DocID}, article: {_article.ID}, Status: {_article.Status}");
|
|
|
|
- _modalInfo_error.Open($"Документ уже отправлен на верификацию.<br>DocID: {DocID}, article: {_article.ID}, Status: {GetDisplayName(_article.Status)}");
|
|
|
|
|
|
+ Console.WriteLine($"SendToVerify, wrong status. DocID: {_article.ID}, Status: {_article.Status}");
|
|
|
|
+ _modalInfo_error.Open($"Документ не может быть отправлен на верификацию.<br>DocID: {_article.ID}, Status: {GetDisplayName(_article.Status)}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ async Task Verify_OnClick()
|
|
|
|
+ {
|
|
|
|
+ if (_article.Status == ArticleStatus.AwatingVerify || _article.Status == ArticleStatus.Verifying)
|
|
|
|
+ {
|
|
|
|
+ Console.WriteLine($"Verify, DocID: {_article.ID}, Status: {_article.Status}");
|
|
|
|
+ _modalLoading.Open();
|
|
|
|
+
|
|
|
|
+ /// form validation
|
|
|
|
+ List<string> errorFields = ValidateForm<ArticleModel>(_article);
|
|
|
|
+ if (errorFields.Count > 0)
|
|
|
|
+ {
|
|
|
|
+ _modalLoading.Close();
|
|
|
|
+ string invalid_fields = string.Join(", ", errorFields);
|
|
|
|
+ _modalInfo_error.Open($"Не заполнены поля: {invalid_fields}");
|
|
|
|
+ Console.WriteLine($"Verify. Required fields: '{invalid_fields}' is not filled.");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ await UpdateDocument(ArticleStatus.Verified);
|
|
|
|
+
|
|
|
|
+ _modalLoading.Close();
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ Console.WriteLine($"Verify, wrong status. DocID: {_article.ID}, Status: {_article.Status}");
|
|
|
|
+ _modalInfo_error.Open($"Документ не может быть верифицирован.<br>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<string, PropertyInfo> propDict = Compare.SimpleCompare<ArticleModel>(_article, _articleClone);
|
|
|
|
+ foreach (KeyValuePair<string, PropertyInfo> 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 AppData.LoadArticles();
|
|
|
|
+
|
|
|
|
+ _modalLoading.Close();
|
|
|
|
+
|
|
|
|
+ string message = propDict.Count > 0 ? "Все изменения успешно сохранены." : "Изменений не найдено.";
|
|
|
|
+ _modalInfo_error.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)
|
|
|
|
+ {
|
|
|
|
+ /// получаем html, сохраняем файлы
|
|
|
|
+ GetHtmlParam htmlParams = new();
|
|
|
|
+ htmlParams.OutHtmlAndBodyTags = true;
|
|
|
|
+ string html = _document.GetHtmlString(htmlParams);
|
|
|
|
+ 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
|
|
|
|
+ ///html
|
|
|
|
+ fullpath = Path.Combine(htmldirectorypath, $"{docid}_{_document.SourceFileName}.html");
|
|
|
|
+ Console.WriteLine($"Saving file [{fullpath}]");
|
|
|
|
+ Directory.CreateDirectory(htmldirectorypath);
|
|
|
|
+ File.WriteAllBytes(fullpath, Encoding.UTF8.GetBytes(html));
|
|
|
|
+
|
|
|
|
+ ///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();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
async Task<string> CalculateHashSum(MemoryStream ms)
|
|
async Task<string> CalculateHashSum(MemoryStream ms)
|
|
{
|
|
{
|
|
MD5CryptoServiceProvider md5Provider = new();
|
|
MD5CryptoServiceProvider md5Provider = new();
|