book list api
This commit is contained in:
parent
2651e603c4
commit
b8c45ed93c
@ -59,6 +59,50 @@ namespace RMuseum.Controllers
|
||||
return Ok(poets);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// get list of books (GanjoorCat entries whose CatType is Book, sorted alphabetically by name),
|
||||
/// optionally filtered by (part of) name and/or poet id. Not to be confused with
|
||||
/// GetBooksAsync()/"books" above, which lists GanjoorCat entries by their (separate,
|
||||
/// legacy) BookName field for cover-image generation.
|
||||
/// </summary>
|
||||
/// <param name="name">optional, only books whose name contains this</param>
|
||||
/// <param name="poetId">optional, only books belonging to this poet</param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[Route("book-catalog")]
|
||||
[AllowAnonymous]
|
||||
[ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorBookViewModel[]))]
|
||||
[ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))]
|
||||
public async Task<IActionResult> GetBookCatalog(string name = null, int? poetId = null)
|
||||
{
|
||||
// only the common, unfiltered call (the one the home page's book search will use to load
|
||||
// the full list once and filter client-side) is worth caching - a filtered call is cheap
|
||||
// on a table this small (well under 200 rows) and caching every name/poetId combination
|
||||
// would just grow the cache for no benefit.
|
||||
if (string.IsNullOrEmpty(name) && poetId == null)
|
||||
{
|
||||
var cacheKey = $"ganjoor/book-catalog";
|
||||
if (!_memoryCache.TryGetValue(cacheKey, out GanjoorBookViewModel[] cachedBooks))
|
||||
{
|
||||
RServiceResult<GanjoorBookViewModel[]> cachedRes =
|
||||
await _ganjoorService.GetBookCatalogAsync();
|
||||
if (!string.IsNullOrEmpty(cachedRes.ExceptionString))
|
||||
return BadRequest(cachedRes.ExceptionString);
|
||||
|
||||
cachedBooks = cachedRes.Result;
|
||||
if (AggressiveCacheEnabled)
|
||||
_memoryCache.Set(cacheKey, cachedBooks, TimeSpan.FromHours(1));
|
||||
}
|
||||
return Ok(cachedBooks);
|
||||
}
|
||||
|
||||
RServiceResult<GanjoorBookViewModel[]> res =
|
||||
await _ganjoorService.GetBookCatalogAsync(name, poetId);
|
||||
if (!string.IsNullOrEmpty(res.ExceptionString))
|
||||
return BadRequest(res.ExceptionString);
|
||||
return Ok(res.Result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// gets list of poets grouped by centuries (first one is the pinned ones)
|
||||
/// </summary>
|
||||
|
||||
39
RMuseum/Models/Ganjoor/ViewModels/GanjoorBookViewModel.cs
Normal file
39
RMuseum/Models/Ganjoor/ViewModels/GanjoorBookViewModel.cs
Normal file
@ -0,0 +1,39 @@
|
||||
namespace RMuseum.Models.Ganjoor.ViewModels
|
||||
{
|
||||
/// <summary>
|
||||
/// A GanjoorCat whose CatType is Book - a minimal view model for listing/searching books
|
||||
/// (e.g. the home page's book search box), not the full category details
|
||||
/// </summary>
|
||||
public class GanjoorBookViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// id (GanjoorCat.Id)
|
||||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// book name (GanjoorCat.Title)
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// full url, sample: /hafez/ghazal
|
||||
/// </summary>
|
||||
public string FullUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// poet id (GanjoorCat.PoetId)
|
||||
/// </summary>
|
||||
public int PoetId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// poet short name (GanjoorPoet.Nickname)
|
||||
/// </summary>
|
||||
public string PoetName { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1096,6 +1096,17 @@
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:RMuseum.Controllers.GanjoorController.GetBookCatalog(System.String,System.Nullable{System.Int32})">
|
||||
<summary>
|
||||
get list of books (GanjoorCat entries whose CatType is Book, sorted alphabetically by name),
|
||||
optionally filtered by (part of) name and/or poet id. Not to be confused with
|
||||
GetBooksAsync()/"books" above, which lists GanjoorCat entries by their (separate,
|
||||
legacy) BookName field for cover-image generation.
|
||||
</summary>
|
||||
<param name="name">optional, only books whose name contains this</param>
|
||||
<param name="poetId">optional, only books belonging to this poet</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:RMuseum.Controllers.GanjoorController.GetCenturiesAsync">
|
||||
<summary>
|
||||
gets list of poets grouped by centuries (first one is the pinned ones)
|
||||
@ -12578,6 +12589,37 @@
|
||||
simulate naming
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:RMuseum.Models.Ganjoor.ViewModels.GanjoorBookViewModel">
|
||||
<summary>
|
||||
A GanjoorCat whose CatType is Book - a minimal view model for listing/searching books
|
||||
(e.g. the home page's book search box), not the full category details
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:RMuseum.Models.Ganjoor.ViewModels.GanjoorBookViewModel.Id">
|
||||
<summary>
|
||||
id (GanjoorCat.Id)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:RMuseum.Models.Ganjoor.ViewModels.GanjoorBookViewModel.Name">
|
||||
<summary>
|
||||
book name (GanjoorCat.Title)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:RMuseum.Models.Ganjoor.ViewModels.GanjoorBookViewModel.FullUrl">
|
||||
<summary>
|
||||
full url, sample: /hafez/ghazal
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:RMuseum.Models.Ganjoor.ViewModels.GanjoorBookViewModel.PoetId">
|
||||
<summary>
|
||||
poet id (GanjoorCat.PoetId)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:RMuseum.Models.Ganjoor.ViewModels.GanjoorBookViewModel.PoetName">
|
||||
<summary>
|
||||
poet short name (GanjoorPoet.Nickname)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:RMuseum.Models.Ganjoor.ViewModels.GanjoorCatCorrectionViewModel.Id">
|
||||
<summary>
|
||||
correct id
|
||||
@ -18549,6 +18591,16 @@
|
||||
<param name="includeBio"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:RMuseum.Services.IGanjoorService.GetBookCatalogAsync(System.String,System.Nullable{System.Int32})">
|
||||
<summary>
|
||||
Get list of books (GanjoorCat entries whose CatType is Book), sorted alphabetically by name.
|
||||
Not to be confused with GetBooksAsync() below, which lists GanjoorCat entries by their
|
||||
(separate, legacy) BookName field for cover-image generation.
|
||||
</summary>
|
||||
<param name="name">optional, only books whose name contains this (case-insensitive)</param>
|
||||
<param name="poetId">optional, only books belonging to this poet</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:RMuseum.Services.IGanjoorService.GetPoetById(System.Int32,System.Boolean)">
|
||||
<summary>
|
||||
get poet by id
|
||||
@ -22286,6 +22338,9 @@
|
||||
<summary>
|
||||
IGanjoorService implementation
|
||||
</summary>
|
||||
<summary>
|
||||
IGanjoorService implementation
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:RMuseum.Services.Implementation.GanjoorService.SwitchCoupletBookmark(System.Guid,System.Int32,System.Int32)">
|
||||
<summary>
|
||||
@ -22366,6 +22421,16 @@
|
||||
<param name="q"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:RMuseum.Services.Implementation.GanjoorService.GetBookCatalogAsync(System.String,System.Nullable{System.Int32})">
|
||||
<summary>
|
||||
Get list of books (GanjoorCat entries whose CatType is Book), sorted alphabetically by name.
|
||||
Not to be confused with GetBooksAsync() elsewhere in this class, which lists GanjoorCat
|
||||
entries by their (separate, legacy) BookName field for cover-image generation.
|
||||
</summary>
|
||||
<param name="name">optional, only books whose name contains this (case-insensitive)</param>
|
||||
<param name="poetId">optional, only books belonging to this poet</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:RMuseum.Services.Implementation.GanjoorService.GetCategoryWordCountsAsync(System.Int32,System.String,RSecurityBackend.Models.Generic.PagingParameterModel)">
|
||||
<summary>
|
||||
category word counts
|
||||
|
||||
@ -22,6 +22,16 @@ namespace RMuseum.Services
|
||||
/// <returns></returns>
|
||||
Task<RServiceResult<GanjoorPoetViewModel[]>> GetPoets(bool published, bool includeBio = true);
|
||||
|
||||
/// <summary>
|
||||
/// Get list of books (GanjoorCat entries whose CatType is Book), sorted alphabetically by name.
|
||||
/// Not to be confused with GetBooksAsync() below, which lists GanjoorCat entries by their
|
||||
/// (separate, legacy) BookName field for cover-image generation.
|
||||
/// </summary>
|
||||
/// <param name="name">optional, only books whose name contains this (case-insensitive)</param>
|
||||
/// <param name="poetId">optional, only books belonging to this poet</param>
|
||||
/// <returns></returns>
|
||||
Task<RServiceResult<GanjoorBookViewModel[]>> GetBookCatalogAsync(string name = null, int? poetId = null);
|
||||
|
||||
/// <summary>
|
||||
/// get poet by id
|
||||
/// </summary>
|
||||
|
||||
@ -0,0 +1,61 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using RMuseum.Models.Ganjoor;
|
||||
using RMuseum.Models.Ganjoor.ViewModels;
|
||||
using RSecurityBackend.Models.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RMuseum.Services.Implementation
|
||||
{
|
||||
/// <summary>
|
||||
/// IGanjoorService implementation
|
||||
/// </summary>
|
||||
public partial class GanjoorService : IGanjoorService
|
||||
{
|
||||
/// <summary>
|
||||
/// Get list of books (GanjoorCat entries whose CatType is Book), sorted alphabetically by name.
|
||||
/// Not to be confused with GetBooksAsync() elsewhere in this class, which lists GanjoorCat
|
||||
/// entries by their (separate, legacy) BookName field for cover-image generation.
|
||||
/// </summary>
|
||||
/// <param name="name">optional, only books whose name contains this (case-insensitive)</param>
|
||||
/// <param name="poetId">optional, only books belonging to this poet</param>
|
||||
/// <returns></returns>
|
||||
public async Task<RServiceResult<GanjoorBookViewModel[]>> GetBookCatalogAsync(string name = null, int? poetId = null)
|
||||
{
|
||||
var query = _context.GanjoorCategories.AsNoTracking()
|
||||
.Where(c => c.CatType == GanjoorCatType.Book);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
query = query.Where(c => c.Title.Contains(name));
|
||||
}
|
||||
|
||||
if (poetId != null)
|
||||
{
|
||||
query = query.Where(c => c.PoetId == poetId.Value);
|
||||
}
|
||||
|
||||
List<GanjoorBookViewModel> books =
|
||||
await query
|
||||
.Select(c => new GanjoorBookViewModel()
|
||||
{
|
||||
Id = c.Id,
|
||||
Name = c.Title,
|
||||
FullUrl = c.FullUrl,
|
||||
PoetId = c.PoetId,
|
||||
PoetName = c.Poet.Nickname,
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
// the fa-IR comparer can't be translated to SQL, so sorting happens here in memory -
|
||||
// the same approach GetPoets() above uses, fine for a list this small (< 200 rows)
|
||||
StringComparer fa = StringComparer.Create(new CultureInfo("fa-IR"), true);
|
||||
books.Sort((a, b) => fa.Compare(a.Name, b.Name));
|
||||
|
||||
return new RServiceResult<GanjoorBookViewModel[]>(books.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user