divan/GanjooRazor/Pages/GanjoorPage.cshtml.cs
Hamid Reza Mohammadi 4007f93cc4 #495 comment ratings
2026-08-04 18:32:26 +03:30

1429 lines
63 KiB
C#
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 DNTPersianUtils.Core;
using GanjooRazor.Utils;
using KontorService.Models.Reporting.ViewModels;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RMuseum.Models.Ganjoor;
using RMuseum.Models.Ganjoor.ViewModels;
using RMuseum.Models.GanjoorAudio;
using RMuseum.Models.GanjoorAudio.ViewModels;
using RMuseum.Services.Implementation;
using RMuseum.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace GanjooRazor.Pages
{
/// <summary>
/// Renders a single Ganjoor content page (poem/poet/category). Split out of IndexModel, which
/// used to serve both this and the home page from one class dispatching on
/// Request.Path == "/" - see _HomePagePartial.cshtml / _GanjoorPagePartial.cshtml, and
/// Startup.cs's AddPageRoute("/GanjoorPage", "{*url}") which now owns the site's catch-all route
/// (Index.cshtml keeps its own automatic "/" route unchanged, so home is unaffected).
/// </summary>
[IgnoreAntiforgeryToken(Order = 1001)]
public partial class GanjoorPageModel : LoginPartialEnabledPageModel
{
/// <summary>
/// Persian stop words excluded from category word-count listings when remStopWords is
/// requested.
/// </summary>
private static readonly HashSet<string> _persianStopWords = new HashSet<string>
{
"و", "از", "که", "به", "در", "را", "ز", "است", "می", "این", "چون", "بود", "ای", "تا", "چو",
"هر", "با", "چه", "شد", "بی", "خود", "گفت", "نیست", "نه", "گر", "کند", "اگر", "کرد", "باشد",
"هم", "روی", "شود", "یک", "دو", "وی", "اندر", "پیش", "آمد", "دارد", "کن", "یا", "همی", "آید",
"کرده", "نمی", "کز", "هست", "ام", "کی", "بهر", "فی", "چنین", "پای", "ها", "اند", "ی", "گردد",
"داد", "چنان", "کنم", "نبود", "گشت", "دیگر", "باید", "دگر", "چند", "همچو", "شده", "بد", "زان",
"پی", "مگر", "آنکه", "رفت", "کنی", "برد", "بدان", "ست", "ازین", "دید", "وز", "گوید", "کجا",
"دهد", "گه", "درین", "آخر", "دارم", "خواهد", "نیز", "های", "چرا", "راست", "کان", "رو", "نباشد",
"بر", "من", "آن", "تو", "او", "ما", "شما", "مرا", "ار", "داری", "بیا", "همه", "گو", "مکن", "زد",
"گفتم",
};
private readonly PoetCacheService _poetCache;
public bool OfflineMode => GetConfigFlag("OfflineMode");
public bool ReadOnlyMode => GetConfigFlag("ReadOnlyMode");
public const int GanjoorSlashVaznPageId = 39401;
/// <summary>
/// constructor
/// </summary>
public GanjoorPageModel(IConfiguration configuration,
HttpClient httpClient,
PoetCacheService poetCache
) : base(httpClient, configuration)
{
_poetCache = poetCache;
}
/// <summary>
/// last error
/// </summary>
public string LastError { get; set; }
/// <summary>
/// banner
/// </summary>
public GanjoorSiteBannerViewModel Banner { get; set; }
/// <summary>
/// If the response failed, stores the API's error message in <see cref="LastError"/> and
/// returns true so the caller can short-circuit (the established pattern here is
/// `if (await CaptureErrorIfFailedAsync(response)) return Page();`).
/// </summary>
private async Task<bool> CaptureErrorIfFailedAsync(HttpResponseMessage response)
{
if (response.IsSuccessStatusCode)
{
return false;
}
LastError = await ReadErrorMessageAsync(response);
return true;
}
public _CommentPartialModel GetCommentModel(GanjoorCommentSummaryViewModel comment, int poemId)
{
return new _CommentPartialModel()
{
Comment = comment,
Error = "",
InReplyTo = null,
LoggedIn = LoggedIn,
DivSuffix = "",
PoemId = poemId,
};
}
public _AudioPlayerPartialModel GetRecitationsModel(PublicRecitationViewModel[] recitations, bool minimumControls, RecitationType recitationType, bool isAdmin)
{
return new _AudioPlayerPartialModel()
{
LoggedIn = LoggedIn,
Recitations = recitations.Where(a => a.RecitationType == recitationType).ToArray(),
ShowAllRecitaions = minimumControls ? true : ShowAllRecitaions,
CategoryMode = minimumControls,
RecitationType = recitationType,
IsAdmin = isAdmin,
};
}
public _QuotedPoemPartialModel GetQuotedPoemModel(GanjoorQuotedPoemViewModel quotedPoem, GanjoorPageCompleteViewModel page, bool canEdit)
{
return new _QuotedPoemPartialModel()
{
GanjoorQuotedPoemViewModel = quotedPoem,
PoetImageUrl = page.PoetOrCat.Poet.ImageUrl,
PoetNickName = page.PoetOrCat.Poet.Nickname,
CanEdit = canEdit,
};
}
public Task<IActionResult> OnPostReply(string replyCommentText, int refPoemId, int refCommentId)
{
return OnPostComment(replyCommentText, refPoemId, refCommentId, -1);
}
/// <summary>
/// comment
/// </summary>
public Task<IActionResult> OnPostComment(string comment, int poemId, int inReplytoId, int coupletIndex)
{
var unauthorized = Partial("~/Pages/Partials/GanjoorPage/_CommentPartial.cshtml", new _CommentPartialModel()
{
Comment = null,
Error = NotLoggedInMessage,
InReplyTo = null
});
return WithSecureClientAsync(async secureClient =>
{
var stringContent = new StringContent(
JsonConvert.SerializeObject(new GanjoorCommentPostViewModel()
{
HtmlComment = comment,
InReplyToId = inReplytoId == 0 ? null : inReplytoId,
PoemId = poemId,
CoupletIndex = coupletIndex == -1 ? null : coupletIndex
}),
Encoding.UTF8, "application/json");
var response = await secureClient.PostAsync($"{APIRoot.Url}/api/ganjoor/comment", stringContent);
if (response.StatusCode == HttpStatusCode.OK)
{
var resComment = JsonConvert.DeserializeObject<GanjoorCommentSummaryViewModel>(await response.Content.ReadAsStringAsync());
resComment.MyComment = true;
return Partial("~/Pages/Partials/GanjoorPage/_CommentPartial.cshtml", new _CommentPartialModel()
{
Comment = resComment,
Error = "",
InReplyTo = inReplytoId == 0 ? null : new GanjoorCommentSummaryViewModel(),
LoggedIn = !string.IsNullOrEmpty(Request.Cookies["Token"]),
PoemId = poemId,
});
}
return Partial("~/Pages/Partials/GanjoorPage/_CommentPartial.cshtml", new _CommentPartialModel()
{
Comment = null,
Error = await ReadErrorMessageAsync(response),
InReplyTo = null,
LoggedIn = !string.IsNullOrEmpty(Request.Cookies["Token"]),
PoemId = poemId,
});
}, unauthorized);
}
public Task<IActionResult> OnDeleteMyComment(int id)
{
return WithSecureClientAsync(async secureClient =>
{
var response = await secureClient.DeleteAsync($"{APIRoot.Url}/api/ganjoor/comment?id={id}");
if (!response.IsSuccessStatusCode)
{
return new BadRequestObjectResult(await ReadErrorMessageAsync(response));
}
return new JsonResult(true);
});
}
public Task<IActionResult> OnPutMyComment(int id, string comment)
{
return WithSecureClientAsync(async secureClient =>
{
var response = await secureClient.PutAsync($"{APIRoot.Url}/api/ganjoor/comment/{id}", new StringContent(JsonConvert.SerializeObject(comment), Encoding.UTF8, "application/json"));
if (!response.IsSuccessStatusCode)
{
return new BadRequestObjectResult(await ReadErrorMessageAsync(response));
}
return new JsonResult(true);
});
}
/// <summary>
/// like / dislike / clear rating for a comment (AJAX, called from rateComment() in bk.js)
/// </summary>
public Task<IActionResult> OnPostRateCommentAsync(int id, short value)
{
return WithSecureClientAsync(async secureClient =>
{
var response = await secureClient.PostAsync($"{APIRoot.Url}/api/ganjoor/poem/comment/{id}/rate?value={value}", null);
if (!response.IsSuccessStatusCode)
{
return new BadRequestObjectResult(await ReadErrorMessageAsync(response));
}
var result = JsonConvert.DeserializeObject<GanjoorCommentRatingResultViewModel>(await response.Content.ReadAsStringAsync());
return new JsonResult(result);
});
}
/// <summary>
/// Poets (for this page's own #hdr2 author dropdown - same pattern as Search/Simi/etc.)
/// </summary>
public List<GanjoorPoetViewModel> Poets { get; set; }
public bool IsPoetPage { get; set; }
public bool IsCatPage { get; set; }
public bool IsPoemPage { get; set; }
public string CanonicalUrl => $"{Configuration["SiteUrl"]}{GanjoorPage.FullUrl}";
public bool CanEdit { get; set; }
public bool KeepHistory { get; set; }
public string PinterestUrl { get; set; }
public bool ShowAllRecitaions { get; set; }
public string ActiveTab { get; set; }
private void _preparePoemExcerpt(GanjoorPoemSummaryViewModel poem)
{
if (poem == null || poem.Excerpt == null)
{
return;
}
if (poem.Excerpt.Length > 100)
{
poem.Excerpt = poem.Excerpt.Substring(0, 50);
int n = poem.Excerpt.LastIndexOf(' ');
if (n >= 0)
{
poem.Excerpt = poem.Excerpt.Substring(0, n) + " ...";
}
else
{
poem.Excerpt += "...";
}
}
}
/// <summary>
/// specify which comments belong to current user
/// </summary>
private async Task _markMyCommentsAndBringUpMyRecitations()
{
if (GanjoorPage == null)
{
return;
}
if (GanjoorPage.Poem == null)
{
return;
}
if (string.IsNullOrEmpty(Request.Cookies["UserId"]))
{
return;
}
if (!Guid.TryParse(Request.Cookies["UserId"], out Guid userId))
{
return;
}
if (userId == Guid.Empty)
{
return;
}
foreach (GanjoorCommentSummaryViewModel comment in GanjoorPage.Poem.Comments)
{
comment.MyComment = comment.UserId == userId;
_markMyReplies(comment, userId, null);
}
if (GanjoorPage.Poem.Recitations.Length > 0)
{
using (HttpClient secureClient = new HttpClient())
{
if (await GanjoorSessionChecker.PrepareClient(secureClient, Request, Response))
{
HttpResponseMessage response = await secureClient.GetAsync($"{APIRoot.Url}/api/ganjoor/poem/{GanjoorPage.Poem.Id}/recitations/upvotes");
if (response.IsSuccessStatusCode)
{
var upVotedIds = JsonConvert.DeserializeObject<int[]>(await response.Content.ReadAsStringAsync());
if (upVotedIds.Length > 0)
{
foreach (var recitation in GanjoorPage.Poem.Recitations)
{
recitation.UpVotedByUser = upVotedIds.Contains(recitation.Id);
}
Array.Sort(GanjoorPage.Poem.Recitations, (a, b) => b.UpVotedByUser == a.UpVotedByUser ? a.AudioOrder.CompareTo(b.AudioOrder) : b.UpVotedByUser.CompareTo(a.UpVotedByUser));
}
}
}
}
}
if (GanjoorPage.Poem.Comments.Length > 0)
{
using (HttpClient secureClient = new HttpClient())
{
if (await GanjoorSessionChecker.PrepareClient(secureClient, Request, Response))
{
HttpResponseMessage response = await secureClient.GetAsync($"{APIRoot.Url}/api/ganjoor/poem/{GanjoorPage.Poem.Id}/comments/myratings");
if (response.IsSuccessStatusCode)
{
var ratings = JsonConvert.DeserializeObject<GanjoorCommentUserRatingViewModel[]>(await response.Content.ReadAsStringAsync());
if (ratings.Length > 0)
{
var ratingsDic = ratings.ToDictionary(r => r.CommentId, r => r.Value);
foreach (GanjoorCommentSummaryViewModel comment in GanjoorPage.Poem.Comments)
{
_applyCommentRatings(comment, ratingsDic);
}
}
}
}
}
}
}
private void _applyCommentRatings(GanjoorCommentSummaryViewModel comment, Dictionary<int, short> ratings)
{
if (ratings.TryGetValue(comment.Id, out short value))
{
comment.CurrentUserRatingValue = value;
}
foreach (var reply in comment.Replies)
{
_applyCommentRatings(reply, ratings);
}
}
private void _markMyReplies(GanjoorCommentSummaryViewModel parent, Guid userId, GanjoorUserBookmarkViewModel[] bookmarks)
{
foreach (var reply in parent.Replies)
{
reply.MyComment = reply.UserId == userId;
if (bookmarks != null)
reply.IsBookmarked = bookmarks.Where(b => b.CoupletIndex == -reply.Id).Any();
_markMyReplies(reply, userId, bookmarks);
}
}
/// <summary>
/// get audio description
/// </summary>
public string getAudioDesc(PublicRecitationViewModel recitation, bool contributionLink = false)
{
string audiodesc = "به خوانش ";
if (!string.IsNullOrEmpty(recitation.AudioArtistUrl))
{
audiodesc += $"<a href='{recitation.AudioArtistUrl}'>{recitation.AudioArtist}</a>";
}
else
{
audiodesc += $"{recitation.AudioArtist}";
}
if (!string.IsNullOrEmpty(recitation.AudioSrc))
{
if (!string.IsNullOrEmpty(recitation.AudioSrcUrl))
{
audiodesc += $" <a href='{recitation.AudioSrcUrl}'>{recitation.AudioSrc}</a>";
}
else
{
audiodesc += $" {recitation.AudioSrc}";
}
}
audiodesc += $" <small><a href='/AudioClip/?a={recitation.Id}' onclick='wpopen(this.href); return false' class='comments-link' title='دریافت'>(دریافت)</a></small>";
if (contributionLink)
{
audiodesc += "<br /> <small>می‌خواهید شما بخوانید؟ <a href='http://ava.ganjoor.net/about/'>اینجا</a> را ببینید.</small>";
}
return audiodesc;
}
private async Task<bool> preparePoets()
{
var (success, poets, error) = await _poetCache.GetPoetsAsync(AggressiveCacheEnabled);
if (!success)
{
LastError = error;
return false;
}
Poets = poets;
return true;
}
public async Task<IActionResult> OnGetPoetInformationAsync(int id)
{
if (id == 0)
{
return new OkObjectResult(null);
}
var (success, poet, error) = await _poetCache.GetPoetAsync(id, AggressiveCacheEnabled);
if (!success)
{
return BadRequest(error);
}
return new OkObjectResult(poet);
}
public string HtmlLanguage { get; set; } = "fa-IR";
private void _prepareNextPre()
{
switch (GanjoorPage.GanjoorPageType)
{
case GanjoorPageType.PoemPage:
{
if (GanjoorPage.Poem.Next != null)
{
NextUrl = GanjoorPage.PoetOrCat.Cat.FullUrl + "/" + GanjoorPage.Poem.Next.UrlSlug;
NextTitle = GanjoorPage.Poem.Next.Title + ": " + GanjoorPage.Poem.Next.Excerpt;
}
else
if (GanjoorPage.Poem.MixedModeOrder > 0
&& GanjoorPage.Poem.Category.Cat.Children.Where(c => c.MixedModeOrder == 0 || c.MixedModeOrder > GanjoorPage.Poem.MixedModeOrder).Any())
{
var nextCat = GanjoorPage.Poem.Category.Cat.Children.Where(c => c.MixedModeOrder == 0 || c.MixedModeOrder > GanjoorPage.Poem.MixedModeOrder).OrderBy(c => c.MixedModeOrder).First();
NextUrl = nextCat.FullUrl;
NextTitle = nextCat.Title;
}
else
if (GanjoorPage.Poem.Category.Cat.Next != null)
{
NextUrl = GanjoorPage.Poem.Category.Cat.Next.FullUrl;
NextTitle = GanjoorPage.Poem.Category.Cat.Next.Title;
}
if (GanjoorPage.Poem.Previous != null)
{
PreviousUrl = GanjoorPage.PoetOrCat.Cat.FullUrl + "/" + GanjoorPage.Poem.Previous.UrlSlug;
PreviousTitle = GanjoorPage.Poem.Previous.Title + ": " + GanjoorPage.Poem.Previous.Excerpt;
}
else
if (GanjoorPage.Poem.MixedModeOrder > 0
&& GanjoorPage.Poem.Category.Cat.Children.Where(c => c.MixedModeOrder != 0 && c.MixedModeOrder < GanjoorPage.Poem.MixedModeOrder).Any())
{
var prevCat = GanjoorPage.Poem.Category.Cat.Children.Where(c => c.MixedModeOrder != 0 && c.MixedModeOrder < GanjoorPage.Poem.MixedModeOrder).OrderByDescending(c => c.MixedModeOrder).First();
PreviousUrl = prevCat.FullUrl;
PreviousTitle = prevCat.Title;
}
else
if (GanjoorPage.Poem.Category.Cat.Previous != null)
{
PreviousUrl = GanjoorPage.Poem.Category.Cat.Previous.FullUrl;
PreviousTitle = GanjoorPage.Poem.Category.Cat.Previous.Title;
}
}
break;
case GanjoorPageType.CatPage:
{
if (GanjoorPage.PoetOrCat.Cat.Next != null)
{
NextUrl = GanjoorPage.PoetOrCat.Cat.Next.FullUrl;
NextTitle = GanjoorPage.PoetOrCat.Cat.Next.Title;
}
if (GanjoorPage.PoetOrCat.Cat.Previous != null)
{
PreviousUrl = GanjoorPage.PoetOrCat.Cat.Previous.FullUrl;
PreviousTitle = GanjoorPage.PoetOrCat.Cat.Previous.Title;
}
}
break;
}
}
public bool MutiPartPoemPage { get; set; }
private void _prepareRelatedSecions()
{
SectionsWithRelated = new List<GanjoorPoemSection>();
SectionsWithMetreAndRhymes = new List<GanjoorPoemSection>();
MutiPartPoemPage = GanjoorPage.Poem.Verses.Where(v => v.VersePosition == VersePosition.Paragraph || v.VersePosition == VersePosition.Single).Any()
||
GanjoorPage.Poem.Sections.Count(s => s.SectionType == PoemSectionType.WholePoem && s.VerseType == VersePoemSectionType.First) != 1;
if (
!MutiPartPoemPage
)
{
foreach (var section in GanjoorPage.Poem.Sections)
{
if (section.Top6RelatedSections.Length > 0)
{
SectionsWithRelated.Add(section);
}
if (section.SectionType == PoemSectionType.WholePoem && section.GanjoorMetre != null && !string.IsNullOrEmpty(section.RhymeLetters))
{
SectionsWithMetreAndRhymes.Add(section);
}
}
}
}
public GanjoorPoetSuggestedPictureViewModel Photo { get; set; }
/// <summary>
/// Get. Unlike the old IndexModel.OnGetAsync, this never needs to check
/// Request.Path == "/" - routing guarantees this page never receives that request, since
/// Index.cshtml's own automatic "/" route always takes precedence over this page's
/// catch-all for a request to "/".
/// </summary>
public async Task<IActionResult> OnGetAsync()
{
var maintenanceResult = TryGetMaintenanceModeResult();
if (maintenanceResult != null)
{
return maintenanceResult;
}
var legacyRedirect = TryHandleLegacyUrlRedirect();
if (legacyRedirect != null)
{
return legacyRedirect;
}
InitializeRequestState();
if (!string.IsNullOrEmpty(Request.Query["p"]))
{
return await RedirectByPageIdAsync(Request.Query["p"]);
}
await preparePoets();
var breadCrumbList = new GoogleBreadCrumbList();
Banner = null;
var pageLoadResult = await LoadGanjoorPageAsync();
if (pageLoadResult != null)
{
return pageLoadResult;
}
var pageDataResult = await LoadPageTypeSpecificDataAsync();
if (pageDataResult != null)
{
return pageDataResult;
}
BuildTitleAndBreadCrumbs(breadCrumbList);
ViewData["BrearCrumpList"] = breadCrumbList.ToString();
if (IsCatPage || IsPoetPage)
{
var geoTagsResult = await LoadCategoryGeoTagsAsync();
if (geoTagsResult != null)
{
return geoTagsResult;
}
}
return Page();
}
/// <summary>
/// A couple of legacy URL shapes get redirected to their modern equivalents.
/// Returns null if the current request doesn't match either pattern.
/// </summary>
private IActionResult TryHandleLegacyUrlRedirect()
{
var path = Request.Path.ToString();
if (path.IndexOf("index.php") != -1)
{
return Redirect($"{path.Replace("index.php", "search")}{Request.QueryString}");
}
if (path.IndexOf("vazn") != -1 && Request.QueryString.ToString().IndexOf("v") != -1)
{
return Redirect($"{path.Replace("vazn", "simi")}{Request.QueryString}");
}
return null;
}
private void InitializeRequestState()
{
LastError = "";
InitializeCommonPageState();
CanEdit = Request.Cookies["CanEdit"] == "True";
KeepHistory = Request.Cookies["KeepHistory"] == "True";
CanTranslate = Request.Cookies["CanTranslate"] == "True";
IsPoetPage = false;
IsCatPage = false;
IsPoemPage = false;
PinterestUrl = Request.Query["pinterest_url"];
ShowAllRecitaions = Request.Query["allaudio"] == "1";
ActiveTab = Request.Query["tab"];
if (ShowAllRecitaions && string.IsNullOrEmpty(ActiveTab))
{
ActiveTab = "recitations";
}
else if (ActiveTab == "recitations" || ActiveTab == "commentaries")
{
ShowAllRecitaions = true;
}
}
/// <summary>
/// Handles the legacy "?p=&lt;id&gt;" query-string form by resolving it to the page's real
/// URL and redirecting there. Also kept on IndexModel (home page): since query strings don't
/// affect ASP.NET Core route matching, a link like "/?p=123" always has Path == "/" and is
/// always routed to the home page regardless of this split, so the check needs to exist on
/// both classes to keep old "?p=" links working from either entry point.
/// </summary>
private async Task<IActionResult> RedirectByPageIdAsync(string pageId)
{
var pageUrlResponse = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/pageurl?id={pageId}");
if (await CaptureErrorIfFailedAsync(pageUrlResponse))
{
return Page();
}
var pageUrl = JsonConvert.DeserializeObject<string>(await pageUrlResponse.Content.ReadAsStringAsync());
return Redirect(pageUrl);
}
/// <summary>
/// Fetches the GanjoorPage for the current URL and applies the page-type-specific preparation
/// that depends only on the page payload itself (excerpts, related sections, next/previous
/// links). Returns null to let OnGetAsync continue, or a terminal IActionResult
/// (redirect/404/error page) to short-circuit.
/// </summary>
private async Task<IActionResult> LoadGanjoorPageAsync()
{
var pageQuery = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/page?url={Request.Path}");
if (!pageQuery.IsSuccessStatusCode)
{
if (pageQuery.StatusCode == HttpStatusCode.NotFound)
{
var redirectQuery = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/redirecturl?url={Request.Path}");
if (redirectQuery.IsSuccessStatusCode)
{
var redirectUrl = JsonConvert.DeserializeObject<string>(await redirectQuery.Content.ReadAsStringAsync());
return Redirect(redirectUrl);
}
return NotFound();
}
LastError = await ReadErrorMessageAsync(pageQuery);
return Page();
}
GanjoorPage = JObject.Parse(await pageQuery.Content.ReadAsStringAsync()).ToObject<GanjoorPageCompleteViewModel>();
if (!string.IsNullOrEmpty(GanjoorPage.HtmlText))
{
GanjoorPage.HtmlText = GanjoorPage.HtmlText.Replace("https://ganjoor.net/", "/").Replace("http://ganjoor.net/", "/");
}
switch (GanjoorPage.GanjoorPageType)
{
case GanjoorPageType.PoemPage:
await _markMyCommentsAndBringUpMyRecitations();
_preparePoemExcerpt(GanjoorPage.Poem.Next);
_preparePoemExcerpt(GanjoorPage.Poem.Previous);
GanjoorPage.PoetOrCat = GanjoorPage.Poem.Category;
_prepareNextPre();
_prepareRelatedSecions();
IsPoemPage = true;
break;
case GanjoorPageType.PoetPage:
IsPoetPage = true;
break;
case GanjoorPageType.CatPage:
_prepareNextPre();
IsCatPage = true;
break;
}
return null;
}
/// <summary>
/// The extra API calls that only apply to specific page types: recitation availability for
/// poet/cat pages, poet photo for poet pages, and the random banner for poem pages.
/// </summary>
private async Task<IActionResult> LoadPageTypeSpecificDataAsync()
{
if (IsPoetPage || IsCatPage)
{
var catHasAnyRecitationQuery = await _httpClient.GetAsync($"{APIRoot.Url}/api/audio/catany/{GanjoorPage.PoetOrCat.Cat.Id}");
if (await CaptureErrorIfFailedAsync(catHasAnyRecitationQuery))
{
return Page();
}
CategoryHasRecitations = JsonConvert.DeserializeObject<bool>(await catHasAnyRecitationQuery.Content.ReadAsStringAsync());
}
if (IsPoetPage)
{
var responsePhotos = await _httpClient.GetAsync($"{APIRoot.Url}/api/poetphotos/poet/{GanjoorPage.PoetOrCat.Poet.Id}");
if (await CaptureErrorIfFailedAsync(responsePhotos))
{
return Page();
}
var photos = JArray.Parse(await responsePhotos.Content.ReadAsStringAsync()).ToObject<List<GanjoorPoetSuggestedPictureViewModel>>();
if (photos.Any())
{
Photo = photos.First();
}
}
if (IsPoemPage)
{
HtmlLanguage = string.IsNullOrEmpty(GanjoorPage.Poem.Language) ? "fa-IR" : GanjoorPage.Poem.Language;
if (GetConfigFlag("BannersEnabled"))
{
var bannerQuery = await _httpClient.GetAsync($"{APIRoot.Url}/api/banners/random");
if (await CaptureErrorIfFailedAsync(bannerQuery))
{
return Page();
}
var bannerResponse = await bannerQuery.Content.ReadAsStringAsync();
if (!string.IsNullOrEmpty(bannerResponse))
{
Banner = JObject.Parse(bannerResponse).ToObject<GanjoorSiteBannerViewModel>();
}
}
}
return null;
}
/// <summary>
/// Sets ViewData["Title"] and populates the breadcrumb list. Unlike the old
/// BuildTitleAndBreadCrumbsAsync, has no IsHomePage branch - this class never serves the home
/// page (see the note on OnGetAsync above).
/// </summary>
private void BuildTitleAndBreadCrumbs(GoogleBreadCrumbList breadCrumbList)
{
if (IsPoetPage)
{
BuildPoetPageTitleAndBreadCrumbs(breadCrumbList);
}
else if (IsCatPage)
{
BuildCatPageTitleAndBreadCrumbs(breadCrumbList);
}
else if (IsPoemPage)
{
BuildPoemPageTitleAndBreadCrumbs(breadCrumbList);
}
else
{
BuildGenericPageTitleAndBreadCrumbs(breadCrumbList);
}
}
private void BuildPoetPageTitleAndBreadCrumbs(GoogleBreadCrumbList breadCrumbList)
{
ViewData["Title"] = $"گنجور » {GanjoorPage.PoetOrCat.Poet.Nickname}";
breadCrumbList.AddItem(GanjoorPage.PoetOrCat.Poet.Nickname, GanjoorPage.PoetOrCat.Cat.FullUrl, $"{APIRoot.InternetUrl + GanjoorPage.PoetOrCat.Poet.ImageUrl}");
}
private void BuildCatPageTitleAndBreadCrumbs(GoogleBreadCrumbList breadCrumbList)
{
string title = $"گنجور » ";
bool poetCat = true;
foreach (var gran in GanjoorPage.PoetOrCat.Cat.Ancestors)
{
title += $"{gran.Title} » ";
breadCrumbList.AddItem(gran.Title, gran.FullUrl, poetCat ? $"{APIRoot.InternetUrl + GanjoorPage.PoetOrCat.Poet.ImageUrl}" : "https://i.ganjoor.net/cat.png");
poetCat = false;
}
breadCrumbList.AddItem(GanjoorPage.PoetOrCat.Cat.Title, GanjoorPage.PoetOrCat.Cat.FullUrl, "https://i.ganjoor.net/cat.png");
title += GanjoorPage.PoetOrCat.Cat.Title;
ViewData["Title"] = title;
}
private void BuildPoemPageTitleAndBreadCrumbs(GoogleBreadCrumbList breadCrumbList)
{
ViewData["Title"] = $"گنجور » {GanjoorPage.Poem.FullTitle}";
bool poetCat = true;
foreach (var gran in GanjoorPage.Poem.Category.Cat.Ancestors)
{
breadCrumbList.AddItem(gran.Title, gran.FullUrl, poetCat ? $"{APIRoot.InternetUrl + GanjoorPage.PoetOrCat.Poet.ImageUrl}" : "https://i.ganjoor.net/cat.png");
poetCat = false;
}
breadCrumbList.AddItem(GanjoorPage.PoetOrCat.Cat.Title, GanjoorPage.PoetOrCat.Cat.FullUrl, "https://i.ganjoor.net/cat.png");
var aiMuseumImage = GanjoorPage.Poem.Images.FirstOrDefault(i => i.TargetPageUrl.StartsWith("https://museum.ganjoor.net/items/ai"));
if (aiMuseumImage != null)
{
breadCrumbList.AddItem(GanjoorPage.Poem.Title, GanjoorPage.Poem.FullUrl, aiMuseumImage.ThumbnailImageUrl.Replace("/thumb/", "/orig/"));
}
else if (GanjoorPage.Poem.Images.Any())
{
breadCrumbList.AddItem(GanjoorPage.Poem.Title, GanjoorPage.Poem.FullUrl, GanjoorPage.Poem.Images.First().ThumbnailImageUrl.Replace("/thumb/", "/orig/"));
}
else
{
breadCrumbList.AddItem(GanjoorPage.Poem.Title, GanjoorPage.Poem.FullUrl, "https://i.ganjoor.net/poem.png");
}
}
private void BuildGenericPageTitleAndBreadCrumbs(GoogleBreadCrumbList breadCrumbList)
{
if (GanjoorPage.PoetOrCat != null)
{
bool poetCat = true;
string fullTitle = "گنجور » ";
if (GanjoorPage.PoetOrCat.Cat.Ancestors.Count == 0)
{
fullTitle += $"{GanjoorPage.PoetOrCat.Poet.Nickname} » ";
}
else
{
foreach (var gran in GanjoorPage.PoetOrCat.Cat.Ancestors)
{
breadCrumbList.AddItem(gran.Title, gran.FullUrl, poetCat ? $"{APIRoot.InternetUrl + GanjoorPage.PoetOrCat.Poet.ImageUrl}" : "https://i.ganjoor.net/cat.png");
poetCat = false;
fullTitle += $"{gran.Title} » ";
}
}
ViewData["Title"] = $"{fullTitle}{GanjoorPage.Title}";
breadCrumbList.AddItem(GanjoorPage.PoetOrCat.Poet.Nickname, GanjoorPage.PoetOrCat.Cat.FullUrl, $"{APIRoot.InternetUrl + GanjoorPage.PoetOrCat.Poet.ImageUrl}");
}
else
{
ViewData["Title"] = $"گنجور » {GanjoorPage.FullTitle}";
}
breadCrumbList.AddItem(GanjoorPage.Title, GanjoorPage.FullUrl, "https://i.ganjoor.net/cat.png");
}
private async Task<IActionResult> LoadCategoryGeoTagsAsync()
{
var tagsResponse = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/cat/{GanjoorPage.PoetOrCat.Cat.Id}/geotag");
if (await CaptureErrorIfFailedAsync(tagsResponse))
{
return Page();
}
CategoryPoemGeoDateTags = JsonConvert.DeserializeObject<PoemGeoDateTag[]>(await tagsResponse.Content.ReadAsStringAsync());
return null;
}
public async Task<IActionResult> OnGetBNumPartialAsync(int poemId, int coupletIndex)
{
var responseCoupletComments = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/poem/{poemId}/comments?coupletIndex={coupletIndex}");
if (!responseCoupletComments.IsSuccessStatusCode)
{
return BadRequest(await ReadErrorMessageAsync(responseCoupletComments));
}
var comments = JArray.Parse(await responseCoupletComments.Content.ReadAsStringAsync()).ToObject<List<GanjoorCommentSummaryViewModel>>();
var responseCoupletNumbers = await _httpClient.GetAsync($"{APIRoot.Url}/api/numberings/couplet/{poemId}/{coupletIndex}");
if (!responseCoupletNumbers.IsSuccessStatusCode)
{
return BadRequest(await ReadErrorMessageAsync(responseCoupletNumbers));
}
var numbers = JArray.Parse(await responseCoupletNumbers.Content.ReadAsStringAsync()).ToObject<List<GanjoorCoupletNumberViewModel>>();
var responseCoupletSections = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/couplet/{poemId}/{coupletIndex}/sections");
if (!responseCoupletSections.IsSuccessStatusCode)
{
return BadRequest(await ReadErrorMessageAsync(responseCoupletSections));
}
var responseVerses = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/poem/{poemId}/verses?coupletIndex={coupletIndex}");
if (!responseVerses.IsSuccessStatusCode)
{
return BadRequest(await ReadErrorMessageAsync(responseVerses));
}
var verses = JArray.Parse(await responseVerses.Content.ReadAsStringAsync()).ToObject<List<GanjoorVerseViewModel>>();
var sections = JArray.Parse(await responseCoupletSections.Content.ReadAsStringAsync()).ToObject<List<GanjoorPoemSection>>();
var sectionsWithMetreAndRhymes = new List<GanjoorPoemSection>();
foreach (var section in sections)
{
if (section.GanjoorMetreId != null && !string.IsNullOrEmpty(section.RhymeLetters))
{
if (!sectionsWithMetreAndRhymes.Any(s => s.GanjoorMetreId == section.GanjoorMetreId && s.RhymeLetters == section.RhymeLetters))
{
sectionsWithMetreAndRhymes.Add(section);
}
}
}
bool isBookmarked = false;
if (!string.IsNullOrEmpty(Request.Cookies["UserId"]))
{
if (Guid.TryParse(Request.Cookies["UserId"], out Guid userId))
if (userId != Guid.Empty)
{
using (HttpClient secureClient = new HttpClient())
{
if (await GanjoorSessionChecker.PrepareClient(secureClient, Request, Response))
{
HttpResponseMessage responseIsBookmarked = await secureClient.GetAsync($"{APIRoot.Url}/api/ganjoor/bookmark/{poemId}");
if (!responseIsBookmarked.IsSuccessStatusCode)
{
return BadRequest(await ReadErrorMessageAsync(responseIsBookmarked));
}
var bookmarks = JsonConvert.DeserializeObject<GanjoorUserBookmarkViewModel[]>(await responseIsBookmarked.Content.ReadAsStringAsync());
if (bookmarks.Where(b => b.CoupletIndex == coupletIndex).Any())
isBookmarked = true;
foreach (GanjoorCommentSummaryViewModel comment in comments)
{
comment.MyComment = comment.UserId == userId;
comment.IsBookmarked = bookmarks.Where(b => b.CoupletIndex == -comment.Id).Any();
_markMyReplies(comment, userId, bookmarks);
}
HttpResponseMessage responseRatings = await secureClient.GetAsync($"{APIRoot.Url}/api/ganjoor/poem/{poemId}/comments/myratings");
if (responseRatings.IsSuccessStatusCode)
{
var ratings = JsonConvert.DeserializeObject<GanjoorCommentUserRatingViewModel[]>(await responseRatings.Content.ReadAsStringAsync());
if (ratings.Length > 0)
{
var ratingsDic = ratings.ToDictionary(r => r.CommentId, r => r.Value);
foreach (GanjoorCommentSummaryViewModel comment in comments)
{
_applyCommentRatings(comment, ratingsDic);
}
}
}
}
}
}
}
return Partial("~/Pages/Partials/GanjoorPage/_BNumPartial.cshtml", new _BNumPartialModel()
{
PoemId = poemId,
CoupletIndex = coupletIndex,
LoggedIn = !string.IsNullOrEmpty(Request.Cookies["Token"]),
Comments = comments,
IsBookmarked = isBookmarked,
Numbers = numbers,
Sections = sections,
SectionsWithMetreAndRhymes = sectionsWithMetreAndRhymes,
Verses = verses,
});
}
public Task<IActionResult> OnPostSwitchBookmarkAsync(int poemId, int coupletIndex)
{
return WithSecureClientAsync(async secureClient =>
{
var response = await secureClient.PostAsync($"{APIRoot.Url}/api/ganjoor/bookmark/switch/ret/{poemId}/{coupletIndex}", null);
if (!response.IsSuccessStatusCode)
{
return new BadRequestObjectResult(await ReadErrorMessageAsync(response));
}
var res = JsonConvert.DeserializeObject<string>(await response.Content.ReadAsStringAsync());
return new OkObjectResult(res);
});
}
public Task<IActionResult> OnGetIsCoupletBookmarkedAsync(int poemId, int coupletIndex)
{
return WithSecureClientAsync(async secureClient =>
{
var response = await secureClient.GetAsync($"{APIRoot.Url}/api/ganjoor/bookmark/{poemId}/{coupletIndex}");
if (!response.IsSuccessStatusCode)
{
return new BadRequestObjectResult(await ReadErrorMessageAsync(response));
}
var res = JsonConvert.DeserializeObject<bool>(await response.Content.ReadAsStringAsync());
return new OkObjectResult(res);
});
}
public Task<IActionResult> OnGetPoemBookmarksAsync(int poemId)
{
return WithSecureClientAsync(async secureClient =>
{
var response = await secureClient.GetAsync($"{APIRoot.Url}/api/ganjoor/bookmark/{poemId}");
if (!response.IsSuccessStatusCode)
{
return new BadRequestObjectResult(await ReadErrorMessageAsync(response));
}
var res = JsonConvert.DeserializeObject<GanjoorUserBookmarkViewModel[]>(await response.Content.ReadAsStringAsync());
return new OkObjectResult(res);
});
}
/// <summary>
/// unused now, to be removed
/// </summary>
public Task<IActionResult> OnGetUserUpvotedRecitationsAsync(int poemId)
{
return WithSecureClientAsync(async secureClient =>
{
var response = await secureClient.GetAsync($"{APIRoot.Url}/api/ganjoor/poem/{poemId}/recitations/upvotes");
if (!response.IsSuccessStatusCode)
{
return new BadRequestObjectResult(await ReadErrorMessageAsync(response));
}
var res = JsonConvert.DeserializeObject<int[]>(await response.Content.ReadAsStringAsync());
return new OkObjectResult(res);
});
}
public Task<IActionResult> OnPostSwitchRecitationUpVoteAsync(int id)
{
return WithSecureClientAsync(async secureClient =>
{
var response = await secureClient.PutAsync($"{APIRoot.Url}/api/audio/vote/switch/{id}", null);
if (!response.IsSuccessStatusCode)
{
return new BadRequestObjectResult(await ReadErrorMessageAsync(response));
}
var res = JsonConvert.DeserializeObject<bool>(await response.Content.ReadAsStringAsync());
return new OkObjectResult(res);
});
}
public Task<IActionResult> OnPostAddToMyHistoryAsync(int poemId)
{
return WithSecureClientAsync(async secureClient =>
{
var response = await secureClient.PostAsync($"{APIRoot.Url}/api/tracking", new StringContent(JsonConvert.SerializeObject(poemId), Encoding.UTF8, "application/json"));
if (!response.IsSuccessStatusCode)
{
return new BadRequestObjectResult(await ReadErrorMessageAsync(response));
}
var res = JsonConvert.DeserializeObject<GanjoorUserPrePoemVisitViewModel>(await response.Content.ReadAsStringAsync());
if (res.KeepTrack == false)
{
if (Request.Cookies["KeepHistory"] != null)
{
Response.Cookies.Delete("KeepHistory");
}
var cookieOption = new CookieOptions()
{
Expires = DateTime.Now.AddDays(365),
};
Response.Cookies.Append("KeepHistory", $"{false}", cookieOption);
}
return new OkObjectResult(res.KeepTrack && res.LastVisit != null ? $"از این صفحه آخرین بار {res.LastVisit.ToFriendlyPersianDateTextify()} و در مجموع {res.TotalVisits.ToPersianNumbers()} بار بازدید کرده‌ام." : "");
});
}
public Task<IActionResult> OnPutBookmarkNote(Guid id, string note)
{
return WithSecureClientAsync(async secureClient =>
{
var response = await secureClient.PutAsync($"{APIRoot.Url}/api/ganjoor/bookmark/{id}", new StringContent(JsonConvert.SerializeObject(note), Encoding.UTF8, "application/json"));
if (!response.IsSuccessStatusCode)
{
return new BadRequestObjectResult(await ReadErrorMessageAsync(response));
}
return new JsonResult(true);
});
}
public Task<IActionResult> OnDeleteMistakeAsync(int id)
{
return WithSecureClientAsync(async secureClient =>
{
var response = await secureClient.DeleteAsync($"{APIRoot.Url}/api/audio/errors/approved/{id}");
if (!response.IsSuccessStatusCode)
{
return new BadRequestObjectResult(await ReadErrorMessageAsync(response));
}
return new JsonResult(true);
});
}
public Task<IActionResult> OnPutMistakeAsync(int id, string reasonText)
{
return WithSecureClientAsync(async secureClient =>
{
var stringContent = new StringContent(
JsonConvert.SerializeObject(new RecitationErrorReportViewModel()
{
Id = id,
ReasonText = reasonText,
NumberOfLinesAffected = 1,
CoupletIndex = -1,
}),
Encoding.UTF8, "application/json");
var response = await secureClient.PutAsync($"{APIRoot.Url}/api/audio/errors/report/edit", stringContent);
if (!response.IsSuccessStatusCode)
{
return new BadRequestObjectResult(await ReadErrorMessageAsync(response));
}
return new JsonResult(true);
});
}
public async Task<IActionResult> OnGetMoreQuotedPoemsForRelatedPoemPartialAsync(int poemId, int relatedPoemId, string poetImageUrl, string poetNickName, bool canEdit)
{
string url = $"{APIRoot.Url}/api/ganjoor/poem/{poemId}/quoteds/{relatedPoemId}?published=true";
var response = await _httpClient.GetAsync(url);
if (!response.IsSuccessStatusCode)
return BadRequest(await ReadErrorMessageAsync(response));
var quoteds = JArray.Parse(await response.Content.ReadAsStringAsync()).ToObject<List<GanjoorQuotedPoemViewModel>>();
if (!quoteds.Any())
{
return BadRequest("مورد دیگری یافت نشد.");
}
if (quoteds.Any(q => q.ChosenForMainList))
{
var mainList = quoteds.Where(q => q.ChosenForMainList).First();
quoteds.Remove(mainList);
}
return Partial("~/Pages/Partials/GanjoorPage/_MultipleQuotedPoemsPartial.cshtml", new _MultipleQuotedPoemsPartialModel()
{
GanjoorQuotedPoems = quoteds.ToArray(),
PoetImageUrl = poetImageUrl,
PoetNickName = poetNickName,
CanEdit = canEdit
});
}
public async Task<IActionResult> OnGetMoreQuotedPoemsPartialAsync(int poemId, int skip, string poetImageUrl, string poetNickName, bool canEdit)
{
string url = $"{APIRoot.Url}/api/ganjoor/poem/{poemId}/quoteds?skip={skip}&itemsCount=1000";
var response = await _httpClient.GetAsync(url);
if (!response.IsSuccessStatusCode)
return BadRequest(await ReadErrorMessageAsync(response));
var quoteds = JArray.Parse(await response.Content.ReadAsStringAsync()).ToObject<List<GanjoorQuotedPoemViewModel>>();
return Partial("~/Pages/Partials/GanjoorPage/_MultipleQuotedPoemsPartial.cshtml", new _MultipleQuotedPoemsPartialModel()
{
GanjoorQuotedPoems = quoteds.ToArray(),
PoetImageUrl = poetImageUrl,
PoetNickName = poetNickName,
CanEdit = canEdit
});
}
public string PoemBlockClass => GanjoorPage != null && GanjoorPage.Poem != null && GanjoorPage.Poem.ClaimedByMultiplePoets ? "poem ribbon-parent" : "poem";
public Task<IActionResult> OnPostMarkAsTextOriginalAsync(int bookId, int categoryId)
{
return WithSecureClientAsync(async secureClient =>
{
var response = await secureClient.PutAsync($"{APIRoot.Url}/api/ganjoor/naskban/textoriginal/{bookId}/{categoryId}/true", null);
if (!response.IsSuccessStatusCode)
{
return new BadRequestObjectResult(await ReadErrorMessageAsync(response));
}
return new OkObjectResult(true);
});
}
public Task<IActionResult> OnDeleteRelatedImageLinkAsync(PoemRelatedImageType relatedImageType, Guid linkId, bool removeItemLink)
{
return WithSecureClientAsync(async secureClient =>
{
var response = await secureClient.DeleteAsync(
relatedImageType == PoemRelatedImageType.MuseumLink
? $"{APIRoot.Url}/api/artifacts/ganjoor?linkId={linkId}&removeItemLink={removeItemLink}"
: $"{APIRoot.Url}/api/artifacts/pinterest?linkId={linkId}");
if (!response.IsSuccessStatusCode)
{
return new BadRequestObjectResult(await ReadErrorMessageAsync(response));
}
return new OkObjectResult(true);
});
}
public async Task<IActionResult> OnGetCategoryRecitationsAsync(int catId)
{
var catTop1RecitationsQuery = await _httpClient.GetAsync($"{APIRoot.Url}/api/audio/cattop1/{catId}?includePoemText=false");
if (!catTop1RecitationsQuery.IsSuccessStatusCode)
{
return BadRequest(await ReadErrorMessageAsync(catTop1RecitationsQuery));
}
var categoryTop1Recitations = JsonConvert.DeserializeObject<PublicRecitationViewModel[]>(await catTop1RecitationsQuery.Content.ReadAsStringAsync());
return Partial("~/Pages/Partials/GanjoorPage/_AudioPlayerPartial.cshtml", new _AudioPlayerPartialModel()
{
LoggedIn = !string.IsNullOrEmpty(Request.Cookies["Token"]),
Recitations = categoryTop1Recitations,
ShowAllRecitaions = true,
CategoryMode = true,
});
}
private async Task<_CategoryWordsCountPartialModel> _GetCategoryWordCountsAsync(int catId, int poetId, bool remStopWords = false)
{
var wordSumsResponse = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/wordsums/{catId}");
if (!wordSumsResponse.IsSuccessStatusCode)
{
return null;
}
var wordSums = JsonConvert.DeserializeObject<CategoryWordCountSummary>(await wordSumsResponse.Content.ReadAsStringAsync());
if (wordSums.TotalWordCount == 0)
{
return null;
}
int pageSize = remStopWords ? 200 : 100;
var wordCountsResponse = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/wordcounts/{catId}?PageNumber=1&PageSize={pageSize}");
if (!wordCountsResponse.IsSuccessStatusCode)
{
return null;
}
var wordCounts = JsonConvert.DeserializeObject<CategoryWordCount[]>(await wordCountsResponse.Content.ReadAsStringAsync());
if (remStopWords)
{
wordCounts = wordCounts.Where(w => !_persianStopWords.Contains(w.Word)).Take(100).ToArray();
}
return new _CategoryWordsCountPartialModel()
{
CatId = catId,
PoetId = poetId,
WordCounts = wordCounts,
UniqueWordCount = wordSums.UniqueWordCount,
TotalWordCount = wordSums.TotalWordCount,
RemStopWords = remStopWords,
};
}
public async Task<IActionResult> OnGetCategoryWordCountsAsync(int catId, int poetId, bool remStopWords = false)
{
var res = await _GetCategoryWordCountsAsync(catId, poetId, remStopWords);
if (res == null)
{
return BadRequest("خطا در دسترسی به شمارش واژگان");
}
return Partial("~/Pages/Partials/GanjoorPage/_CategoryWordsCountPartial.cshtml", res);
}
public async Task<IActionResult> OnGetSearchCategoryWordCountsAsync(int catId, int poetId, string term, int totalWordCount)
{
if (!string.IsNullOrEmpty(term))
{
term = term.Trim();
}
var wordCountsResponse = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/wordcounts/{catId}?PageNumber=1&PageSize=100&term={term}");
if (!wordCountsResponse.IsSuccessStatusCode)
{
return BadRequest(await ReadErrorMessageAsync(wordCountsResponse));
}
var wordCounts = JsonConvert.DeserializeObject<CategoryWordCount[]>(await wordCountsResponse.Content.ReadAsStringAsync());
return Partial("~/Pages/Partials/GanjoorPage/_CategoryWordsCountTablePartial.cshtml", new _CategoryWordsCountTablePartialModel()
{
CatId = catId,
PoetId = poetId,
WordCounts = wordCounts,
TotalWordCount = totalWordCount,
});
}
public async Task<IActionResult> OnGetPoemWordCountsAsync(int poemId)
{
var poemQuery = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/poem/{poemId}");
if (!poemQuery.IsSuccessStatusCode)
{
return BadRequest(await ReadErrorMessageAsync(poemQuery));
}
var poem = JObject.Parse(await poemQuery.Content.ReadAsStringAsync()).ToObject<GanjoorPoemCompleteViewModel>();
List<CategoryWordCount> counts = new List<CategoryWordCount>();
foreach (var verse in poem.Verses.Where(v => v.VersePosition != VersePosition.Comment))
{
string[] words = LanguageUtils.MakeTextSearchable(verse.Text).Split([' ', '‌']);
foreach (var word in words)
{
if (string.IsNullOrEmpty(word)) continue;
var wordCount = counts.Where(c => c.Word == word).SingleOrDefault();
if (wordCount != null)
{
wordCount.Count++;
}
else
{
counts.Add(new CategoryWordCount { CatId = 0, Word = word, Count = 1 });
}
}
}
counts.Sort((a, b) => b.Count.CompareTo(a.Count));
for (int i = 0; i < counts.Count; i++)
{
counts[i].RowNmbrInCat = i + 1;
}
counts.Insert(0, new CategoryWordCount()
{
Word = "* تعداد کل",
Count = counts.Sum(c => c.Count),
RowNmbrInCat = 0,
});
return Partial("~/Pages/Partials/GanjoorPage/_CategoryWordsCountTablePartial.cshtml", new _CategoryWordsCountTablePartialModel()
{
CatId = -1,
PoetId = -1,
TotalWordCount = counts.Where(c => c.RowNmbrInCat > 0).Sum(c => c.Count),
WordCounts = counts.ToArray()
});
}
public async Task<IActionResult> OnGetTopVisitsAsync(string url)
{
url = $"https://ganjoor.net/{url}/";
var apiUrl = $"https://track.kntr.ir/api/reporting/toppages/1/ganjoor.net?parentUrl={WebUtility.UrlEncode(url)}&count=20";
var topVisitsResponse = await _httpClient.GetAsync(apiUrl);
if (!topVisitsResponse.IsSuccessStatusCode)
{
return Partial("~/Pages/Partials/GanjoorPage/_TopVisitsPartial.cshtml", new _TopVisitsPartialModel()
{
Visits = null
});
}
var topVisits = JsonConvert.DeserializeObject<PageVisitsViewModel[]>(await topVisitsResponse.Content.ReadAsStringAsync());
return Partial("~/Pages/Partials/GanjoorPage/_TopVisitsPartial.cshtml", new _TopVisitsPartialModel()
{
Visits = topVisits
});
}
public async Task<IActionResult> OnGetSevenDaysVisitsAsync(string url)
{
url = $"https://ganjoor.net/{url}/";
var apiUrl = $"https://track.kntr.ir/api/reporting/dailypagevisits/1/ganjoor.net/for/{WebUtility.UrlEncode(url)}?start={DateTime.Now.Date.AddDays(-6).ToString("yyyy-MM-dd")}";
var s7ndaysVisitsResponse = await _httpClient.GetAsync(apiUrl);
if (!s7ndaysVisitsResponse.IsSuccessStatusCode)
{
return Partial("~/Pages/Partials/GanjoorPage/_7DaysVisitsPartial.cshtml", new _7DaysVisitsPartialModel()
{
SevenDaysVisits = null
});
}
var s7ndaysVisits = JsonConvert.DeserializeObject<DateRangeVisitsViewModel[]>(await s7ndaysVisitsResponse.Content.ReadAsStringAsync());
return Partial("~/Pages/Partials/GanjoorPage/_7DaysVisitsPartial.cshtml", new _7DaysVisitsPartialModel()
{
SevenDaysVisits = s7ndaysVisits
});
}
// --- merged from the old _SimiPage.cshtml.cs (was a partial-class extension of IndexModel) ---
public async Task<IActionResult> OnGetSimilarPoemsPartialAsync(int poemId, int skip, string prosodyMetre, string rhymeLetters, string poemFullUrl, int sectionIndex)
{
string url = $"{APIRoot.Url}/api/ganjoor/section/{poemId}/{sectionIndex}/related?skip={skip}&itemsCount=21";
var response = await _httpClient.GetAsync(url);
if (!response.IsSuccessStatusCode)
return BadRequest(await ReadErrorMessageAsync(response));
var relatedSections = JArray.Parse(await response.Content.ReadAsStringAsync()).ToObject<List<GanjoorCachedRelatedSection>>();
return Partial("~/Pages/Partials/GanjoorPage/_SimiPartialView.cshtml", new _SimiPartialViewModel()
{
RelatedSections = relatedSections.ToArray(),
Rhythm = prosodyMetre,
RhymeLetters = rhymeLetters,
Skip = skip,
PoemId = poemId,
PoemFullUrl = poemFullUrl,
SectionIndex = sectionIndex
});
}
public async Task<IActionResult> OnGetSimilarPoemsFromPoetPartialAsync(int poetId, string prosodyMetre, string rhymeLetters, string skipPoemFullUrl1, string skipPoemFullUrl2)
{
string url = $"{APIRoot.Url}/api/ganjoor/poems/similar?metre={prosodyMetre}&rhyme={rhymeLetters}&poetId={poetId}";
var response = await _httpClient.GetAsync(url);
if (!response.IsSuccessStatusCode)
return BadRequest(await ReadErrorMessageAsync(response));
var poems = JArray.Parse(await response.Content.ReadAsStringAsync()).ToObject<List<GanjoorPoemCompleteViewModel>>();
if (poems.Any(p => p.FullUrl == skipPoemFullUrl1))
poems.RemoveAll(p => p.FullUrl == skipPoemFullUrl1); //TODO: fix errors here
if (poems.Any(p => p.FullUrl == skipPoemFullUrl2))
poems.RemoveAll(p => p.FullUrl == skipPoemFullUrl2);
foreach (var poem in poems)
{
poem.HtmlText = GanjoorPoemTools.GetPoemHtmlExcerpt(poem.HtmlText);
}
return Partial("~/Pages/Partials/GanjoorPage/_SimiPartialFromPoetView.cshtml", new _SimiPartialFromPoetViewModel()
{
Poems = poems,
});
}
}
}