using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Text.RegularExpressions; using System.Threading.Tasks; using DNTPersianUtils.Core; using DivanRazor.Utils; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.OutputCaching; using Microsoft.Extensions.Configuration; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using RMuseum.Models.Divan.ViewModels; using RMuseum.Services.Implementation; using RSecurityBackend.Models.Generic; namespace DivanRazor.Pages { [OutputCache(PolicyName = "DivanPublicPage")] public class SearchModel : LoginPartialEnabledPageModel { private readonly PoetCacheService _poetCache; /// /// constructor /// public SearchModel(HttpClient httpClient, IConfiguration configuration, PoetCacheService poetCache) : base(httpClient, configuration) { _poetCache = poetCache; } public List Poets { get; set; } public string Query { get; set; } public bool QueryIsSingleWord { get { return !string.IsNullOrEmpty(Query) && Query.IndexOfAny([' ', '‌']) == -1; } } public int PoetId { get; set; } public int CatId { get; set; } public string CatFullTitle { get; set; } public string CatFullUrl { get; set; } public DivanPoetCompleteViewModel Poet { get; set; } public List Poems { get; set; } public PaginationMetadata PaginationMetadata { get; set; } public string PagingToolsHtml { get; set; } public string LastError { get; set; } public int[] ExceptPoetId { get; set; } public async Task OnGetPoetInformationAsync(int id) { if (id == 0) { return new OkObjectResult(null); } var (success, poet, error) = await _poetCache.GetPoetAsync(id, EditorCacheBypass); if (!success) { return BadRequest(error); } return new OkObjectResult(poet); } public string AlternativeSearchPhrase { get; set; } public string AlternativeSearchPhraseDescription { get; set; } public bool Quoted { get; set; } public bool ExactSearch { get; set; } public string QueryDin { get { return Query.ApplyCorrectYeKe().Trim().Replace("\"", ""); } } public bool StatsAtTop { get; set; } public async Task OnGetAsync() { var maintenanceResult = TryGetMaintenanceModeResult(); if (maintenanceResult != null) { return maintenanceResult; } InitializeCommonPageState(); Query = Request.Query["s"].ApplyCorrectYeKe().Trim(); ExactSearch = Request.Query["es"] == "1"; bool quotes = Query.IndexOf("\"") != -1 || ExactSearch; Query = LanguageUtils.MakeTextSearchable(Query); //replace zwnj with space if (quotes) Query = $"\"{Query}\""; Quoted = quotes && Query.Contains(" "); AlternativeSearchPhrase = Quoted ? WebUtility.UrlEncode(Query.Replace("\"", "")) : Query.Contains(" ") ? WebUtility.UrlEncode($"\"{Query}\"") : ""; AlternativeSearchPhraseDescription = ""; if (Quoted) { AlternativeSearchPhraseDescription = "مطمئن نہیں؟! "; bool needsComma = false; var splitteds = Query.Replace("\"", "").Split(' '); for (int sp = 0; sp < splitteds.Length - 1; sp++) { var splitted = splitteds[sp]; if (needsComma) AlternativeSearchPhraseDescription += "، "; AlternativeSearchPhraseDescription += $"«{splitted}»"; needsComma = true; } AlternativeSearchPhraseDescription += $" و «{splitteds[splitteds.Length - 1]}»"; AlternativeSearchPhraseDescription += " کو الفاظ کی ترتیب کے بغیر تلاش کریں."; } else if (Query.Contains(" ")) { AlternativeSearchPhraseDescription = $"مطمئن نہیں؟ عبارت «{Query}» کو بالکل اسی طرح تلاش کریں."; } PoetId = string.IsNullOrEmpty(Request.Query["author"]) ? 0 : int.Parse(Request.Query["author"]); CatId = PoetId == 0 ? 0 : string.IsNullOrEmpty(Request.Query["cat"]) ? 0 : int.Parse(Request.Query["cat"]); if (CatId != 0) { var catResponse = await _httpClient.GetAsync($"{APIRoot.Url}/api/divan/cat/{CatId}?poems=false&mainSections=false"); if (!catResponse.IsSuccessStatusCode) { LastError = await ReadErrorMessageAsync(catResponse); return Page(); } else { var cat = JObject.Parse(await catResponse.Content.ReadAsStringAsync()).ToObject(); CatFullUrl = cat.Cat.FullUrl; CatFullTitle = ""; foreach (var parentCat in cat.Cat.Ancestors) { CatFullTitle += parentCat.Title; CatFullTitle += " »"; } CatFullTitle += " " + cat.Cat.Title; } } else { CatFullUrl = ""; CatFullTitle = ""; } StatsAtTop = !string.IsNullOrEmpty(Request.Query["stats"]); //todo: use html master layout or make it partial // 1. poets var (poetsOk, poets, poetsError) = await _poetCache.GetPoetsAsync(EditorCacheBypass); if (!poetsOk) { LastError = poetsError; return Page(); } Poets = poets; var poetName = Poets.SingleOrDefault(p => p.Id == PoetId); if (poetName != null) { if (CatFullTitle != "") { ViewData["Title"] = $"دیوان » تلاش کے نتائج: {Query} حصے میں {CatFullTitle}"; } else { ViewData["Title"] = $"دیوان » تلاش کے نتائج: {Query} کلام میں: {poetName?.Name}"; } } else { if (!string.IsNullOrEmpty(Query)) { ViewData["Title"] = $"دیوان » تلاش کے نتائج: {Query}"; } else { ViewData["Title"] = $"دیوان » تلاش"; } } if (PoetId != 0) { var (poetOk, poet, poetError) = await _poetCache.GetPoetAsync(PoetId, EditorCacheBypass); if (!poetOk) { LastError = poetError; return Page(); } Poet = poet; } // 2. search verses int pageNumber = 1; if (!string.IsNullOrEmpty(Request.Query["page"])) { pageNumber = int.Parse(Request.Query["page"]); } if (pageNumber > 1) { ViewData["Title"] += $" - صفحہ {pageNumber.ToPersianNumbers()}"; } HttpResponseMessage searchQueryResponse = null; List exceptPoetId = new List(); foreach (var e in Request.Query["e"]) { exceptPoetId.Add(int.Parse(e)); } ExceptPoetId = exceptPoetId.ToArray(); string exceptUrl = ""; if (!string.IsNullOrEmpty(Query)) { string url = $"{APIRoot.Url}/api/divan/poems/search?term={Query}&poetId={PoetId}&catId={CatId}&PageNumber={pageNumber}&PageSize=20"; foreach (var e in exceptPoetId) { exceptUrl += $"&e={e}"; } url += exceptUrl; searchQueryResponse = await _httpClient.GetAsync(url); if (!searchQueryResponse.IsSuccessStatusCode) { LastError = await ReadErrorMessageAsync(searchQueryResponse); return Page(); } Poems = JArray.Parse(await searchQueryResponse.Content.ReadAsStringAsync()).ToObject>(); } if (Poems != null && Poems.Count == 0) { Poems = null; } if (Poems != null) { // highlight searched word string[] queryParts = Query.IndexOf('"') == 0 && Query.LastIndexOf('"') == (Query.Length - 1) ? new string[] { Query.Replace("\"", "") } : Query.Replace("\"", "").Split(' ', StringSplitOptions.RemoveEmptyEntries); foreach (var poem in Poems) { string[] lines = poem.PlainText.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries); List linesInExcerpt = new List(); for (int i = 0; i < lines.Length; i++) { foreach (var queryPart in queryParts) { if (lines[i].IndexOf(queryPart) != -1) { if (i > 0) { if (linesInExcerpt.IndexOf(i - 1) == -1) { linesInExcerpt.Add(i - 1); } } if (linesInExcerpt.IndexOf(i) == -1) { linesInExcerpt.Add(i); } if (i < (lines.Length - 1)) linesInExcerpt.Add(i + 1); break; } } } string plainText = ""; for (int i = 0; i < linesInExcerpt.Count; i++) { if (linesInExcerpt[i] > 0 && linesInExcerpt.IndexOf(linesInExcerpt[i] - 1) == -1) plainText += "... "; plainText += $"{lines[linesInExcerpt[i]]}"; if (linesInExcerpt[i] < (lines.Length - 1) && linesInExcerpt.IndexOf(linesInExcerpt[i] + 1) == -1) plainText += " ..."; plainText += $"{Environment.NewLine}"; } string finalPlainText = ""; foreach (string line in plainText.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries)) { finalPlainText += $"

{line}

"; } if (linesInExcerpt.Count > 0) { poem.PlainText = finalPlainText; } for (int i = 0; i < queryParts.Length; i++) { string cssClass = i % 3 == 0 ? "hilite" : i % 3 == 1 ? "hilite2" : "hilite3"; poem.PlainText = Regex.Replace(poem.PlainText, queryParts[i], $"{queryParts[i]}", RegexOptions.IgnoreCase | RegexOptions.RightToLeft); ; } } if (searchQueryResponse != null) { string paginationMetadataJsonValue = searchQueryResponse.Headers.GetValues("paging-headers").FirstOrDefault(); if (!string.IsNullOrEmpty(paginationMetadataJsonValue)) { PaginationMetadata = JsonConvert.DeserializeObject(paginationMetadataJsonValue); string catQuery = ""; if (!string.IsNullOrEmpty(Request.Query["cat"])) { catQuery = $"&cat={Request.Query["cat"]}"; } PagingToolsHtml = GeneratePagingBarHtml(PaginationMetadata, $"/search?s={WebUtility.UrlEncode(Query)}&author={PoetId}{catQuery}{exceptUrl}"); } } } return Page(); } private string GeneratePagingBarHtml(PaginationMetadata paginationMetadata, string routeStartWithQueryStrings) { string htmlText = $"
{Environment.NewLine}"; if (paginationMetadata != null && paginationMetadata.totalPages > 1) { if (paginationMetadata.currentPage > 3) { htmlText += $"
۱
{Environment.NewLine} …"; } for (int i = paginationMetadata.currentPage - 2; i <= (paginationMetadata.currentPage + 2); i++) { if (i >= 1 && i <= paginationMetadata.totalPages) { if (i == paginationMetadata.currentPage) { htmlText += $"
{i.ToPersianNumbers()}
"; } else { htmlText += $"
{i.ToPersianNumbers()}
{Environment.NewLine}"; } } } if (paginationMetadata.totalPages > (paginationMetadata.currentPage + 2)) { htmlText += $"…
{paginationMetadata.totalPages.ToPersianNumbers()}
{Environment.NewLine}"; } } htmlText += $"
{Environment.NewLine}"; return htmlText; } public async Task OnGetWordCountsByPoetAsync(string term, int poetId, int catId, bool blur) { if (term == null) return new BadRequestObjectResult("term is null"); term = term.Replace("\"", ""); if (!string.IsNullOrEmpty(term)) { term = term.Trim(); } else { if (term == null) return new BadRequestObjectResult("term is empty"); } string url = $"{APIRoot.Url}/api/divan/wordcounts/bycat?term={term}"; if (poetId != 0) { url += $"&poetId={poetId}"; } if (catId != 0) { url += $"&catId={catId}"; } var wordCountsResponse = await _httpClient.GetAsync(url); if (!wordCountsResponse.IsSuccessStatusCode) { return new BadRequestObjectResult(await ReadErrorMessageAsync(wordCountsResponse)); } var wordCounts = JsonConvert.DeserializeObject(await wordCountsResponse.Content.ReadAsStringAsync()); string countStr = wordCountsResponse.Headers.GetValues("items-count").FirstOrDefault(); return Partial("~/Pages/Partials/Search/_CategoryWordsCountByCatPartial.cshtml", new _CategoryWordsCountByCatPartialModel() { Term = term, WordStats = wordCounts, Whole = catId == 0 && poetId == 0, TotalCount = string.IsNullOrEmpty(countStr) ? 0 : int.Parse(countStr), Blur = blur, }); } } }