From 639ec9e4aa93d89cd79516169ad7db622bfa5efa Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Sat, 2 Oct 2021 10:19:12 +0330 Subject: [PATCH] rerfactoring --- RMuseum/RMuseum.xml | 91 ++-- .../GanjoorService-Maintenance.cs | 510 ++++++++++++++++++ .../Services/Implementation/GanjoorService.cs | 492 ----------------- 3 files changed, 557 insertions(+), 536 deletions(-) create mode 100644 RMuseum/Services/Implementation/GanjoorService-Partials/GanjoorService-Maintenance.cs diff --git a/RMuseum/RMuseum.xml b/RMuseum/RMuseum.xml index 16445492..04cb0110 100644 --- a/RMuseum/RMuseum.xml +++ b/RMuseum/RMuseum.xml @@ -9786,6 +9786,9 @@ IGanjoorService implementation + + IGanjoorService implementation + @@ -9849,6 +9852,50 @@ + + + find category poem rhymes + + + + + + + + + start generating sub cats TOC + + + + + + + + generate category TOC + + + + + + + + make plain text + + + + + + + separate verses in poem.PlainText with Environment.NewLine instead of SPACE + + + + + + examine site pages for broken links + + + start updating stats page @@ -10397,50 +10444,6 @@ - - - find category poem rhymes - - - - - - - - - start generating sub cats TOC - - - - - - - - generate category TOC - - - - - - - - make plain text - - - - - - - separate verses in poem.PlainText with Environment.NewLine instead of SPACE - - - - - - examine site pages for broken links - - - Database Context diff --git a/RMuseum/Services/Implementation/GanjoorService-Partials/GanjoorService-Maintenance.cs b/RMuseum/Services/Implementation/GanjoorService-Partials/GanjoorService-Maintenance.cs new file mode 100644 index 00000000..a2d65c56 --- /dev/null +++ b/RMuseum/Services/Implementation/GanjoorService-Partials/GanjoorService-Maintenance.cs @@ -0,0 +1,510 @@ +using Microsoft.EntityFrameworkCore; +using RMuseum.DbContext; +using RMuseum.Models.Ganjoor; +using RMuseum.Services.Implementation.ImportedFromDesktopGanjoor; +using RSecurityBackend.Models.Generic; +using RSecurityBackend.Models.Generic.Db; +using RSecurityBackend.Services.Implementation; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; + +namespace RMuseum.Services.Implementation +{ + /// + /// IGanjoorService implementation + /// + public partial class GanjoorService : IGanjoorService + { + private async Task _FindCategoryPoemsRhythmsInternal(int catId, bool retag, string rhythm) + { + using (RMuseumDbContext context = new RMuseumDbContext(new DbContextOptions())) //this is long running job, so _context might be already been freed/collected by GC + { + LongRunningJobProgressServiceEF jobProgressServiceEF = new LongRunningJobProgressServiceEF(context); + var job = (await jobProgressServiceEF.NewJob($"FindCategoryPoemsRhythms Cat {catId}", "Query data")).Result; + try + { + var metres = await context.GanjoorMetres.OrderBy(m => m.Rhythm).AsNoTracking().ToArrayAsync(); + var rhythms = metres.Select(m => m.Rhythm).ToArray(); + + GanjoorMetre preDeterminedMetre = string.IsNullOrEmpty(rhythm) ? null : metres.Where(m => m.Rhythm == rhythm).Single(); + + var poems = await context.GanjoorPoems.Where(p => p.CatId == catId).ToListAsync(); + + int i = 0; + using (HttpClient httpClient = new HttpClient()) + { + foreach (var poem in poems) + { + if (retag || poem.GanjoorMetreId == null) + { + await jobProgressServiceEF.UpdateJob(job.Id, i++); + if (preDeterminedMetre == null) + { + var res = await _FindPoemRhythm(poem.Id, context, httpClient, rhythms); + if (!string.IsNullOrEmpty(res.Result)) + { + poem.GanjoorMetreId = metres.Where(m => m.Rhythm == res.Result).Single().Id; + context.GanjoorPoems.Update(poem); + await context.SaveChangesAsync(); + } + } + else + { + poem.GanjoorMetreId = preDeterminedMetre.Id; + context.GanjoorPoems.Update(poem); + await context.SaveChangesAsync(); + } + } + } + } + await jobProgressServiceEF.UpdateJob(job.Id, 99); + + await jobProgressServiceEF.UpdateJob(job.Id, 100, "", true); + } + catch (Exception exp) + { + await jobProgressServiceEF.UpdateJob(job.Id, 100, "", false, exp.ToString()); + } + } + } + + /// + /// find category poem rhymes + /// + /// + /// + /// + /// + public RServiceResult FindCategoryPoemsRhythms(int catId, bool retag, string rhythm = "") + { + _backgroundTaskQueue.QueueBackgroundWorkItem + ( + async token => + { + await _FindCategoryPoemsRhythmsInternal(catId, retag, rhythm); + }); + + return new RServiceResult(true); + } + + private async Task _GeneratingSubCatsTOC(Guid userId, RMuseumDbContext context, LongRunningJobProgressServiceEF jobProgressServiceEF, RLongRunningJobStatus job, int catId) + { + foreach (var cat in await context.GanjoorCategories.AsNoTracking().Where(c => c.ParentId == catId).ToListAsync()) + { + await jobProgressServiceEF.UpdateJob(job.Id, cat.Id); + var page = await context.GanjoorPages.Where(p => p.FullUrl == cat.FullUrl).SingleAsync(); + + context.GanjoorPageSnapshots.Add + ( + new GanjoorPageSnapshot() + { + GanjoorPageId = page.Id, + MadeObsoleteByUserId = userId, + HtmlText = page.HtmlText, + Note = "تولید گروهی فهرستهای زیربخشها", + RecordDate = DateTime.Now + } + ); + + page.HtmlText = (await _GenerateTableOfContents(context, cat.Id, GanjoorTOC.TitlesAndFirstVerse)).Result; + context.GanjoorPages.Update(page); + await context.SaveChangesAsync(); + + await _GeneratingSubCatsTOC(userId, context, jobProgressServiceEF, job, cat.Id); + } + } + + /// + /// start generating sub cats TOC + /// + /// + /// + /// + public RServiceResult StartGeneratingSubCatsTOC(Guid userId, int catId) + { + _backgroundTaskQueue.QueueBackgroundWorkItem + ( + async token => + { + using (RMuseumDbContext context = new RMuseumDbContext(new DbContextOptions())) //this is long running job, so _context might be already been freed/collected by GC + { + LongRunningJobProgressServiceEF jobProgressServiceEF = new LongRunningJobProgressServiceEF(context); + var job = (await jobProgressServiceEF.NewJob($"GeneratingSubCatsTOC {catId}", "Query data")).Result; + try + { + await _GeneratingSubCatsTOC(userId, context, jobProgressServiceEF, job, catId); + await jobProgressServiceEF.UpdateJob(job.Id, 100, "", true); + } + catch (Exception exp) + { + await jobProgressServiceEF.UpdateJob(job.Id, 100, "", false, exp.ToString()); + } + + } + }); + + return new RServiceResult(true); + } + + /// + /// generate category TOC + /// + /// + /// + /// + public async Task> GenerateTableOfContents(int catId, GanjoorTOC options) + { + return await _GenerateTableOfContents(_context, catId, options); + } + + + private async Task> _GenerateTableOfContents(RMuseumDbContext context, int catId, GanjoorTOC options) + { + string html = ""; + var subCats = await context.GanjoorCategories.Where(c => c.ParentId == catId).OrderBy(c => c.Id).AsNoTracking().ToArrayAsync(); + + foreach (var cat in subCats) + { + html += $"

{cat.Title}

{Environment.NewLine}"; + } + + var poems = await context.GanjoorPoems.Where(p => p.CatId == catId).OrderBy(p => p.Id).AsNoTracking().ToArrayAsync(); + + if (poems.Length > 0) + { + if (options == GanjoorTOC.Analyse) + { + if (poems.Where(p => !string.IsNullOrEmpty(p.RhymeLetters)).Count() * 100 / poems.Length > 50) + { + options = GanjoorTOC.AlphabeticWithFirstVerse; + } + else + { + options = GanjoorTOC.TitlesAndFirstVerse; + } + } + } + + if + ( + options == GanjoorTOC.AlphabeticWithFirstCouplet + || + options == GanjoorTOC.AlphabeticWithFirstVerse + || + options == GanjoorTOC.AlphabeticWithSecondVerse + ) + { + var taggedPoems = poems.Where(p => !string.IsNullOrEmpty(p.RhymeLetters)).ToArray(); + if (taggedPoems.Length > 0) + { + html += $"

فهرست شعرها به ترتیب آخر حرف قافیه گردآوری شده است. برای پیدا کردن یک شعر کافی است حرف آخر قافیهٔ آن را در نظر بگیرید تا بتوانید آن را پیدا کنید.

{Environment.NewLine}"; + var randomPoem = taggedPoems[new Random(DateTime.Now.Millisecond).Next(taggedPoems.Length)]; + var randomPoemVerses = await context.GanjoorVerses.AsNoTracking().Where(p => p.PoemId == randomPoem.Id).OrderBy(v => v.VOrder).ToArrayAsync(); + if (randomPoemVerses.Length > 2) + { + html += $"

مثلاً برای پیدا کردن شعری که مصرع {randomPoemVerses[1].Text} مصرع دوم یکی از بیتهای آن است باید شعرهایی را نگاه کنید که آخر حرف قافیهٔ آنها «{randomPoem.RhymeLetters.Substring(randomPoem.RhymeLetters.Length - 1)}» است.

{Environment.NewLine}"; + } + + html += $"

دسترسی سریع به حروف

{Environment.NewLine}"; + html += $"

{Environment.NewLine}"; + string lastChar = ""; + List visitedLastChart = new List(); + foreach (var poem in taggedPoems) + { + string poemLastChar = poem.RhymeLetters.Substring(poem.RhymeLetters.Length - 1); + if (poemLastChar != lastChar) + { + if (visitedLastChart.IndexOf(poemLastChar) == -1) + { + if (lastChar != "") + { + html += " | "; + } + html += $"{poemLastChar}"; + lastChar = poemLastChar; + + visitedLastChart.Add(poemLastChar); + } + } + } + html += $"

{Environment.NewLine}"; + } + } + + string last = ""; + List visitedLast = new List(); + foreach (var poem in poems) + { + if + ( + options == GanjoorTOC.AlphabeticWithFirstCouplet + || + options == GanjoorTOC.AlphabeticWithFirstVerse + || + options == GanjoorTOC.AlphabeticWithSecondVerse + ) + { + + if (!string.IsNullOrEmpty(poem.RhymeLetters)) + { + string poemLast = poem.RhymeLetters.Substring(poem.RhymeLetters.Length - 1); + if (poemLast != last) + { + if (visitedLast.IndexOf(poemLast) == -1) + { + html += $"

{poemLast}

{Environment.NewLine}"; + last = poemLast; + visitedLast.Add(poemLast); + } + } + } + } + + html += $"

{poem.Title}"; + + var verses = await context.GanjoorVerses.AsNoTracking().Where(p => p.PoemId == poem.Id).OrderBy(v => v.VOrder).ToArrayAsync(); + + if (verses.Length > 0) + { + if (options == GanjoorTOC.TitlesAndFirstVerse || options == GanjoorTOC.AlphabeticWithFirstVerse) + { + html += $": {verses[0].Text}"; + } + else + if (options == GanjoorTOC.AlphabeticWithSecondVerse || options == GanjoorTOC.TitlesAndSecondVerse) + { + if (verses.Length > 1) + { + html += $": {verses[1].Text}"; + } + else + { + html += $": {verses[0].Text}"; + } + } + else + if (options == GanjoorTOC.AlphabeticWithFirstCouplet || options == GanjoorTOC.TitlesAndFirstCouplet) + { + if (verses.Length > 1) + { + html += $": {verses[0].Text} - {verses[1].Text}"; + } + else + { + html += $": {verses[0].Text}"; + } + } + else + if (options == GanjoorTOC.TitlesAndFirstCenteredVerse) + { + if (verses.Where(v => v.VersePosition == VersePosition.CenteredVerse1).Any()) + { + html += $": {verses.Where(v => v.VersePosition == VersePosition.CenteredVerse1).First().Text}"; + } + else + { + html += $": {verses[0].Text}"; + } + } + else + if (options == GanjoorTOC.TitlesAndFirstCenteredCouplet) + { + if ( + verses.Where(v => v.VersePosition == VersePosition.CenteredVerse1).Any() + && + verses.Where(v => v.VersePosition == VersePosition.CenteredVerse2).Any() + ) + { + html += $": {verses.Where(v => v.VersePosition == VersePosition.CenteredVerse1).First().Text} - {verses.Where(v => v.VersePosition == VersePosition.CenteredVerse2).First().Text}"; + } + else + { + html += $": {verses[0].Text}"; + } + } + } + + + html += $"

{Environment.NewLine}"; + } + return new RServiceResult(html); + } + + + + /// + /// make plain text + /// + /// + /// + private static string PreparePlainText(List verses) + { + string plainText = ""; + foreach (GanjoorVerse verse in verses) + { + plainText += $"{LanguageUtils.MakeTextSearchable(verse.Text)}{Environment.NewLine}";//replace zwnj with space + } + return plainText.Trim(); + } + + /// + /// separate verses in poem.PlainText with Environment.NewLine instead of SPACE + /// + /// + public RServiceResult RegerneratePoemsPlainText() + { + _backgroundTaskQueue.QueueBackgroundWorkItem + ( + async token => + { + using (RMuseumDbContext context = new RMuseumDbContext(new DbContextOptions())) //this is long running job, so _context might be already been freed/collected by GC + { + LongRunningJobProgressServiceEF jobProgressServiceEF = new LongRunningJobProgressServiceEF(context); + var job = (await jobProgressServiceEF.NewJob("RegerneratePoemsPlainText", "Query data")).Result; + + try + { + var poems = await context.GanjoorPoems.ToArrayAsync(); + + await jobProgressServiceEF.UpdateJob(job.Id, 0, $"Updating PlainText/Poem Html"); + + int percent = 0; + for (int i = 0; i < poems.Length; i++) + { + if (i * 100 / poems.Length > percent) + { + percent++; + await jobProgressServiceEF.UpdateJob(job.Id, percent); + } + + var poem = poems[i]; + + var verses = await context.GanjoorVerses.AsNoTracking().Where(v => v.PoemId == poem.Id).OrderBy(v => v.VOrder).ToListAsync(); + + poem.PlainText = PreparePlainText(verses); + poem.HtmlText = PrepareHtmlText(verses); + } + + await jobProgressServiceEF.UpdateJob(job.Id, 0, $"Finalizing PlainText/Poem Html"); + + context.GanjoorPoems.UpdateRange(poems); + + await context.SaveChangesAsync(); + + await jobProgressServiceEF.UpdateJob(job.Id, 50, $"Updating pages HTML"); + + await context.Database.ExecuteSqlRawAsync("UPDATE p SET p.HtmlText = (SELECT poem.HtmlText FROM GanjoorPoems poem WHERE poem.Id = p.Id) FROM GanjoorPages p WHERE p.GanjoorPageType = 3 "); + + await jobProgressServiceEF.UpdateJob(job.Id, 100, "", true); + } + catch (Exception exp) + { + await jobProgressServiceEF.UpdateJob(job.Id, 100, "", false, exp.ToString()); + } + + } + } + ); + + return new RServiceResult(true); + } + + /// + /// examine site pages for broken links + /// + /// + public RServiceResult HealthCheckContents() + { + _backgroundTaskQueue.QueueBackgroundWorkItem + ( + async token => + { + using (RMuseumDbContext context = new RMuseumDbContext(new DbContextOptions())) //this is long running job, so _context might be already been freed/collected by GC + { + LongRunningJobProgressServiceEF jobProgressServiceEF = new LongRunningJobProgressServiceEF(context); + var job = (await jobProgressServiceEF.NewJob("HealthCheckContents", "Query data")).Result; + + try + { + var pages = await context.GanjoorPages.ToArrayAsync(); + + await jobProgressServiceEF.UpdateJob(job.Id, 0, $"Examining Pages"); + + var previousErrors = await context.GanjoorHealthCheckErrors.ToArrayAsync(); + context.RemoveRange(previousErrors); + await context.SaveChangesAsync(); + int percent = 0; + for (int i = 0; i < pages.Length; i++) + { + if (i * 100 / pages.Length > percent) + { + percent++; + await jobProgressServiceEF.UpdateJob(job.Id, percent); + } + + var hrefs = pages[i].HtmlText.Split(new[] { "href=\"" }, StringSplitOptions.RemoveEmptyEntries).Where(o => o.StartsWith("http")).Select(o => o.Substring(0, o.IndexOf("\""))); + + foreach (string url in hrefs) + { + if (url == "https://ganjoor.net" || url == "https://ganjoor.net/" || url.IndexOf("https://ganjoor.net/vazn/?") == 0 || url.IndexOf("https://ganjoor.net/simi/?v") == 0) + continue; + if (url.IndexOf("http://ganjoor.net") == 0) + { + context.GanjoorHealthCheckErrors.Add + ( + new GanjoorHealthCheckError() + { + ReferrerPageUrl = pages[i].FullUrl, + TargetUrl = url, + BrokenLink = false, + MulipleTargets = false + } + ); + + await context.SaveChangesAsync(); + } + else + if (url.IndexOf("https://ganjoor.net") == 0) + { + var testUrl = url.Substring("https://ganjoor.net".Length); + if (testUrl[testUrl.Length - 1] == '/') + testUrl = testUrl.Substring(0, testUrl.Length - 1); + var pageCount = await context.GanjoorPages.Where(p => p.FullUrl == testUrl).CountAsync(); + if (pageCount != 1) + { + context.GanjoorHealthCheckErrors.Add + ( + new GanjoorHealthCheckError() + { + ReferrerPageUrl = pages[i].FullUrl, + TargetUrl = url, + BrokenLink = pageCount == 0, + MulipleTargets = pageCount != 0 + } + ); + + await context.SaveChangesAsync(); + } + } + } + } + + await jobProgressServiceEF.UpdateJob(job.Id, 100, "", true); + } + catch (Exception exp) + { + await jobProgressServiceEF.UpdateJob(job.Id, 100, "", false, exp.ToString()); + } + + } + } + ); + + return new RServiceResult(true); + } + } +} \ No newline at end of file diff --git a/RMuseum/Services/Implementation/GanjoorService.cs b/RMuseum/Services/Implementation/GanjoorService.cs index c3268833..244df299 100644 --- a/RMuseum/Services/Implementation/GanjoorService.cs +++ b/RMuseum/Services/Implementation/GanjoorService.cs @@ -20,8 +20,6 @@ using DNTPersianUtils.Core; using Microsoft.Extensions.Caching.Memory; using System.Net.Http; using System.Web; -using RMuseum.Services.Implementation.ImportedFromDesktopGanjoor; -using RSecurityBackend.Models.Generic.Db; namespace RMuseum.Services.Implementation { @@ -3605,496 +3603,6 @@ namespace RMuseum.Services.Implementation } } - private async Task _FindCategoryPoemsRhythmsInternal(int catId, bool retag, string rhythm) - { - using (RMuseumDbContext context = new RMuseumDbContext(new DbContextOptions())) //this is long running job, so _context might be already been freed/collected by GC - { - LongRunningJobProgressServiceEF jobProgressServiceEF = new LongRunningJobProgressServiceEF(context); - var job = (await jobProgressServiceEF.NewJob($"FindCategoryPoemsRhythms Cat {catId}", "Query data")).Result; - try - { - var metres = await context.GanjoorMetres.OrderBy(m => m.Rhythm).AsNoTracking().ToArrayAsync(); - var rhythms = metres.Select(m => m.Rhythm).ToArray(); - - GanjoorMetre preDeterminedMetre = string.IsNullOrEmpty(rhythm) ? null : metres.Where(m => m.Rhythm == rhythm).Single(); - - var poems = await context.GanjoorPoems.Where(p => p.CatId == catId).ToListAsync(); - - int i = 0; - using (HttpClient httpClient = new HttpClient()) - { - foreach (var poem in poems) - { - if (retag || poem.GanjoorMetreId == null) - { - await jobProgressServiceEF.UpdateJob(job.Id, i++); - if (preDeterminedMetre == null) - { - var res = await _FindPoemRhythm(poem.Id, context, httpClient, rhythms); - if (!string.IsNullOrEmpty(res.Result)) - { - poem.GanjoorMetreId = metres.Where(m => m.Rhythm == res.Result).Single().Id; - context.GanjoorPoems.Update(poem); - await context.SaveChangesAsync(); - } - } - else - { - poem.GanjoorMetreId = preDeterminedMetre.Id; - context.GanjoorPoems.Update(poem); - await context.SaveChangesAsync(); - } - } - } - } - await jobProgressServiceEF.UpdateJob(job.Id, 99); - - await jobProgressServiceEF.UpdateJob(job.Id, 100, "", true); - } - catch (Exception exp) - { - await jobProgressServiceEF.UpdateJob(job.Id, 100, "", false, exp.ToString()); - } - } - } - - /// - /// find category poem rhymes - /// - /// - /// - /// - /// - public RServiceResult FindCategoryPoemsRhythms(int catId, bool retag, string rhythm = "") - { - _backgroundTaskQueue.QueueBackgroundWorkItem - ( - async token => - { - await _FindCategoryPoemsRhythmsInternal(catId, retag, rhythm); - }); - - return new RServiceResult(true); - } - - private async Task _GeneratingSubCatsTOC(Guid userId, RMuseumDbContext context, LongRunningJobProgressServiceEF jobProgressServiceEF, RLongRunningJobStatus job, int catId) - { - foreach (var cat in await context.GanjoorCategories.AsNoTracking().Where(c => c.ParentId == catId).ToListAsync()) - { - await jobProgressServiceEF.UpdateJob(job.Id, cat.Id); - var page = await context.GanjoorPages.Where(p => p.FullUrl == cat.FullUrl).SingleAsync(); - - context.GanjoorPageSnapshots.Add - ( - new GanjoorPageSnapshot() - { - GanjoorPageId = page.Id, - MadeObsoleteByUserId = userId, - HtmlText = page.HtmlText, - Note = "تولید گروهی فهرستهای زیربخشها", - RecordDate = DateTime.Now - } - ); - - page.HtmlText = (await _GenerateTableOfContents(context, cat.Id, GanjoorTOC.TitlesAndFirstVerse)).Result; - context.GanjoorPages.Update(page); - await context.SaveChangesAsync(); - - await _GeneratingSubCatsTOC(userId, context, jobProgressServiceEF, job, cat.Id); - } - } - - /// - /// start generating sub cats TOC - /// - /// - /// - /// - public RServiceResult StartGeneratingSubCatsTOC(Guid userId, int catId) - { - _backgroundTaskQueue.QueueBackgroundWorkItem - ( - async token => - { - using (RMuseumDbContext context = new RMuseumDbContext(new DbContextOptions())) //this is long running job, so _context might be already been freed/collected by GC - { - LongRunningJobProgressServiceEF jobProgressServiceEF = new LongRunningJobProgressServiceEF(context); - var job = (await jobProgressServiceEF.NewJob($"GeneratingSubCatsTOC {catId}", "Query data")).Result; - try - { - await _GeneratingSubCatsTOC(userId, context, jobProgressServiceEF, job, catId); - await jobProgressServiceEF.UpdateJob(job.Id, 100, "", true); - } - catch (Exception exp) - { - await jobProgressServiceEF.UpdateJob(job.Id, 100, "", false, exp.ToString()); - } - - } - }); - - return new RServiceResult(true); - } - - /// - /// generate category TOC - /// - /// - /// - /// - public async Task> GenerateTableOfContents(int catId, GanjoorTOC options) - { - return await _GenerateTableOfContents(_context, catId, options); - } - - - private async Task> _GenerateTableOfContents(RMuseumDbContext context, int catId, GanjoorTOC options) - { - string html = ""; - var subCats = await context.GanjoorCategories.Where(c => c.ParentId == catId).OrderBy(c => c.Id).AsNoTracking().ToArrayAsync(); - - foreach (var cat in subCats) - { - html += $"

{cat.Title}

{Environment.NewLine}"; - } - - var poems = await context.GanjoorPoems.Where(p => p.CatId == catId).OrderBy(p => p.Id).AsNoTracking().ToArrayAsync(); - - if (poems.Length > 0) - { - if (options == GanjoorTOC.Analyse) - { - if (poems.Where(p => !string.IsNullOrEmpty(p.RhymeLetters)).Count() * 100 / poems.Length > 50) - { - options = GanjoorTOC.AlphabeticWithFirstVerse; - } - else - { - options = GanjoorTOC.TitlesAndFirstVerse; - } - } - } - - if - ( - options == GanjoorTOC.AlphabeticWithFirstCouplet - || - options == GanjoorTOC.AlphabeticWithFirstVerse - || - options == GanjoorTOC.AlphabeticWithSecondVerse - ) - { - var taggedPoems = poems.Where(p => !string.IsNullOrEmpty(p.RhymeLetters)).ToArray(); - if (taggedPoems.Length > 0) - { - html += $"

فهرست شعرها به ترتیب آخر حرف قافیه گردآوری شده است. برای پیدا کردن یک شعر کافی است حرف آخر قافیهٔ آن را در نظر بگیرید تا بتوانید آن را پیدا کنید.

{Environment.NewLine}"; - var randomPoem = taggedPoems[new Random(DateTime.Now.Millisecond).Next(taggedPoems.Length)]; - var randomPoemVerses = await context.GanjoorVerses.AsNoTracking().Where(p => p.PoemId == randomPoem.Id).OrderBy(v => v.VOrder).ToArrayAsync(); - if (randomPoemVerses.Length > 2) - { - html += $"

مثلاً برای پیدا کردن شعری که مصرع {randomPoemVerses[1].Text} مصرع دوم یکی از بیتهای آن است باید شعرهایی را نگاه کنید که آخر حرف قافیهٔ آنها «{randomPoem.RhymeLetters.Substring(randomPoem.RhymeLetters.Length - 1)}» است.

{Environment.NewLine}"; - } - - html += $"

دسترسی سریع به حروف

{Environment.NewLine}"; - html += $"

{Environment.NewLine}"; - string lastChar = ""; - List visitedLastChart = new List(); - foreach (var poem in taggedPoems) - { - string poemLastChar = poem.RhymeLetters.Substring(poem.RhymeLetters.Length - 1); - if (poemLastChar != lastChar) - { - if (visitedLastChart.IndexOf(poemLastChar) == -1) - { - if (lastChar != "") - { - html += " | "; - } - html += $"{poemLastChar}"; - lastChar = poemLastChar; - - visitedLastChart.Add(poemLastChar); - } - } - } - html += $"

{Environment.NewLine}"; - } - } - - string last = ""; - List visitedLast = new List(); - foreach (var poem in poems) - { - if - ( - options == GanjoorTOC.AlphabeticWithFirstCouplet - || - options == GanjoorTOC.AlphabeticWithFirstVerse - || - options == GanjoorTOC.AlphabeticWithSecondVerse - ) - { - - if (!string.IsNullOrEmpty(poem.RhymeLetters)) - { - string poemLast = poem.RhymeLetters.Substring(poem.RhymeLetters.Length - 1); - if (poemLast != last) - { - if (visitedLast.IndexOf(poemLast) == -1) - { - html += $"

{poemLast}

{Environment.NewLine}"; - last = poemLast; - visitedLast.Add(poemLast); - } - } - } - } - - html += $"

{poem.Title}"; - - var verses = await context.GanjoorVerses.AsNoTracking().Where(p => p.PoemId == poem.Id).OrderBy(v => v.VOrder).ToArrayAsync(); - - if (verses.Length > 0) - { - if (options == GanjoorTOC.TitlesAndFirstVerse || options == GanjoorTOC.AlphabeticWithFirstVerse) - { - html += $": {verses[0].Text}"; - } - else - if (options == GanjoorTOC.AlphabeticWithSecondVerse || options == GanjoorTOC.TitlesAndSecondVerse) - { - if (verses.Length > 1) - { - html += $": {verses[1].Text}"; - } - else - { - html += $": {verses[0].Text}"; - } - } - else - if (options == GanjoorTOC.AlphabeticWithFirstCouplet || options == GanjoorTOC.TitlesAndFirstCouplet) - { - if (verses.Length > 1) - { - html += $": {verses[0].Text} - {verses[1].Text}"; - } - else - { - html += $": {verses[0].Text}"; - } - } - else - if (options == GanjoorTOC.TitlesAndFirstCenteredVerse) - { - if (verses.Where(v => v.VersePosition == VersePosition.CenteredVerse1).Any()) - { - html += $": {verses.Where(v => v.VersePosition == VersePosition.CenteredVerse1).First().Text}"; - } - else - { - html += $": {verses[0].Text}"; - } - } - else - if (options == GanjoorTOC.TitlesAndFirstCenteredCouplet) - { - if ( - verses.Where(v => v.VersePosition == VersePosition.CenteredVerse1).Any() - && - verses.Where(v => v.VersePosition == VersePosition.CenteredVerse2).Any() - ) - { - html += $": {verses.Where(v => v.VersePosition == VersePosition.CenteredVerse1).First().Text} - {verses.Where(v => v.VersePosition == VersePosition.CenteredVerse2).First().Text}"; - } - else - { - html += $": {verses[0].Text}"; - } - } - } - - - html += $"

{Environment.NewLine}"; - } - return new RServiceResult(html); - } - - - - /// - /// make plain text - /// - /// - /// - private static string PreparePlainText(List verses) - { - string plainText = ""; - foreach (GanjoorVerse verse in verses) - { - plainText += $"{LanguageUtils.MakeTextSearchable(verse.Text)}{Environment.NewLine}";//replace zwnj with space - } - return plainText.Trim(); - } - - /// - /// separate verses in poem.PlainText with Environment.NewLine instead of SPACE - /// - /// - public RServiceResult RegerneratePoemsPlainText() - { - _backgroundTaskQueue.QueueBackgroundWorkItem - ( - async token => - { - using (RMuseumDbContext context = new RMuseumDbContext(new DbContextOptions())) //this is long running job, so _context might be already been freed/collected by GC - { - LongRunningJobProgressServiceEF jobProgressServiceEF = new LongRunningJobProgressServiceEF(context); - var job = (await jobProgressServiceEF.NewJob("RegerneratePoemsPlainText", "Query data")).Result; - - try - { - var poems = await context.GanjoorPoems.ToArrayAsync(); - - await jobProgressServiceEF.UpdateJob(job.Id, 0, $"Updating PlainText/Poem Html"); - - int percent = 0; - for (int i = 0; i < poems.Length; i++) - { - if (i * 100 / poems.Length > percent) - { - percent++; - await jobProgressServiceEF.UpdateJob(job.Id, percent); - } - - var poem = poems[i]; - - var verses = await context.GanjoorVerses.AsNoTracking().Where(v => v.PoemId == poem.Id).OrderBy(v => v.VOrder).ToListAsync(); - - poem.PlainText = PreparePlainText(verses); - poem.HtmlText = PrepareHtmlText(verses); - } - - await jobProgressServiceEF.UpdateJob(job.Id, 0, $"Finalizing PlainText/Poem Html"); - - context.GanjoorPoems.UpdateRange(poems); - - await context.SaveChangesAsync(); - - await jobProgressServiceEF.UpdateJob(job.Id, 50, $"Updating pages HTML"); - - await context.Database.ExecuteSqlRawAsync("UPDATE p SET p.HtmlText = (SELECT poem.HtmlText FROM GanjoorPoems poem WHERE poem.Id = p.Id) FROM GanjoorPages p WHERE p.GanjoorPageType = 3 "); - - await jobProgressServiceEF.UpdateJob(job.Id, 100, "", true); - } - catch (Exception exp) - { - await jobProgressServiceEF.UpdateJob(job.Id, 100, "", false, exp.ToString()); - } - - } - } - ); - - return new RServiceResult(true); - } - - /// - /// examine site pages for broken links - /// - /// - public RServiceResult HealthCheckContents() - { - _backgroundTaskQueue.QueueBackgroundWorkItem - ( - async token => - { - using (RMuseumDbContext context = new RMuseumDbContext(new DbContextOptions())) //this is long running job, so _context might be already been freed/collected by GC - { - LongRunningJobProgressServiceEF jobProgressServiceEF = new LongRunningJobProgressServiceEF(context); - var job = (await jobProgressServiceEF.NewJob("HealthCheckContents", "Query data")).Result; - - try - { - var pages = await context.GanjoorPages.ToArrayAsync(); - - await jobProgressServiceEF.UpdateJob(job.Id, 0, $"Examining Pages"); - - var previousErrors = await context.GanjoorHealthCheckErrors.ToArrayAsync(); - context.RemoveRange(previousErrors); - await context.SaveChangesAsync(); - int percent = 0; - for (int i = 0; i < pages.Length; i++) - { - if (i * 100 / pages.Length > percent) - { - percent++; - await jobProgressServiceEF.UpdateJob(job.Id, percent); - } - - var hrefs = pages[i].HtmlText.Split(new[] { "href=\"" }, StringSplitOptions.RemoveEmptyEntries).Where(o => o.StartsWith("http")).Select(o => o.Substring(0, o.IndexOf("\""))); - - foreach (string url in hrefs) - { - if (url == "https://ganjoor.net" || url == "https://ganjoor.net/" || url.IndexOf("https://ganjoor.net/vazn/?") == 0 || url.IndexOf("https://ganjoor.net/simi/?v") == 0) - continue; - if (url.IndexOf("http://ganjoor.net") == 0) - { - context.GanjoorHealthCheckErrors.Add - ( - new GanjoorHealthCheckError() - { - ReferrerPageUrl = pages[i].FullUrl, - TargetUrl = url, - BrokenLink = false, - MulipleTargets = false - } - ); - - await context.SaveChangesAsync(); - } - else - if (url.IndexOf("https://ganjoor.net") == 0) - { - var testUrl = url.Substring("https://ganjoor.net".Length); - if (testUrl[testUrl.Length - 1] == '/') - testUrl = testUrl.Substring(0, testUrl.Length - 1); - var pageCount = await context.GanjoorPages.Where(p => p.FullUrl == testUrl).CountAsync(); - if (pageCount != 1) - { - context.GanjoorHealthCheckErrors.Add - ( - new GanjoorHealthCheckError() - { - ReferrerPageUrl = pages[i].FullUrl, - TargetUrl = url, - BrokenLink = pageCount == 0, - MulipleTargets = pageCount != 0 - } - ); - - await context.SaveChangesAsync(); - } - } - } - } - - await jobProgressServiceEF.UpdateJob(job.Id, 100, "", true); - } - catch (Exception exp) - { - await jobProgressServiceEF.UpdateJob(job.Id, 100, "", false, exp.ToString()); - } - - } - } - ); - - return new RServiceResult(true); - } - - - /// /// Database Context ///