using DNTPersianUtils.Core; using Microsoft.EntityFrameworkCore; using RMuseum.DbContext; using RMuseum.Migrations; using RMuseum.Models.Ganjoor; using RMuseum.Models.Ganjoor.ViewModels; using RSecurityBackend.Models.Generic; using RSecurityBackend.Services.Implementation; using System; using System.Collections.Generic; using System.Data; using System.Drawing; using System.Globalization; using System.Linq; using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; namespace RMuseum.Services.Implementation { /// /// IGanjoorService implementation /// public partial class GanjoorService : IGanjoorService { /// /// get digital source from tag /// /// /// public async Task> GetDigitalSourceFromTagAsync(string sourceUrlSlug) { try { return new RServiceResult(await _context.DigitalSources.AsNoTracking().Where(d => d.UrlSlug == sourceUrlSlug).SingleOrDefaultAsync()); } catch (Exception exp) { return new RServiceResult(null, exp.ToString()); } } /// /// tag with sources /// /// /// public void TagCategoryWithSource(int catId, DigitalSource source) { _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($"TagCategoryWithSource(catId: {catId} - source:{source.UrlSlug})", "Query data")).Result; try { var pages = await context.GanjoorPages.AsNoTracking().Where(p => p.FullUrl.StartsWith("/sources/")).ToListAsync(); foreach (var page in pages) { if (false == await context.DigitalSources.Where(d => d.UrlSlug == page.UrlSlug).AnyAsync()) { string shortName = page.Title; switch (page.UrlSlug) { case "wikidorj": shortName = "ویکی‌درج"; break; case "frankfurt": shortName = "دانشگاه فرانکفورت"; break; case "tariqmo": shortName = "طریق التحقیق دکتر مؤذنی"; break; case "tebyan": shortName = "تبیان"; break; } context.DigitalSources.Add ( new DigitalSource() { UrlSlug = page.UrlSlug, ShortName = shortName, FullName = page.Title, SourceType = "", CoupletsCount = 0, } ); await context.SaveChangesAsync(); } } var digitalSource = await context.DigitalSources.Where(p => p.UrlSlug == source.UrlSlug).SingleOrDefaultAsync(); if (digitalSource == null) { context.DigitalSources.Add ( new DigitalSource() { UrlSlug = source.UrlSlug, ShortName = source.ShortName, FullName = source.FullName, SourceType = source.SourceType, CoupletsCount = 0, } ); var parentPage = await context.GanjoorPages.AsNoTracking().Where(p => p.UrlSlug == "sources").SingleAsync(); var newPageId = 1 + await context.GanjoorPages.MaxAsync(p => p.Id); while (await context.GanjoorPoems.Where(p => p.Id == newPageId).AnyAsync()) newPageId++; context.GanjoorPages.Add ( new GanjoorPage() { Id = newPageId, GanjoorPageType = GanjoorPageType.None, Published = true, PageOrder = -1, Title = source.FullName, FullTitle = $"{parentPage.FullTitle} » {source.FullName}", FullUrl = $"{parentPage.FullUrl}/{source.UrlSlug}", UrlSlug = source.UrlSlug, HtmlText = $"

{source.FullName}

", PostDate = DateTime.Now, ParentId = parentPage.Id, } ); await context.SaveChangesAsync(); digitalSource = await context.DigitalSources.Where(p => p.UrlSlug == source.UrlSlug).SingleAsync(); } List catIdList = new List { catId }; await _populateCategoryChildren(context, catId, catIdList); int poemCount = 0; int progress = 0; foreach (int catId in catIdList) { var poems = await context.GanjoorPoems.AsNoTracking().Where(p => p.CatId == catId).ToListAsync(); poemCount += poems.Count; foreach (var poem in poems) { poem.SourceName = digitalSource.ShortName; poem.SourceUrlSlug = source.UrlSlug; context.Update(poem); int coupletCount = await context.GanjoorVerses.AsNoTracking() .Where(v => v.PoemId == poem.Id && (v.VersePosition == VersePosition.Right || v.VersePosition == VersePosition.CenteredVerse1) ).CountAsync(); digitalSource.CoupletsCount += coupletCount; await jobProgressServiceEF.UpdateJob(job.Id, progress, $"{progress} از {poemCount}"); } } context.Update(digitalSource); await jobProgressServiceEF.UpdateJob(job.Id, 100, "", true); } catch (Exception exp) { await jobProgressServiceEF.UpdateJob(job.Id, 100, "", false, exp.ToString()); } } }); } /// /// update digital sources stats /// /// public void UpdateDigitalSourcesStats(Guid editingUserId) { _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($"UpdateDigitalSourcesStats", "Query data")).Result; try { var pages = await context.GanjoorPages.AsNoTracking().Where(p => p.FullUrl.StartsWith("/sources/")).ToListAsync(); foreach (var page in pages) { if (false == await context.DigitalSources.Where(d => d.UrlSlug == page.UrlSlug).AnyAsync()) { string shortName = page.Title; switch (page.UrlSlug) { case "wikidorj": shortName = "ویکی‌درج"; break; case "frankfurt": shortName = "دانشگاه فرانکفورت"; break; case "tariqmo": shortName = "طریق التحقیق دکتر مؤذنی"; break; case "tebyan": shortName = "تبیان"; break; } context.DigitalSources.Add ( new DigitalSource() { UrlSlug = page.UrlSlug, ShortName = shortName, FullName = page.Title, SourceType = "", CoupletsCount = 0, } ); await context.SaveChangesAsync(); } } var digitalSources = await context.DigitalSources.ToArrayAsync(); Dictionary> digitalSourcesCats = new Dictionary>(); int totalCoupletsCount = 0; foreach (var digitalSource in digitalSources) { digitalSource.CoupletsCount = 0; List cats = new List(); var poems = await context.GanjoorPoems.AsNoTracking().Where(p => p.SourceUrlSlug == digitalSource.UrlSlug).ToArrayAsync(); foreach (var poem in poems) { int coupletCount = await context.GanjoorVerses.AsNoTracking() .Where(v => v.PoemId == poem.Id && (v.VersePosition == VersePosition.Right || v.VersePosition == VersePosition.CenteredVerse1) ).CountAsync(); digitalSource.CoupletsCount += coupletCount; if(!cats.Contains(poem.CatId)) { cats.Add(poem.CatId); } } totalCoupletsCount += digitalSource.CoupletsCount; digitalSourcesCats.Add(digitalSource.Id, cats); context.Update(digitalSource); await jobProgressServiceEF.UpdateJob(job.Id, 50, digitalSource.FullName); } var noSourceUrlPoems = await context.GanjoorPoems.AsNoTracking().Where(p => string.IsNullOrEmpty(p.SourceUrlSlug)).ToArrayAsync(); int untaggaed = 0; foreach (var noSourceUrlPoem in noSourceUrlPoems) { int coupletCount = await context.GanjoorVerses.AsNoTracking() .Where(v => v.PoemId == noSourceUrlPoem.Id && (v.VersePosition == VersePosition.Right || v.VersePosition == VersePosition.CenteredVerse1) ).CountAsync(); totalCoupletsCount += coupletCount; untaggaed += coupletCount; } //now rebuild /sources page contents await jobProgressServiceEF.UpdateJob(job.Id, 75, "Rebuild Sources Page"); var sources = await context.DigitalSources.AsNoTracking().Where(d => d.CoupletsCount > 0).OrderByDescending(d => d.CoupletsCount).ToListAsync(); int totalCount = sources.Sum(s => s.CoupletsCount); string htmlText = $"

بخش عمدهٔ محتوای گنجور که در حال حاضر شامل {LanguageUtils.FormatMoney(totalCount)} بیت شعر است از نرم‌افزارها و وبگاه‌های دیگر وارد شده است و در این زمینه علاقمندان ادبیات مدیون بزرگوارانی هستند که پیش و بیش از گنجور روی دیجیتالی کردن میراث ادب ایران‌زمین سرمایه‌گذاری کرده‌اند. آمار زیر نشان دهندهٔ ترکیب محتوای گنجور بر اساس نوع منبع دیجیتالی شدن آنهاست.

{Environment.NewLine}"; htmlText += $"{Environment.NewLine}" + $"{Environment.NewLine}" + $"{Environment.NewLine}" + $"{Environment.NewLine}" + $"{Environment.NewLine}" + $"{Environment.NewLine}" + $"{Environment.NewLine}"; var sourcesByType = await context.DigitalSources.AsNoTracking().Where(d => d.CoupletsCount > 0).GroupBy(d => d.SourceType).Select(d => new { SourceType = d.Key, CoupletsCount = d.Sum(s => s.CoupletsCount) }).OrderByDescending(d => d.CoupletsCount).ToListAsync(); for (int i = 0; i < sourcesByType.Count; i++) { if (i % 2 == 0) htmlText += $"{Environment.NewLine}"; else htmlText += $"{Environment.NewLine}"; htmlText += $"{Environment.NewLine}"; htmlText += $"{Environment.NewLine}"; htmlText += $"{Environment.NewLine}"; htmlText += $"{Environment.NewLine}"; htmlText += $"{Environment.NewLine}"; } htmlText += $"
ردیفنوع منبعتعداد ابیاتدرصد از کل
{(i + 1).ToPersianNumbers()}{sourcesByType[i].SourceType}{LanguageUtils.FormatMoney(sourcesByType[i].CoupletsCount)}{(sourcesByType[i].CoupletsCount * 100.0 / totalCount).ToString("N2", new CultureInfo("fa-IR")).ToPersianNumbers()}
{Environment.NewLine}"; htmlText += $"

جدول زیر نشان‌دهندهٔ آمار ریز منابع دیجیتال گنجور است:

{Environment.NewLine}"; htmlText += $"{Environment.NewLine}" + $"{Environment.NewLine}" + $"{Environment.NewLine}" + $"{Environment.NewLine}" + $"{Environment.NewLine}" + $"{Environment.NewLine}" + $"{Environment.NewLine}"; for (int i = 0; i < sources.Count; i++) { if (i % 2 == 0) htmlText += $"{Environment.NewLine}"; else htmlText += $"{Environment.NewLine}"; htmlText += $"{Environment.NewLine}"; htmlText += $"{Environment.NewLine}"; htmlText += $"{Environment.NewLine}"; htmlText += $"{Environment.NewLine}"; htmlText += $"{Environment.NewLine}"; } htmlText += $"
ردیفنام منبعتعداد ابیاتدرصد از کل
{(i + 1).ToPersianNumbers()}{sources[i].FullName}{LanguageUtils.FormatMoney(sources[i].CoupletsCount)}{(sources[i].CoupletsCount * 100.0 / totalCount).ToString("N2", new CultureInfo("fa-IR")).ToPersianNumbers()}
{Environment.NewLine}"; var dbPage = await context.GanjoorPages.Where(p => p.FullUrl == "/sources").SingleAsync(); await _UpdatePageHtmlText(context, editingUserId, dbPage, "به روزرسانی خودکار صفحهٔ آمار منابع", htmlText); await jobProgressServiceEF.UpdateJob(job.Id, 80, "Rebuild Sources SubPages"); foreach (var digitalSource in digitalSources) { List includedCats = new List(); foreach (var catId in digitalSourcesCats[digitalSource.Id]) { var resCat = await _GetCatById(context, catId, false, false, false); var cat = resCat.Result.Cat; if(cat.Ancestors.Any()) { var lastParent = cat.Ancestors.Last(); if (includedCats.Any(f => f.Id == lastParent.Id)) continue; var resParent = await _GetCatById(context, lastParent.Id, false, false, false); var parent = resParent.Result.Cat; bool includesAllChildren = true; foreach (var child in parent.Children) { if(!digitalSourcesCats[digitalSource.Id].Contains(child.Id)) { includesAllChildren = false; break; } } if(includesAllChildren) { includedCats.Add(parent); } else { includedCats.Add(cat); } } else { includedCats.Add(cat); } } List finalCats = new List(); foreach (var cat in includedCats) { if(!cat.Ancestors.Any()) { finalCats.Add(cat); } else { var thisCat = cat; var lastParent = cat.Ancestors.Last(); if(lastParent != null) { var resParent = await _GetCatById(context, lastParent.Id, false, false, false); var parent = resParent.Result.Cat; while (parent != null) { bool includesAllChildren = false; foreach (var child in parent.Children) { if (!includedCats.Any(c => c.Id == child.Id)) { includesAllChildren = true; break; } } if (includesAllChildren) { thisCat = parent; lastParent = thisCat.Ancestors.Last(); if(lastParent == null) { break; } resParent = await _GetCatById(context, lastParent.Id, false, false, false); parent = resParent.Result.Cat; } else { break; } } } finalCats.Add(thisCat); } } var dbPageDigitalPage = await context.GanjoorPages.Where(p => p.FullUrl == $"/sources/{digitalSource.UrlSlug}").FirstOrDefaultAsync(); if(dbPageDigitalPage != null) { string commentTag = $"{Environment.NewLine}{Environment.NewLine}"; if (dbPageDigitalPage.HtmlText.Contains(commentTag)) { htmlText = dbPageDigitalPage.HtmlText.Substring(0, dbPageDigitalPage.HtmlText.IndexOf(commentTag)); } else { htmlText = dbPageDigitalPage.HtmlText; } htmlText += commentTag; htmlText += $"

{digitalSource.FullName} منبع دیجیتال {LanguageUtils.FormatMoney(digitalSource.CoupletsCount)} بیت شعر بخش‌های زیر است:

{Environment.NewLine}"; htmlText += $"{Environment.NewLine}" + $"{Environment.NewLine}" + $"{Environment.NewLine}" + $"{Environment.NewLine}" + $"{Environment.NewLine}"; int rowIndex = 0; foreach (var cat in finalCats) { if (rowIndex % 2 == 0) htmlText += $"{Environment.NewLine}"; else htmlText += $"{Environment.NewLine}"; htmlText += $"{Environment.NewLine}"; htmlText += $"{Environment.NewLine}"; htmlText += $"{Environment.NewLine}"; rowIndex++; } htmlText += $"
ردیفنام بخش
{(rowIndex + 1).ToPersianNumbers()}{cat.Title}
{Environment.NewLine}"; await _UpdatePageHtmlText(context, editingUserId, dbPageDigitalPage, "به روزرسانی خودکار صفحهٔ آمار منابع", htmlText); } } await jobProgressServiceEF.UpdateJob(job.Id, 100, $"total: {totalCoupletsCount} - untagged: {untaggaed}", true); } catch (Exception exp) { await jobProgressServiceEF.UpdateJob(job.Id, 100, "", false, exp.ToString()); } } }); } } }