refactoring
This commit is contained in:
parent
86837dc6c8
commit
64ab66aacd
@ -1,85 +1,52 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using GanjooRazor.Utils;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using RMuseum.Models.Ganjoor.ViewModels;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using System;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace GanjooRazor.Pages
|
||||
{
|
||||
[IgnoreAntiforgeryToken(Order = 1001)]
|
||||
public class BooksModel : LoginPartialEnabledPageModel
|
||||
{
|
||||
private readonly PoetCacheService _poetCache;
|
||||
|
||||
public async Task<IActionResult> OnGetAsync()
|
||||
{
|
||||
if (bool.Parse(Configuration["MaintenanceMode"]))
|
||||
var maintenanceResult = TryGetMaintenanceModeResult();
|
||||
if (maintenanceResult != null)
|
||||
{
|
||||
return StatusCode(503);
|
||||
return maintenanceResult;
|
||||
}
|
||||
ViewData["Title"] = "فهرست کتابها";
|
||||
ViewData["TrackingScript"] = Configuration["TrackingScript"] != null && string.IsNullOrEmpty(Request.Cookies["Token"]) ? Configuration["TrackingScript"].Replace("loggedon", "") : Configuration["TrackingScript"];
|
||||
LoggedIn = !string.IsNullOrEmpty(Request.Cookies["Token"]);
|
||||
|
||||
if (false == await preparePoets())
|
||||
ViewData["Title"] = "فهرست کتابها";
|
||||
InitializeCommonPageState();
|
||||
|
||||
var (poetsOk, poets, poetsError) = await _poetCache.GetPoetsAsync(AggressiveCacheEnabled);
|
||||
if (!poetsOk)
|
||||
{
|
||||
LastError = poetsError;
|
||||
return Page();
|
||||
}
|
||||
Poets = poets;
|
||||
|
||||
var response = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/books");
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
LastError = JsonConvert.DeserializeObject<string>(await response.Content.ReadAsStringAsync());
|
||||
LastError = await ReadErrorMessageAsync(response);
|
||||
return Page();
|
||||
}
|
||||
Books = JArray.Parse(await response.Content.ReadAsStringAsync()).ToObject<List<GanjoorCatViewModel>>();
|
||||
return Page();
|
||||
}
|
||||
|
||||
private async Task<bool> preparePoets()
|
||||
{
|
||||
var cacheKey = $"/api/ganjoor/poets";
|
||||
if (!_memoryCache.TryGetValue(cacheKey, out List<GanjoorPoetViewModel> poets))
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/poets");
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
LastError = JsonConvert.DeserializeObject<string>(await response.Content.ReadAsStringAsync());
|
||||
return false;
|
||||
}
|
||||
poets = JArray.Parse(await response.Content.ReadAsStringAsync()).ToObject<List<GanjoorPoetViewModel>>();
|
||||
if (AggressiveCacheEnabled)
|
||||
{
|
||||
_memoryCache.Set(cacheKey, poets, TimeSpan.FromHours(1));
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
LastError = "خطا در دسترسی به وب سرویس گنجور";
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Poets = poets;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// configration file reader (appsettings.json)
|
||||
/// </summary>
|
||||
protected readonly IConfiguration Configuration;
|
||||
|
||||
/// <summary>
|
||||
/// books
|
||||
/// </summary>
|
||||
public List<GanjoorCatViewModel> Books { get; set; }
|
||||
public List<GanjoorCatViewModel> Books { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Poets
|
||||
@ -91,41 +58,13 @@ namespace GanjooRazor.Pages
|
||||
/// </summary>
|
||||
public string LastError { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// memory cache
|
||||
/// </summary>
|
||||
private readonly IMemoryCache _memoryCache;
|
||||
|
||||
// <summary>
|
||||
/// aggressive cache
|
||||
/// </summary>
|
||||
public bool AggressiveCacheEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return bool.Parse(Configuration["AggressiveCacheEnabled"]);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// constructor
|
||||
/// </summary>
|
||||
/// <param name="configuration"></param>
|
||||
/// <param name="httpClient"></param>
|
||||
/// <param name="memoryCache"></param>
|
||||
public BooksModel(IConfiguration configuration,
|
||||
HttpClient httpClient, IMemoryCache memoryCache
|
||||
) : base(httpClient)
|
||||
public BooksModel(IConfiguration configuration, HttpClient httpClient, PoetCacheService poetCache) : base(httpClient, configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
_memoryCache = memoryCache;
|
||||
_poetCache = poetCache;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,152 +1,81 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using RMuseum.Models.Ganjoor.ViewModels;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using GanjooRazor.Utils;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using RMuseum.Models.Ganjoor.ViewModels;
|
||||
using RMuseum.Models.Generic.ViewModels;
|
||||
using RSecurityBackend.Models.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using static Betalgo.Ranul.OpenAI.ObjectModels.RealtimeModels.RealtimeEventTypes;
|
||||
using Org.BouncyCastle.Asn1.Ocsp;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GanjooRazor.Pages
|
||||
{
|
||||
[IgnoreAntiforgeryToken(Order = 1001)]
|
||||
public class ContribsModel : LoginPartialEnabledPageModel
|
||||
{
|
||||
private readonly PoetCacheService _poetCache;
|
||||
|
||||
public List<GanjoorPoetViewModel> Poets { get; set; }
|
||||
public int PoetId { get; set; }
|
||||
public GanjoorPoetCompleteViewModel Poet { get; set; }
|
||||
public string LastError { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// aggressive cache
|
||||
/// </summary>
|
||||
public bool AggressiveCacheEnabled
|
||||
public async Task<IActionResult> OnGetAsync()
|
||||
{
|
||||
get
|
||||
var maintenanceResult = TryGetMaintenanceModeResult();
|
||||
if (maintenanceResult != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
return bool.Parse(Configuration["AggressiveCacheEnabled"]);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private async Task<bool> preparePoets()
|
||||
{
|
||||
var cacheKey = $"/api/ganjoor/poets";
|
||||
if (!_memoryCache.TryGetValue(cacheKey, out List<GanjoorPoetViewModel> poets))
|
||||
{
|
||||
var response = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/poets");
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
LastError = JsonConvert.DeserializeObject<string>(await response.Content.ReadAsStringAsync());
|
||||
return false;
|
||||
}
|
||||
poets = JArray.Parse(await response.Content.ReadAsStringAsync()).ToObject<List<GanjoorPoetViewModel>>();
|
||||
if (AggressiveCacheEnabled)
|
||||
{
|
||||
_memoryCache.Set(cacheKey, poets, TimeSpan.FromHours(1));
|
||||
}
|
||||
return maintenanceResult;
|
||||
}
|
||||
|
||||
InitializeCommonPageState();
|
||||
PoetId = string.IsNullOrEmpty(Request.Query["a"]) ? 0 : int.Parse(Request.Query["a"]);
|
||||
|
||||
var (poetsOk, poets, poetsError) = await _poetCache.GetPoetsAsync(AggressiveCacheEnabled);
|
||||
if (!poetsOk)
|
||||
{
|
||||
LastError = poetsError;
|
||||
return Page();
|
||||
}
|
||||
Poets = poets;
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task<bool> preparePoet()
|
||||
{
|
||||
var cacheKey = $"/api/ganjoor/poet/{PoetId}";
|
||||
if (!_memoryCache.TryGetValue(cacheKey, out GanjoorPoetCompleteViewModel poet))
|
||||
if (PoetId != 0)
|
||||
{
|
||||
var poetResponse = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/poet/{PoetId}");
|
||||
if (!poetResponse.IsSuccessStatusCode)
|
||||
var (poetOk, poet, poetError) = await _poetCache.GetPoetAsync(PoetId, AggressiveCacheEnabled);
|
||||
if (!poetOk)
|
||||
{
|
||||
LastError = JsonConvert.DeserializeObject<string>(await poetResponse.Content.ReadAsStringAsync());
|
||||
return false;
|
||||
}
|
||||
poet = JObject.Parse(await poetResponse.Content.ReadAsStringAsync()).ToObject<GanjoorPoetCompleteViewModel>();
|
||||
if (AggressiveCacheEnabled)
|
||||
{
|
||||
_memoryCache.Set(cacheKey, poet, TimeSpan.FromHours(1));
|
||||
LastError = poetError;
|
||||
return Page();
|
||||
}
|
||||
Poet = poet;
|
||||
}
|
||||
|
||||
Poet = poet;
|
||||
return true;
|
||||
return Page();
|
||||
}
|
||||
|
||||
public async Task<IActionResult> OnGetPoetInformationAsync(int id)
|
||||
{
|
||||
if (id == 0)
|
||||
return new OkObjectResult(null);
|
||||
var cacheKey = $"/api/ganjoor/poet/{id}";
|
||||
if (!_memoryCache.TryGetValue(cacheKey, out GanjoorPoetCompleteViewModel poet))
|
||||
{
|
||||
var poetResponse = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/poet/{id}");
|
||||
if (!poetResponse.IsSuccessStatusCode)
|
||||
{
|
||||
return BadRequest(JsonConvert.DeserializeObject<string>(await poetResponse.Content.ReadAsStringAsync()));
|
||||
}
|
||||
poet = JObject.Parse(await poetResponse.Content.ReadAsStringAsync()).ToObject<GanjoorPoetCompleteViewModel>();
|
||||
if (AggressiveCacheEnabled)
|
||||
{
|
||||
_memoryCache.Set(cacheKey, poet, TimeSpan.FromHours(1));
|
||||
}
|
||||
return new OkObjectResult(null);
|
||||
}
|
||||
var (success, poet, error) = await _poetCache.GetPoetAsync(id, AggressiveCacheEnabled);
|
||||
if (!success)
|
||||
{
|
||||
return BadRequest(error);
|
||||
}
|
||||
return new OkObjectResult(poet);
|
||||
}
|
||||
|
||||
public async Task<IActionResult> OnGetAsync()
|
||||
{
|
||||
if (bool.Parse(Configuration["MaintenanceMode"]))
|
||||
{
|
||||
return StatusCode(503);
|
||||
}
|
||||
|
||||
LoggedIn = !string.IsNullOrEmpty(Request.Cookies["Token"]);
|
||||
|
||||
PoetId = string.IsNullOrEmpty(Request.Query["a"]) ? 0 : int.Parse(Request.Query["a"]);
|
||||
|
||||
ViewData["TrackingScript"] = Configuration["TrackingScript"] != null && string.IsNullOrEmpty(Request.Cookies["Token"]) ? Configuration["TrackingScript"].Replace("loggedon", "") : Configuration["TrackingScript"];
|
||||
|
||||
//todo: use html master layout or make it partial
|
||||
// 1. poets
|
||||
if (false == (await preparePoets()))
|
||||
return Page();
|
||||
|
||||
if (PoetId != 0)
|
||||
{
|
||||
if (false == (await preparePoet()))
|
||||
return Page();
|
||||
}
|
||||
|
||||
|
||||
|
||||
return Page();
|
||||
}
|
||||
|
||||
public async Task<ActionResult> OnGetGroupedByDateAsync(string dataType)
|
||||
public async Task<IActionResult> OnGetGroupedByDateAsync(string dataType)
|
||||
{
|
||||
var responseDays = await _httpClient.GetAsync($"{APIRoot.Url}/api/contributions/{dataType}/daily?PageNumber=1&PageSize=30");
|
||||
|
||||
if (!responseDays.IsSuccessStatusCode)
|
||||
{
|
||||
return new BadRequestObjectResult(JsonConvert.DeserializeObject<string>(await responseDays.Content.ReadAsStringAsync()));
|
||||
return new BadRequestObjectResult(await ReadErrorMessageAsync(responseDays));
|
||||
}
|
||||
var days = JArray.Parse(await responseDays.Content.ReadAsStringAsync()).ToObject<List<GroupedByDateViewModel>>();
|
||||
|
||||
@ -155,116 +84,73 @@ namespace GanjooRazor.Pages
|
||||
if (dataType != "users")
|
||||
{
|
||||
var responseUsers = await _httpClient.GetAsync($"{APIRoot.Url}/api/contributions/{dataType}/by/user?PageNumber=1&PageSize=30");
|
||||
|
||||
if (!responseUsers.IsSuccessStatusCode)
|
||||
{
|
||||
return new BadRequestObjectResult(JsonConvert.DeserializeObject<string>(await responseUsers.Content.ReadAsStringAsync()));
|
||||
return new BadRequestObjectResult(await ReadErrorMessageAsync(responseUsers));
|
||||
}
|
||||
users = JArray.Parse(await responseUsers.Content.ReadAsStringAsync()).ToObject<List<GroupedByUserViewModel>>();
|
||||
usersPagination = JsonConvert.DeserializeObject<PaginationMetadata>(responseUsers.Headers.GetValues("paging-headers").Single());
|
||||
}
|
||||
|
||||
var response = await _httpClient.GetAsync($"{APIRoot.Url}/api/contributions/{dataType}/summary");
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
return new BadRequestObjectResult(JsonConvert.DeserializeObject<string>(await response.Content.ReadAsStringAsync()));
|
||||
return new BadRequestObjectResult(await ReadErrorMessageAsync(response));
|
||||
}
|
||||
SummedUpViewModel summary = JsonConvert.DeserializeObject<SummedUpViewModel>(await response.Content.ReadAsStringAsync());
|
||||
|
||||
return new PartialViewResult()
|
||||
return Partial("_GroupedByDateViewPartial", new _GroupedByDateViewPartialModel()
|
||||
{
|
||||
ViewName = "_GroupedByDateViewPartial",
|
||||
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
|
||||
{
|
||||
Model = new _GroupedByDateViewPartialModel()
|
||||
{
|
||||
DataType = dataType,
|
||||
Days = days.ToArray(),
|
||||
DaysPagination = JsonConvert.DeserializeObject<PaginationMetadata>(responseDays.Headers.GetValues("paging-headers").Single()),
|
||||
Users = users == null ? null :users.ToArray(),
|
||||
UsersPagination = usersPagination,
|
||||
Summary = summary
|
||||
}
|
||||
}
|
||||
};
|
||||
DataType = dataType,
|
||||
Days = days.ToArray(),
|
||||
DaysPagination = JsonConvert.DeserializeObject<PaginationMetadata>(responseDays.Headers.GetValues("paging-headers").Single()),
|
||||
Users = users?.ToArray(),
|
||||
UsersPagination = usersPagination,
|
||||
Summary = summary
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public async Task<ActionResult> OnGetGroupedByUsersAsync(string dataType, int pageNumber)
|
||||
public async Task<IActionResult> OnGetGroupedByUsersAsync(string dataType, int pageNumber)
|
||||
{
|
||||
var responseUsers = await _httpClient.GetAsync($"{APIRoot.Url}/api/contributions/{dataType}/by/user?PageNumber={pageNumber}&PageSize=30");
|
||||
|
||||
if (!responseUsers.IsSuccessStatusCode)
|
||||
{
|
||||
return new BadRequestObjectResult(JsonConvert.DeserializeObject<string>(await responseUsers.Content.ReadAsStringAsync()));
|
||||
return new BadRequestObjectResult(await ReadErrorMessageAsync(responseUsers));
|
||||
}
|
||||
var users = JArray.Parse(await responseUsers.Content.ReadAsStringAsync()).ToObject<List<GroupedByUserViewModel>>();
|
||||
var usersPagination = JsonConvert.DeserializeObject<PaginationMetadata>(responseUsers.Headers.GetValues("paging-headers").Single());
|
||||
|
||||
return new PartialViewResult()
|
||||
return Partial("_GroupedByDateViewTablePartial", new _GroupedByDateViewTablePartialModel()
|
||||
{
|
||||
ViewName = "_GroupedByDateViewTablePartial",
|
||||
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
|
||||
{
|
||||
Model = new _GroupedByDateViewTablePartialModel()
|
||||
{
|
||||
DataType = dataType,
|
||||
Users = users.ToArray(),
|
||||
UsersPagination = usersPagination,
|
||||
}
|
||||
}
|
||||
};
|
||||
DataType = dataType,
|
||||
Users = users.ToArray(),
|
||||
UsersPagination = usersPagination,
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<ActionResult> OnGetGroupedByDayAsync(string dataType, int pageNumber)
|
||||
public async Task<IActionResult> OnGetGroupedByDayAsync(string dataType, int pageNumber)
|
||||
{
|
||||
var responseDays = await _httpClient.GetAsync($"{APIRoot.Url}/api/contributions/{dataType}/daily?PageNumber={pageNumber}&PageSize=30");
|
||||
|
||||
if (!responseDays.IsSuccessStatusCode)
|
||||
{
|
||||
return new BadRequestObjectResult(JsonConvert.DeserializeObject<string>(await responseDays.Content.ReadAsStringAsync()));
|
||||
return new BadRequestObjectResult(await ReadErrorMessageAsync(responseDays));
|
||||
}
|
||||
var days = JArray.Parse(await responseDays.Content.ReadAsStringAsync()).ToObject<List<GroupedByDateViewModel>>();
|
||||
|
||||
return new PartialViewResult()
|
||||
return Partial("_GroupedByDateViewTablePartial", new _GroupedByDateViewTablePartialModel()
|
||||
{
|
||||
ViewName = "_GroupedByDateViewTablePartial",
|
||||
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
|
||||
{
|
||||
Model = new _GroupedByDateViewTablePartialModel()
|
||||
{
|
||||
DataType = dataType,
|
||||
Days = days.ToArray(),
|
||||
DaysPagination = JsonConvert.DeserializeObject<PaginationMetadata>(responseDays.Headers.GetValues("paging-headers").Single()),
|
||||
}
|
||||
}
|
||||
};
|
||||
DataType = dataType,
|
||||
Days = days.ToArray(),
|
||||
DaysPagination = JsonConvert.DeserializeObject<PaginationMetadata>(responseDays.Headers.GetValues("paging-headers").Single()),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// memory cache
|
||||
/// </summary>
|
||||
private readonly IMemoryCache _memoryCache;
|
||||
|
||||
/// <summary>
|
||||
/// configration file reader (appsettings.json)
|
||||
/// </summary>
|
||||
private readonly IConfiguration Configuration;
|
||||
|
||||
/// <summary>
|
||||
/// constructor
|
||||
/// </summary>
|
||||
/// <param name="httpClient"></param>
|
||||
/// <param name="memoryCache"></param>
|
||||
/// <param name="configuration"></param>
|
||||
public ContribsModel(HttpClient httpClient, IMemoryCache memoryCache, IConfiguration configuration) : base(httpClient)
|
||||
public ContribsModel(HttpClient httpClient, IConfiguration configuration, PoetCacheService poetCache) : base(httpClient, configuration)
|
||||
{
|
||||
_memoryCache = memoryCache;
|
||||
Configuration
|
||||
= configuration;
|
||||
_poetCache = poetCache;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using GanjooRazor.Utils;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using RMuseum.Models.FAQ;
|
||||
using RMuseum.Models.Ganjoor.ViewModels;
|
||||
using RSecurityBackend.Models.Auth.ViewModels;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
@ -15,6 +14,8 @@ namespace GanjooRazor.Pages
|
||||
[IgnoreAntiforgeryToken(Order = 1001)]
|
||||
public class FAQModel : LoginPartialEnabledPageModel
|
||||
{
|
||||
private readonly PoetCacheService _poetCache;
|
||||
|
||||
public string LastError { get; set; }
|
||||
|
||||
public List<GanjoorPoetViewModel> Poets { get; set; }
|
||||
@ -23,43 +24,32 @@ namespace GanjooRazor.Pages
|
||||
|
||||
public FAQItem Question { get; set; }
|
||||
|
||||
private async Task<bool> preparePoets()
|
||||
{
|
||||
var response = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/poets");
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
LastError = JsonConvert.DeserializeObject<string>(await response.Content.ReadAsStringAsync());
|
||||
return false;
|
||||
}
|
||||
Poets = JArray.Parse(await response.Content.ReadAsStringAsync()).ToObject<List<GanjoorPoetViewModel>>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<IActionResult> OnGetAsync()
|
||||
{
|
||||
if (bool.Parse(Configuration["MaintenanceMode"]))
|
||||
var maintenanceResult = TryGetMaintenanceModeResult();
|
||||
if (maintenanceResult != null)
|
||||
{
|
||||
return StatusCode(503);
|
||||
return maintenanceResult;
|
||||
}
|
||||
|
||||
ViewData["Title"] = $"گنجور » پرسشهای متداول";
|
||||
LoggedIn = !string.IsNullOrEmpty(Request.Cookies["Token"]);
|
||||
InitializeCommonPageState();
|
||||
|
||||
|
||||
ViewData["TrackingScript"] = Configuration["TrackingScript"] != null && string.IsNullOrEmpty(Request.Cookies["Token"]) ? Configuration["TrackingScript"].Replace("loggedon", "") : Configuration["TrackingScript"];
|
||||
|
||||
//todo: use html master layout or make it partial
|
||||
if (false == (await preparePoets()))
|
||||
var (poetsOk, poets, poetsError) = await _poetCache.GetPoetsAsync(AggressiveCacheEnabled);
|
||||
if (!poetsOk)
|
||||
{
|
||||
LastError = poetsError;
|
||||
return Page();
|
||||
}
|
||||
Poets = poets;
|
||||
|
||||
if(!string.IsNullOrEmpty(Request.Query["id"]))
|
||||
if (!string.IsNullOrEmpty(Request.Query["id"]))
|
||||
{
|
||||
var response = await _httpClient.GetAsync($"{APIRoot.Url}/api/faq/{Request.Query["id"]}");
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
LastError = JsonConvert.DeserializeObject<string>(await response.Content.ReadAsStringAsync());
|
||||
if(string.IsNullOrEmpty(LastError))
|
||||
LastError = await ReadErrorMessageAsync(response);
|
||||
if (string.IsNullOrEmpty(LastError))
|
||||
{
|
||||
LastError = $"خطا در دریافت اطلاعات پرسش مد نظر - کد خطا = {response.StatusCode}";
|
||||
}
|
||||
@ -73,7 +63,7 @@ namespace GanjooRazor.Pages
|
||||
var response = await _httpClient.GetAsync($"{APIRoot.Url}/api/faq/pinned");
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
LastError = JsonConvert.DeserializeObject<string>(await response.Content.ReadAsStringAsync());
|
||||
LastError = await ReadErrorMessageAsync(response);
|
||||
return Page();
|
||||
}
|
||||
PinnedItemsCategories = JArray.Parse(await response.Content.ReadAsStringAsync()).ToObject<List<FAQCategory>>();
|
||||
@ -82,21 +72,12 @@ namespace GanjooRazor.Pages
|
||||
return Page();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// configration file reader (appsettings.json)
|
||||
/// </summary>
|
||||
private readonly IConfiguration Configuration;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// constructor
|
||||
/// </summary>
|
||||
/// <param name="httpClient"></param>
|
||||
/// <param name="configuration"></param>
|
||||
public FAQModel(HttpClient httpClient, IConfiguration configuration) : base(httpClient)
|
||||
public FAQModel(HttpClient httpClient, IConfiguration configuration, PoetCacheService poetCache) : base(httpClient, configuration)
|
||||
{
|
||||
Configuration
|
||||
= configuration;
|
||||
_poetCache = poetCache;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,11 +28,6 @@ namespace GanjooRazor.Pages
|
||||
/// </summary>
|
||||
private readonly IMemoryCache _memoryCache;
|
||||
|
||||
/// <summary>
|
||||
/// configration file reader (appsettings.json)
|
||||
/// </summary>
|
||||
private readonly IConfiguration Configuration;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// constructor
|
||||
@ -40,29 +35,9 @@ namespace GanjooRazor.Pages
|
||||
/// <param name="httpClient"></param>
|
||||
/// <param name="memoryCache"></param>
|
||||
/// <param name="configuration"></param>
|
||||
public HashiehaModel(HttpClient httpClient, IMemoryCache memoryCache, IConfiguration configuration) : base(httpClient)
|
||||
public HashiehaModel(HttpClient httpClient, IMemoryCache memoryCache, IConfiguration configuration) : base(httpClient, configuration)
|
||||
{
|
||||
_memoryCache = memoryCache;
|
||||
Configuration
|
||||
= configuration;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// aggressive cache
|
||||
/// </summary>
|
||||
public bool AggressiveCacheEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return bool.Parse(Configuration["AggressiveCacheEnabled"]);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<GanjoorPoetViewModel> Poets { get; set; }
|
||||
|
||||
@ -3,7 +3,6 @@ using GanjooRazor.Utils;
|
||||
using KontorService.Models.Reporting.ViewModels;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
@ -45,19 +44,10 @@ namespace GanjooRazor.Pages
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// configration file reader (appsettings.json)
|
||||
/// poet list/detail cache (shared with Books, Contribs, FAQ, Quotes, and eventually
|
||||
/// Hashieha/Search/Simi once they're migrated too)
|
||||
/// </summary>
|
||||
private readonly IConfiguration Configuration;
|
||||
|
||||
/// <summary>
|
||||
/// memory cache
|
||||
/// </summary>
|
||||
private readonly IMemoryCache _memoryCache;
|
||||
|
||||
/// <summary>
|
||||
/// aggressive cache
|
||||
/// </summary>
|
||||
public bool AggressiveCacheEnabled => GetConfigFlag("AggressiveCacheEnabled");
|
||||
private readonly PoetCacheService _poetCache;
|
||||
|
||||
public bool OfflineMode => GetConfigFlag("OfflineMode");
|
||||
|
||||
@ -68,14 +58,13 @@ namespace GanjooRazor.Pages
|
||||
/// </summary>
|
||||
/// <param name="configuration"></param>
|
||||
/// <param name="httpClient"></param>
|
||||
/// <param name="memoryCache"></param>
|
||||
/// <param name="poetCache"></param>
|
||||
public IndexModel(IConfiguration configuration,
|
||||
HttpClient httpClient,
|
||||
IMemoryCache memoryCache
|
||||
) : base(httpClient)
|
||||
PoetCacheService poetCache
|
||||
) : base(httpClient, configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
_memoryCache = memoryCache;
|
||||
_poetCache = poetCache;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -89,20 +78,11 @@ namespace GanjooRazor.Pages
|
||||
public GanjoorSiteBannerViewModel Banner { get; set; }
|
||||
|
||||
#region Shared helpers
|
||||
// GetConfigFlag and CaptureErrorIfFailedAsync stay local to this class since they touch
|
||||
// IndexModel-specific state (Configuration, LastError). NotLoggedInMessage,
|
||||
// ReadErrorMessageAsync, and WithSecureClientAsync now live on GanjoorPageModelBase
|
||||
// (inherited via LoginPartialEnabledPageModel) since they're used across every page model,
|
||||
// not just this one.
|
||||
|
||||
/// <summary>
|
||||
/// Reads a boolean feature flag from configuration, defaulting to <paramref name="defaultValue"/>
|
||||
/// if the key is missing or not a valid bool, instead of each flag having its own try/catch.
|
||||
/// </summary>
|
||||
private bool GetConfigFlag(string key, bool defaultValue = false)
|
||||
{
|
||||
return bool.TryParse(Configuration[key], out var value) ? value : defaultValue;
|
||||
}
|
||||
// CaptureErrorIfFailedAsync stays local to this class since it touches IndexModel-specific
|
||||
// state (LastError). GetConfigFlag, AggressiveCacheEnabled, NotLoggedInMessage,
|
||||
// ReadErrorMessageAsync, and WithSecureClientAsync now live on GanjoorPageModelBase /
|
||||
// LoginPartialEnabledPageModel (inherited) since they're used across every page model, not
|
||||
// just this one.
|
||||
|
||||
/// <summary>
|
||||
/// If the response failed, stores the API's error message in <see cref="LastError"/> and
|
||||
@ -446,30 +426,12 @@ namespace GanjooRazor.Pages
|
||||
|
||||
private async Task<bool> preparePoets()
|
||||
{
|
||||
const string cacheKey = "/api/ganjoor/poets";
|
||||
if (!_memoryCache.TryGetValue(cacheKey, out List<GanjoorPoetViewModel> poets))
|
||||
var (success, poets, error) = await _poetCache.GetPoetsAsync(AggressiveCacheEnabled);
|
||||
if (!success)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/poets");
|
||||
if (await CaptureErrorIfFailedAsync(response))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
poets = JArray.Parse(await response.Content.ReadAsStringAsync()).ToObject<List<GanjoorPoetViewModel>>();
|
||||
if (AggressiveCacheEnabled)
|
||||
{
|
||||
_memoryCache.Set(cacheKey, poets, TimeSpan.FromHours(1));
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
LastError = "خطا در دسترسی به وب سرویس گنجور";
|
||||
return false;
|
||||
}
|
||||
|
||||
LastError = error;
|
||||
return false;
|
||||
}
|
||||
|
||||
Poets = poets;
|
||||
return true;
|
||||
}
|
||||
@ -477,20 +439,13 @@ namespace GanjooRazor.Pages
|
||||
public async Task<IActionResult> OnGetPoetInformationAsync(int id)
|
||||
{
|
||||
if (id == 0)
|
||||
return new OkObjectResult(null);
|
||||
var cacheKey = $"/api/ganjoor/poet/{id}";
|
||||
if (!_memoryCache.TryGetValue(cacheKey, out GanjoorPoetCompleteViewModel poet))
|
||||
{
|
||||
var poetResponse = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/poet/{id}");
|
||||
if (!poetResponse.IsSuccessStatusCode)
|
||||
{
|
||||
return BadRequest(await ReadErrorMessageAsync(poetResponse));
|
||||
}
|
||||
poet = JObject.Parse(await poetResponse.Content.ReadAsStringAsync()).ToObject<GanjoorPoetCompleteViewModel>();
|
||||
if (AggressiveCacheEnabled)
|
||||
{
|
||||
_memoryCache.Set(cacheKey, poet, TimeSpan.FromHours(1));
|
||||
}
|
||||
return new OkObjectResult(null);
|
||||
}
|
||||
var (success, poet, error) = await _poetCache.GetPoetAsync(id, AggressiveCacheEnabled);
|
||||
if (!success)
|
||||
{
|
||||
return BadRequest(error);
|
||||
}
|
||||
return new OkObjectResult(poet);
|
||||
}
|
||||
@ -624,9 +579,10 @@ namespace GanjooRazor.Pages
|
||||
/// <returns></returns>
|
||||
public async Task<IActionResult> OnGetAsync()
|
||||
{
|
||||
if (GetConfigFlag("MaintenanceMode"))
|
||||
var maintenanceResult = TryGetMaintenanceModeResult();
|
||||
if (maintenanceResult != null)
|
||||
{
|
||||
return StatusCode(503);
|
||||
return maintenanceResult;
|
||||
}
|
||||
|
||||
var legacyRedirect = TryHandleLegacyUrlRedirect();
|
||||
@ -705,7 +661,7 @@ namespace GanjooRazor.Pages
|
||||
private void InitializeRequestState()
|
||||
{
|
||||
LastError = "";
|
||||
LoggedIn = !string.IsNullOrEmpty(Request.Cookies["Token"]);
|
||||
InitializeCommonPageState();
|
||||
CanEdit = Request.Cookies["CanEdit"] == "True";
|
||||
KeepHistory = Request.Cookies["KeepHistory"] == "True";
|
||||
CanTranslate = Request.Cookies["CanTranslate"] == "True";
|
||||
@ -715,9 +671,6 @@ namespace GanjooRazor.Pages
|
||||
IsHomePage = Request.Path == "/";
|
||||
PinterestUrl = Request.Query["pinterest_url"];
|
||||
ShowAllRecitaions = Request.Query["allaudio"] == "1";
|
||||
ViewData["TrackingScript"] = Configuration["TrackingScript"] != null && string.IsNullOrEmpty(Request.Cookies["Token"])
|
||||
? Configuration["TrackingScript"].Replace("loggedon", "")
|
||||
: Configuration["TrackingScript"];
|
||||
ActiveTab = Request.Query["tab"];
|
||||
|
||||
if (ShowAllRecitaions && string.IsNullOrEmpty(ActiveTab))
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace GanjooRazor.Pages
|
||||
@ -7,7 +8,7 @@ namespace GanjooRazor.Pages
|
||||
public class LoginModel : LoginPartialEnabledPageModel
|
||||
{
|
||||
|
||||
public LoginModel(HttpClient httpClient) : base(httpClient) { }
|
||||
public LoginModel(HttpClient httpClient, IConfiguration configuration) : base(httpClient, configuration) { }
|
||||
public string UserFriendlyName { get; set; }
|
||||
|
||||
public string LastError { get; set; }
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
using GanjooRazor.Utils;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Newtonsoft.Json;
|
||||
using RMuseum.Models.Auth.Memory;
|
||||
using RMuseum.Models.Auth.ViewModel;
|
||||
@ -21,6 +22,57 @@ namespace GanjooRazor.Pages
|
||||
{
|
||||
public class LoginPartialEnabledPageModel : GanjoorPageModelBase
|
||||
{
|
||||
/// <summary>
|
||||
/// configuration file reader (appsettings.json). Was previously duplicated as a private field
|
||||
/// on almost every page model that derives from this class (Index, Contribs, Quotes, FAQ,
|
||||
/// Books, Hashieha, Search, Simi all had their own copy).
|
||||
/// </summary>
|
||||
protected readonly IConfiguration Configuration;
|
||||
|
||||
/// <summary>
|
||||
/// Reads a boolean feature flag from configuration, defaulting to <paramref name="defaultValue"/>
|
||||
/// if the key is missing or not a valid bool. Was previously a per-page try/catch block
|
||||
/// (and in IndexModel's case, was the ONLY one of these that had the try/catch at all -
|
||||
/// every other page's `bool.Parse(Configuration["MaintenanceMode"])` below would throw on a
|
||||
/// missing/malformed config key instead of defaulting to false).
|
||||
/// </summary>
|
||||
protected bool GetConfigFlag(string key, bool defaultValue = false)
|
||||
{
|
||||
return bool.TryParse(Configuration[key], out var value) ? value : defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// aggressive cache flag. Every page model that had this property defined it identically -
|
||||
/// same try/catch-wrapped bool.Parse now handled once by GetConfigFlag.
|
||||
/// </summary>
|
||||
protected bool AggressiveCacheEnabled => GetConfigFlag("AggressiveCacheEnabled");
|
||||
|
||||
/// <summary>
|
||||
/// Returns a 503 result if the site is in maintenance mode, or null otherwise. Was previously
|
||||
/// `if (bool.Parse(Configuration["MaintenanceMode"])) { return StatusCode(503); }` duplicated
|
||||
/// verbatim at the top of OnGetAsync in 8 different page models, all without try/catch (so a
|
||||
/// missing "MaintenanceMode" config key would throw a FormatException/ArgumentNullException
|
||||
/// instead of just... not being in maintenance mode).
|
||||
/// </summary>
|
||||
protected IActionResult TryGetMaintenanceModeResult()
|
||||
{
|
||||
return GetConfigFlag("MaintenanceMode") ? StatusCode(503) : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the two pieces of per-request state that were duplicated character-for-character
|
||||
/// across every page model in this hierarchy: whether the current visitor is logged in, and
|
||||
/// the tracking script to render (with "loggedon" stripped out for anonymous visitors).
|
||||
/// Call once near the top of each page's OnGetAsync instead of repeating both lines.
|
||||
/// </summary>
|
||||
protected void InitializeCommonPageState()
|
||||
{
|
||||
LoggedIn = !string.IsNullOrEmpty(Request.Cookies["Token"]);
|
||||
ViewData["TrackingScript"] = Configuration["TrackingScript"] != null && string.IsNullOrEmpty(Request.Cookies["Token"])
|
||||
? Configuration["TrackingScript"].Replace("loggedon", "")
|
||||
: Configuration["TrackingScript"];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// is logged on
|
||||
/// </summary>
|
||||
@ -175,8 +227,9 @@ namespace GanjooRazor.Pages
|
||||
});
|
||||
}
|
||||
|
||||
public LoginPartialEnabledPageModel(HttpClient httpClient) : base(httpClient)
|
||||
public LoginPartialEnabledPageModel(HttpClient httpClient, IConfiguration configuration) : base(httpClient)
|
||||
{
|
||||
Configuration = configuration;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -304,14 +304,10 @@ namespace GanjooRazor.Pages
|
||||
return new OkResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// configration file reader (appsettings.json)
|
||||
/// </summary>
|
||||
private readonly IConfiguration Configuration;
|
||||
|
||||
public PhotosModel(HttpClient httpClient, IConfiguration configuration) : base(httpClient)
|
||||
public PhotosModel(HttpClient httpClient, IConfiguration configuration) : base(httpClient, configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using GanjooRazor.Utils;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using RMuseum.Models.Ganjoor.ViewModels;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
@ -12,56 +12,52 @@ namespace GanjooRazor.Pages
|
||||
[IgnoreAntiforgeryToken(Order = 1001)]
|
||||
public class QuotesModel : LoginPartialEnabledPageModel
|
||||
{
|
||||
private readonly IConfiguration Configuration;
|
||||
public QuotesModel(HttpClient httpClient, IConfiguration configuration) : base(httpClient)
|
||||
private readonly PoetCacheService _poetCache;
|
||||
|
||||
public QuotesModel(HttpClient httpClient, IConfiguration configuration, PoetCacheService poetCache) : base(httpClient, configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
_poetCache = poetCache;
|
||||
}
|
||||
|
||||
public string LastError { get; set; }
|
||||
public List<GanjoorPoetViewModel> Poets { get; set; }
|
||||
public GanjoorPoetViewModel Poet { get; set; }
|
||||
public List<GanjoorQuotedPoemViewModel> ClaimedQuotes { get; set; }
|
||||
public List<GanjoorQuotedPoemViewModel> Quotes { get; set; }
|
||||
|
||||
private async Task<bool> preparePoets()
|
||||
{
|
||||
var response = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/poets");
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
LastError = JsonConvert.DeserializeObject<string>(await response.Content.ReadAsStringAsync());
|
||||
return false;
|
||||
}
|
||||
Poets = JArray.Parse(await response.Content.ReadAsStringAsync()).ToObject<List<GanjoorPoetViewModel>>();
|
||||
|
||||
return true;
|
||||
}
|
||||
public async Task<IActionResult> OnGetAsync()
|
||||
{
|
||||
if (bool.Parse(Configuration["MaintenanceMode"]))
|
||||
var maintenanceResult = TryGetMaintenanceModeResult();
|
||||
if (maintenanceResult != null)
|
||||
{
|
||||
return StatusCode(503);
|
||||
return maintenanceResult;
|
||||
}
|
||||
|
||||
LoggedIn = !string.IsNullOrEmpty(Request.Cookies["Token"]);
|
||||
ViewData["TrackingScript"] = Configuration["TrackingScript"] != null && string.IsNullOrEmpty(Request.Cookies["Token"]) ? Configuration["TrackingScript"].Replace("loggedon", "") : Configuration["TrackingScript"];
|
||||
InitializeCommonPageState();
|
||||
|
||||
//todo: use html master layout or make it partial
|
||||
if (false == (await preparePoets()))
|
||||
var (poetsOk, poets, poetsError) = await _poetCache.GetPoetsAsync(AggressiveCacheEnabled);
|
||||
if (!poetsOk)
|
||||
{
|
||||
LastError = poetsError;
|
||||
return Page();
|
||||
}
|
||||
Poets = poets;
|
||||
|
||||
if (!string.IsNullOrEmpty(Request.Query["p"]))
|
||||
{
|
||||
// Fetched by URL slug rather than id, and returns the "complete" poet shape rather
|
||||
// than the list shape - different enough from PoetCacheService's GetPoetAsync(id)
|
||||
// that it stays a direct call here rather than being folded into that service.
|
||||
var response = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/poet?url=/{Request.Query["p"]}");
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
LastError = JsonConvert.DeserializeObject<string>(await response.Content.ReadAsStringAsync());
|
||||
LastError = await ReadErrorMessageAsync(response);
|
||||
return Page();
|
||||
}
|
||||
Poet = JObject.Parse(await response.Content.ReadAsStringAsync()).ToObject<GanjoorPoetCompleteViewModel>().Poet;
|
||||
Poet.ImageUrl = $"{APIRoot.InternetUrl}{Poet.ImageUrl}";
|
||||
}
|
||||
|
||||
|
||||
var url = $"{APIRoot.Url}/api/ganjoor/quoted?published=true";
|
||||
if (Poet != null)
|
||||
{
|
||||
@ -70,19 +66,17 @@ namespace GanjooRazor.Pages
|
||||
var responseQuotes = await _httpClient.GetAsync(url + "&claimed=false");
|
||||
if (!responseQuotes.IsSuccessStatusCode)
|
||||
{
|
||||
LastError = JsonConvert.DeserializeObject<string>(await responseQuotes.Content.ReadAsStringAsync());
|
||||
LastError = await ReadErrorMessageAsync(responseQuotes);
|
||||
return Page();
|
||||
}
|
||||
|
||||
Quotes = JArray.Parse(await responseQuotes.Content.ReadAsStringAsync()).ToObject<List<GanjoorQuotedPoemViewModel>>();
|
||||
|
||||
var responseClaimedQuotes = await _httpClient.GetAsync(url + "&claimed=true");
|
||||
if (!responseClaimedQuotes.IsSuccessStatusCode)
|
||||
{
|
||||
LastError = JsonConvert.DeserializeObject<string>(await responseClaimedQuotes.Content.ReadAsStringAsync());
|
||||
LastError = await ReadErrorMessageAsync(responseClaimedQuotes);
|
||||
return Page();
|
||||
}
|
||||
|
||||
ClaimedQuotes = JArray.Parse(await responseClaimedQuotes.Content.ReadAsStringAsync()).ToObject<List<GanjoorQuotedPoemViewModel>>();
|
||||
|
||||
ViewData["Title"] = Poet == null ? "نقل قولهای شاعران" : $"نقل قولها و شعرهای مرتبط {Poet.Nickname}";
|
||||
|
||||
@ -28,10 +28,6 @@ namespace GanjooRazor.Pages
|
||||
/// </summary>
|
||||
private readonly IMemoryCache _memoryCache;
|
||||
|
||||
/// <summary>
|
||||
/// configration file reader (appsettings.json)
|
||||
/// </summary>
|
||||
private readonly IConfiguration Configuration;
|
||||
|
||||
|
||||
/// <summary>
|
||||
@ -40,29 +36,9 @@ namespace GanjooRazor.Pages
|
||||
/// <param name="httpClient"></param>
|
||||
/// <param name="memoryCache"></param>
|
||||
/// <param name="configuration"></param>
|
||||
public SearchModel(HttpClient httpClient, IMemoryCache memoryCache, IConfiguration configuration) : base(httpClient)
|
||||
public SearchModel(HttpClient httpClient, IMemoryCache memoryCache, IConfiguration configuration) : base(httpClient, configuration)
|
||||
{
|
||||
_memoryCache = memoryCache;
|
||||
Configuration
|
||||
= configuration;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// aggressive cache
|
||||
/// </summary>
|
||||
public bool AggressiveCacheEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return bool.Parse(Configuration["AggressiveCacheEnabled"]);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<GanjoorPoetViewModel> Poets { get; set; }
|
||||
|
||||
@ -28,10 +28,6 @@ namespace GanjooRazor.Pages
|
||||
/// </summary>
|
||||
private readonly IMemoryCache _memoryCache;
|
||||
|
||||
/// <summary>
|
||||
/// configration file reader (appsettings.json)
|
||||
/// </summary>
|
||||
private readonly IConfiguration Configuration;
|
||||
|
||||
|
||||
/// <summary>
|
||||
@ -40,29 +36,9 @@ namespace GanjooRazor.Pages
|
||||
/// <param name="httpClient"></param>
|
||||
/// <param name="memoryCache"></param>
|
||||
/// <param name="configuration"></param>
|
||||
public SimiModel(HttpClient httpClient, IMemoryCache memoryCache, IConfiguration configuration) : base(httpClient)
|
||||
public SimiModel(HttpClient httpClient, IMemoryCache memoryCache, IConfiguration configuration) : base(httpClient, configuration)
|
||||
{
|
||||
_memoryCache = memoryCache;
|
||||
Configuration
|
||||
= configuration;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// aggressive cache
|
||||
/// </summary>
|
||||
public bool AggressiveCacheEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return bool.Parse(Configuration["AggressiveCacheEnabled"]);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<GanjoorPoetViewModel> Poets { get; set; }
|
||||
|
||||
@ -25,11 +25,7 @@ namespace GanjooRazor.Pages
|
||||
/// </summary>
|
||||
private readonly IMemoryCache _memoryCache;
|
||||
|
||||
/// <summary>
|
||||
/// configration file reader (appsettings.json)
|
||||
/// </summary>
|
||||
private readonly IConfiguration Configuration;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// constructor
|
||||
@ -37,30 +33,11 @@ namespace GanjooRazor.Pages
|
||||
/// <param name="httpClient"></param>
|
||||
/// <param name="memoryCache"></param>
|
||||
/// <param name="configuration"></param>
|
||||
public TaggedModel(HttpClient httpClient, IMemoryCache memoryCache, IConfiguration configuration) : base(httpClient)
|
||||
public TaggedModel(HttpClient httpClient, IMemoryCache memoryCache, IConfiguration configuration) : base(httpClient, configuration)
|
||||
{
|
||||
_memoryCache = memoryCache;
|
||||
Configuration
|
||||
= configuration;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// aggressive cache
|
||||
/// </summary>
|
||||
public bool AggressiveCacheEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return bool.Parse(Configuration["AggressiveCacheEnabled"]);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<GanjoorPoetViewModel> Poets { get; set; }
|
||||
public int PoetId { get; set; }
|
||||
|
||||
@ -24,6 +24,8 @@ namespace GanjooRazor
|
||||
|
||||
services.AddMemoryCache();
|
||||
|
||||
services.AddScoped<GanjooRazor.Utils.PoetCacheService>();
|
||||
|
||||
services.AddSingleton(
|
||||
HtmlEncoder.Create(allowedRanges: new[] { UnicodeRanges.BasicLatin,
|
||||
UnicodeRanges.Arabic }));
|
||||
|
||||
85
GanjooRazor/Utils/PoetCacheService.cs
Normal file
85
GanjooRazor/Utils/PoetCacheService.cs
Normal file
@ -0,0 +1,85 @@
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using RMuseum.Models.Ganjoor.ViewModels;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GanjooRazor.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// Fetches the poet list and individual poet details from the Ganjoor API, optionally caching
|
||||
/// the results in-memory. This logic (fetch-or-return-cached, deserialize, cache if enabled) was
|
||||
/// previously copy-pasted as three near-identical private methods (a "get all poets" fetcher, a
|
||||
/// "get one poet by id and store on Model.Poet" fetcher, and an "get one poet by id and return as
|
||||
/// JSON" AJAX handler) in IndexModel, ContribsModel, HashiehaModel, SearchModel, and SimiModel.
|
||||
///
|
||||
/// Registered as a scoped service in Startup.cs; inject via constructor like any other service.
|
||||
/// </summary>
|
||||
public class PoetCacheService
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly IMemoryCache _memoryCache;
|
||||
|
||||
public PoetCacheService(HttpClient httpClient, IMemoryCache memoryCache)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_memoryCache = memoryCache;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the full poet list. Returns (true, poets, null) on success, or (false, null, error)
|
||||
/// on failure - callers decide what to do with the error (set LastError and return Page(),
|
||||
/// return BadRequest(error), etc.) since that varies per caller.
|
||||
/// </summary>
|
||||
public async Task<(bool success, List<GanjoorPoetViewModel> poets, string error)> GetPoetsAsync(bool cacheResult)
|
||||
{
|
||||
const string cacheKey = "/api/ganjoor/poets";
|
||||
if (_memoryCache.TryGetValue(cacheKey, out List<GanjoorPoetViewModel> poets))
|
||||
{
|
||||
return (true, poets, null);
|
||||
}
|
||||
|
||||
var response = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/poets");
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
return (false, null, JsonConvert.DeserializeObject<string>(await response.Content.ReadAsStringAsync()));
|
||||
}
|
||||
|
||||
poets = JArray.Parse(await response.Content.ReadAsStringAsync()).ToObject<List<GanjoorPoetViewModel>>();
|
||||
if (cacheResult)
|
||||
{
|
||||
_memoryCache.Set(cacheKey, poets, TimeSpan.FromHours(1));
|
||||
}
|
||||
return (true, poets, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a single poet's full details by id. Returns (true, poet, null) on success, or
|
||||
/// (false, null, error) on failure.
|
||||
/// </summary>
|
||||
public async Task<(bool success, GanjoorPoetCompleteViewModel poet, string error)> GetPoetAsync(int poetId, bool cacheResult)
|
||||
{
|
||||
var cacheKey = $"/api/ganjoor/poet/{poetId}";
|
||||
if (_memoryCache.TryGetValue(cacheKey, out GanjoorPoetCompleteViewModel poet))
|
||||
{
|
||||
return (true, poet, null);
|
||||
}
|
||||
|
||||
var response = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/poet/{poetId}");
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
return (false, null, JsonConvert.DeserializeObject<string>(await response.Content.ReadAsStringAsync()));
|
||||
}
|
||||
|
||||
poet = JObject.Parse(await response.Content.ReadAsStringAsync()).ToObject<GanjoorPoetCompleteViewModel>();
|
||||
if (cacheResult)
|
||||
{
|
||||
_memoryCache.Set(cacheKey, poet, TimeSpan.FromHours(1));
|
||||
}
|
||||
return (true, poet, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user