divan/DiwanRazor/Pages/Simi.cshtml.cs
Anas Rashid 020b010483 Urdu public pages, batch 2 (#2): auth, errors, map, FAQ, similar poems, people pages, page titles
- translate remaining public views and page-model strings (titles, messages, relation names)
- Urdu stopword list for word-frequency stats (replaces Persian list)
- error pages: drop list of alternative Ganjoor services

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 00:22:09 +02:00

466 lines
17 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using DNTPersianUtils.Core;
using DiwanRazor.Utils;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OutputCaching;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RMuseum.Models.Diwan;
using RMuseum.Models.Diwan.ViewModels;
using RMuseum.Services.Implementation;
using RMuseum.Utils;
using RSecurityBackend.Models.Generic;
namespace DiwanRazor.Pages
{
[OutputCache(PolicyName = "DiwanPublicPage")]
public class SimiModel : LoginPartialEnabledPageModel
{
private readonly PoetCacheService _poetCache;
/// <summary>
/// constructor
/// </summary>
public SimiModel(HttpClient httpClient, IConfiguration configuration, PoetCacheService poetCache) : base(httpClient, configuration)
{
_poetCache = poetCache;
}
public List<DiwanPoetViewModel> Poets { get; set; }
public int PoetId { get; set; }
public int CatId { get; set; }
public string CatFullTitle { get; set; }
public string CatFullUrl { get; set; }
public string Metre { get; set; }
public string Rhyme { get; set; }
public int CoupletCountsFrom { get; set; }
public int CoupletCountsTo { get; set; }
public DiwanLanguage[] Languages { get; set; }
public DiwanPoetCompleteViewModel Poet { get; set; }
public List<DiwanPoemCompleteViewModel> Poems { get; set; }
public string PagingToolsHtml { get; set; }
public PaginationMetadata PaginationMetadata { get; set; }
public string LastError { get; set; }
public string Language { get; set; }
public DiwanPoemFormat Format { get; set; }
public string Query { get; set; }
public bool Quoted { get; set; }
public bool ExactSearch { get; set; }
public int[] ExceptPoetId { get; set; }
/// <summary>
/// can edit
/// </summary>
public bool CanEdit { get; set; }
private async Task ReadLanguagesAsync()
{
HttpResponseMessage response = await _httpClient.GetAsync($"{APIRoot.Url}/api/translations/languages");
if (!response.IsSuccessStatusCode)
{
LastError = await ReadErrorMessageAsync(response);
return;
}
Languages = JsonConvert.DeserializeObject<DiwanLanguage[]>(await response.Content.ReadAsStringAsync());
}
/// <summary>
/// rhythms alphabetically
/// </summary>
public DiwanMetre[] RhythmsAlphabetically { get; set; }
/// <summary>
/// rhythms by frequency
/// </summary>
public DiwanMetre[] RhythmsByVerseCount { get; set; }
public async Task<IActionResult> 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 async Task<IActionResult> OnGetAsync()
{
var maintenanceResult = TryGetMaintenanceModeResult();
if (maintenanceResult != null)
{
return maintenanceResult;
}
bool anyParamsGiven = false;
InitializeCommonPageState();
CanEdit = Request.Cookies["CanEdit"] == "True";
PoetId = string.IsNullOrEmpty(Request.Query["a"]) ? 0 : int.Parse(Request.Query["a"]);
CatId = string.IsNullOrEmpty(Request.Query["c"]) ? 0 : int.Parse(Request.Query["c"]);
anyParamsGiven |= PoetId != 0;
Language = Request.Query["l"];
anyParamsGiven |= Language != null;
Language ??= "ur-PK";
string f = Request.Query["f"];
anyParamsGiven |= f != null;
Format = DiwanPoemFormat.Unknown;
if (f != null)
{
Format = (DiwanPoemFormat)int.Parse(f);
}
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(" ");
//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;
await ReadLanguagesAsync();
if (PoetId != 0)
{
var (poetOk, poet, poetError) = await _poetCache.GetPoetAsync(PoetId, EditorCacheBypass);
if (!poetOk)
{
LastError = poetError;
return Page();
}
Poet = poet;
}
// 2. search verses
var rhythmResponse = await _httpClient.GetAsync($"{APIRoot.Url}/api/diwan/rhythms?sortOnVerseCount=true");
if (!rhythmResponse.IsSuccessStatusCode)
{
LastError = await ReadErrorMessageAsync(rhythmResponse);
return Page();
}
RhythmsByVerseCount = JsonConvert.DeserializeObject<DiwanMetre[]>(await rhythmResponse.Content.ReadAsStringAsync());
List<DiwanMetre> rhythmsByVerseCount = new List<DiwanMetre>(RhythmsByVerseCount);
rhythmsByVerseCount.Sort((a, b) => a.Rhythm.CompareTo(b.Rhythm));
rhythmsByVerseCount.Insert(0, new DiwanMetre()
{
Rhythm = "null"
}
);
rhythmsByVerseCount.Insert(0, new DiwanMetre()
{
Rhythm = ""
}
);
RhythmsAlphabetically = rhythmsByVerseCount.ToArray();
int pageNumber = 1;
if (!string.IsNullOrEmpty(Request.Query["page"]))
{
pageNumber = int.Parse(Request.Query["page"]);
}
Metre = Request.Query["v"];
Rhyme = Request.Query["g"];
anyParamsGiven |= Metre != null;
anyParamsGiven |= Rhyme != null;
Metre ??= "";
Rhyme ??= "";
if (!string.IsNullOrEmpty(Rhyme))
{
Rhyme = Rhyme.Replace(" ", "");
}
CoupletCountsFrom = 0;
if (!string.IsNullOrEmpty(Request.Query["c1"]))
{
if (int.TryParse(Request.Query["c1"], out int i))
{
CoupletCountsFrom = i;
anyParamsGiven = anyParamsGiven || CoupletCountsFrom != 0;
}
}
CoupletCountsTo = 0;
if (!string.IsNullOrEmpty(Request.Query["c2"]))
{
if (int.TryParse(Request.Query["c2"], out int i))
{
CoupletCountsTo = i;
anyParamsGiven = anyParamsGiven || CoupletCountsTo != 0;
}
}
if (!anyParamsGiven)
{
ViewData["Title"] = $"دیوان » ملتی جلتی تخلیقات";
return Page();
}
string title = "اشعار ";
if (PoetId != 0)
{
var poetInfo = Poets.Where(p => p.Id == PoetId).SingleOrDefault();
if (poetInfo != null)
{
title += $"{poetInfo.Nickname} ";
}
}
if (!string.IsNullOrEmpty(Metre))
{
title += $"بحر: «{Metre}»";
}
if (!string.IsNullOrEmpty(Rhyme))
{
if (!string.IsNullOrEmpty(Metre))
{
title += $" و";
}
else
{
title += $"با";
}
title += $" حروفِ قافیہ: «{Rhyme}»";
}
if (Language != "ur-PK")
{
var langModel = Languages.Where(l => l.Code == Language).FirstOrDefault();
if (langModel != null)
{
title += $" غالب زبان: «{langModel.Name}»";
}
}
if (Format != DiwanPoemFormat.Unknown)
{
title += $" صنف: «{DiwanPoemFormatConvertor.GetString(Format)}»";
}
if (CoupletCountsFrom != 0)
{
title += $" اشعار کی کم از کم تعداد «{CoupletCountsFrom.ToPersianNumbers()}»";
}
if (CoupletCountsTo != 0)
{
title += $" اشعار کی زیادہ سے زیادہ تعداد «{CoupletCountsTo.ToPersianNumbers()}»";
}
if (CatId != 0)
{
var catResponse = await _httpClient.GetAsync($"{APIRoot.Url}/api/diwan/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<DiwanPoetCompleteViewModel>();
CatFullUrl = cat.Cat.FullUrl;
CatFullTitle = "";
foreach (var parentCat in cat.Cat.Ancestors)
{
CatFullTitle += parentCat.Title;
CatFullTitle += " »";
}
CatFullTitle += " " + cat.Cat.Title;
title += $" حصے میں {CatFullTitle}";
}
}
else
{
CatFullUrl = "";
CatFullTitle = "";
}
if (!string.IsNullOrEmpty(Query))
{
title += $" کلیدی لفظ: «{Query}»";
}
List<int> exceptPoetId = new List<int>();
foreach (var e in Request.Query["e"])
{
exceptPoetId.Add(int.Parse(e));
}
ExceptPoetId = exceptPoetId.ToArray();
string url = $"{APIRoot.Url}/api/diwan/poems/similar?PageNumber={pageNumber}&PageSize=20&metre={Metre}&rhyme={Rhyme}&poetId={PoetId}&catId={CatId}&language={Language}&format={(int)Format}&coupletCountsFrom={CoupletCountsFrom}&coupletCountsTo={CoupletCountsTo}";
if (!string.IsNullOrEmpty(Query))
{
url += $"&term={Query}";
}
string exceptUrl = "";
foreach (var e in exceptPoetId)
{
exceptUrl += $"&e={e}";
}
url += exceptUrl;
var response = await _httpClient.GetAsync(url);
if (!response.IsSuccessStatusCode)
{
LastError = await ReadErrorMessageAsync(response);
return Page();
}
Poems = JArray.Parse(await response.Content.ReadAsStringAsync()).ToObject<List<DiwanPoemCompleteViewModel>>();
foreach (var poem in Poems)
{
poem.HtmlText = DiwanPoemTools.GetPoemHtmlExcerpt(poem.HtmlText);
}
string paginnationMetadata = response.Headers.GetValues("paging-headers").FirstOrDefault();
PaginationMetadata = JsonConvert.DeserializeObject<PaginationMetadata>(paginnationMetadata);
string htmlText = "";
if (PaginationMetadata.totalPages > 1)
{
htmlText = $"<div>{Environment.NewLine}";
string authorParam = PoetId != 0 ? $"&amp;a={PoetId}" : "";
if (authorParam != "" && CatId != 0)
{
authorParam += $"&amp;c={CatId}";
}
title += $" - صفحہ {pageNumber.ToPersianNumbers()}";
if (PaginationMetadata.currentPage > 3)
{
htmlText += $"<a href=\"/simi/?v={Uri.EscapeDataString(Metre)}&amp;g={Uri.EscapeDataString(Rhyme)}&amp;page=1{authorParam}&amp;l={Language}&amp;f={(int)Format}&amp;c1={CoupletCountsFrom}&amp;c2={CoupletCountsTo}{exceptUrl}\"><div class=\"circled-number\">۱</div></a> …";
}
for (int i = PaginationMetadata.currentPage - 2; i <= (PaginationMetadata.currentPage + 2); i++)
{
if (i >= 1 && i <= PaginationMetadata.totalPages)
{
if (i == PaginationMetadata.currentPage)
{
htmlText += $"<div class=\"circled-number-diff\">{i.ToPersianNumbers()}</div>{Environment.NewLine}";
}
else
{
htmlText += $"<a href=\"/simi/?v={Uri.EscapeDataString(Metre)}&amp;g={Uri.EscapeDataString(Rhyme)}&amp;page={i}{authorParam}&amp;l={Language}&amp;f={(int)Format}&amp;c1={CoupletCountsFrom}&amp;c2={CoupletCountsTo}{exceptUrl}\"><div class=\"circled-number\">{i.ToPersianNumbers()}</div></a>{Environment.NewLine}";
}
}
}
if (PaginationMetadata.totalPages > (PaginationMetadata.currentPage + 2))
{
htmlText += $"… <a href=\"/simi/?v={Uri.EscapeDataString(Metre)}&amp;g={Uri.EscapeDataString(Rhyme)}&amp;page={PaginationMetadata.totalPages}{authorParam}&amp;l={Language}&amp;f={(int)Format}&amp;c1={CoupletCountsFrom}&amp;c2={CoupletCountsTo}{exceptUrl}\"><div class=\"circled-number\">{PaginationMetadata.totalPages.ToPersianNumbers()}</div></a>{Environment.NewLine}";
}
htmlText += $"</div>{Environment.NewLine}";
}
ViewData["Title"] = $"دیوان » {title}";
PagingToolsHtml = htmlText;
return Page();
}
public string HtmlText { get; set; }
public Task<IActionResult> OnPostSendSectionMetreSuggestionAsync(int poemId, int sectionIndex, string rhythm)
{
return WithSecureClientAsync(async secureClient =>
{
if (rhythm == "null")
rhythm = "";
if (string.IsNullOrEmpty(rhythm))
{
return new BadRequestObjectResult("بحر منتخب نہیں");
}
var sectionResponse = await secureClient.GetAsync($"{APIRoot.Url}/api/diwan/sections/{poemId}");
if (!sectionResponse.IsSuccessStatusCode)
{
return new BadRequestObjectResult(await ReadErrorMessageAsync(sectionResponse));
}
var sections = JsonConvert.DeserializeObject<DiwanPoemSection[]>(await sectionResponse.Content.ReadAsStringAsync());
var section = sections.Where(s => s.Index == sectionIndex).Single();
var correctionResponse = await secureClient.GetAsync($"{APIRoot.Url}/api/diwan/section/correction/last/{section.Id}");
if (!correctionResponse.IsSuccessStatusCode)
{
return new BadRequestObjectResult(await ReadErrorMessageAsync(correctionResponse));
}
if (null != JsonConvert.DeserializeObject<DiwanPoemSectionCorrectionViewModel>(await correctionResponse.Content.ReadAsStringAsync()))
{
return new BadRequestObjectResult("آپ اس حصے کے لیے پہلے ہی تصحیح تجویز کر چکے ہیں.");
}
DiwanPoemSectionCorrectionViewModel correction = new DiwanPoemSectionCorrectionViewModel()
{
SectionId = section.Id,
Rhythm = rhythm,
};
HttpResponseMessage response = await secureClient.PostAsync(
$"{APIRoot.Url}/api/diwan/section/correction",
new StringContent(JsonConvert.SerializeObject(correction),
Encoding.UTF8,
"application/json"));
if (!response.IsSuccessStatusCode)
{
return new BadRequestObjectResult(await ReadErrorMessageAsync(response));
}
return new OkObjectResult(true);
});
}
}
}