using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Configuration; using Newtonsoft.Json; using RMuseum.Models.Auth.Memory; using RMuseum.Models.Auth.ViewModel; using RMuseum.Models.Ganjoor; using RMuseum.Models.Ganjoor.ViewModels; using RMuseum.Models.GanjoorAudio.ViewModels; using RMuseum.Services; using RSecurityBackend.Models.Auth.Memory; using RSecurityBackend.Models.Auth.ViewModels; using RSecurityBackend.Models.Generic; using RSecurityBackend.Models.Image; using RSecurityBackend.Services; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Threading.Tasks; namespace RMuseum.Controllers { [Produces("application/json")] [Route("api/ganjoor")] public class GanjoorController : Controller { /// /// get list of published poets without their biography /// /// [HttpGet] [Route("poets")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorPoetViewModel[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetPoets() { var cacheKey = $"ganjoor/poets"; if (!_memoryCache.TryGetValue(cacheKey, out GanjoorPoetViewModel[] poets)) { RServiceResult res = await _ganjoorService.GetPoets(true, false); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); poets = res.Result; if (AggressiveCacheEnabled) _memoryCache.Set(cacheKey, poets); } return Ok(poets); } /// /// gets list of poets grouped by centuries (first one is the pinned ones) /// /// [HttpGet] [Route("centuries")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorCenturyViewModel[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetCenturiesAsync() { var cacheKey = $"ganjoor/centuries"; if (!_memoryCache.TryGetValue(cacheKey, out GanjoorCenturyViewModel[] centuries)) { RServiceResult res = await _ganjoorService.GetCenturiesAsync(); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); centuries = res.Result; if (AggressiveCacheEnabled) _memoryCache.Set(cacheKey, centuries); } return Ok(centuries); } /// /// get list of all poets (including unpublished ones) with their bio /// /// [HttpGet] [Route("poets/secure")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorPoetViewModel[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetAllPoets() { RServiceResult res = await _ganjoorService.GetPoets(false, true); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// poet by id /// /// /// /// [HttpGet] [Route("poet/{id}")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorPoetCompleteViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task GetPoetById(int id, bool catPoems = false) { var cacheKey = $"poet/byid/{id}"; if (!_memoryCache.TryGetValue(cacheKey, out GanjoorPoetCompleteViewModel poet)) { RServiceResult res = await _ganjoorService.GetPoetById(id, catPoems); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); if (res.Result == null) return NotFound(); poet = res.Result; if (AggressiveCacheEnabled) _memoryCache.Set(cacheKey, poet); } return Ok(poet); } /// /// poet by url /// /// /// [HttpGet] [Route("poet")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorPoetCompleteViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task GetPoetByUrl(string url) { var cacheKey = $"poet/byurl/{url}"; if (!_memoryCache.TryGetValue(cacheKey, out GanjoorPoetCompleteViewModel poet)) { RServiceResult res = await _ganjoorService.GetPoetByUrl(url); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); if (res.Result == null) return NotFound(); poet = res.Result; if (AggressiveCacheEnabled) _memoryCache.Set(cacheKey, poet); } return Ok(poet); } /// /// update poet info (except for image) /// /// /// /// [HttpPut] [Route("poet/{id}")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task ModifyPoet(int id, [FromBody]GanjoorPoetViewModel poet) { if (!string.IsNullOrEmpty(poet.ImageUrl)) { return BadRequest("Please send an empty image url, if you are trying to change poet image this is not the right method to do it."); } Guid userId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); poet.Id = id; var res = await _ganjoorService.UpdatePoetAsync(poet, userId); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// regenerate half centuries /// /// [HttpPost] [Route("periods")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorPoetCompleteViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task RegenerateHalfCenturiesAsync() { var res = await _ganjoorService.RegenerateHalfCenturiesAsync(); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); _memoryCache.Remove($"ganjoor/centuries"); return Ok(res.Result); } /// /// create new poet /// /// /// [HttpPost] [Route("poet")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorPoetCompleteViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task CreatePoet([FromBody] GanjoorPoetViewModel poet) { if (!string.IsNullOrEmpty(poet.ImageUrl)) { return BadRequest("Please send an empty image url, if you are trying to change poet image this is not the right method to do it."); } Guid userId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); var res = await _ganjoorService.AddPoetAsync(poet, userId); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// starts deleting poet job /// /// /// [HttpDelete("poet/{id}")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public IActionResult StartDeletePoet(int id) { var res = _ganjoorService.StartDeletePoet(id); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(); } /// /// get poet image with png ext /// /// sample: hafez /// [HttpGet("poet/image/{url}.png")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(FileStreamResult))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetPoetImageInPng(string url) { return await GetPoetImage(url.Replace(".png", ".gif")); } /// /// get poet image /// /// sample: hafez /// [HttpGet("poet/image/{url}.gif")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(FileStreamResult))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetPoetImage(string url) { var cacheKey = $"poet/image/{url}.gif"; var cacheKeyForLastModified = $"{cacheKey}/lastModified"; if (!_memoryCache.TryGetValue(cacheKey, out string imagePath) || !_memoryCache.TryGetValue(cacheKeyForLastModified, out DateTime lastModified)) { RServiceResult poet = await _ganjoorService.GetPoetImageIdByUrl($"/{url}"); if (!string.IsNullOrEmpty(poet.ExceptionString)) return BadRequest(poet.ExceptionString); if (poet.Result == Guid.Empty) return NotFound(); RServiceResult img = await _imageFileService.GetImage(poet.Result); if (!string.IsNullOrEmpty(img.ExceptionString)) return BadRequest(img.ExceptionString); if (img.Result == null) return NotFound(); lastModified = img.Result.LastModified; RServiceResult imgPath = _imageFileService.GetImagePath(img.Result); if (!string.IsNullOrEmpty(imgPath.ExceptionString)) return BadRequest(imgPath.ExceptionString); imagePath = imgPath.Result; _memoryCache.Set(cacheKey, imagePath); _memoryCache.Set(cacheKeyForLastModified, lastModified); } Response.GetTypedHeaders().LastModified = lastModified; var requestHeaders = Request.GetTypedHeaders(); if (requestHeaders.IfModifiedSince.HasValue && requestHeaders.IfModifiedSince.Value >= lastModified) { return StatusCode(StatusCodes.Status304NotModified); } return new FileStreamResult(new FileStream(imagePath, FileMode.Open, FileAccess.Read), "image/gif"); } /// /// set poet image /// /// poet image /// [HttpPost("poet/image/{id}")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Unauthorized)] [ProducesResponseType((int)HttpStatusCode.Forbidden, Type = typeof(string))] public async Task UploadPoetImage(int id) { try { var poet = await _ganjoorService.GetPoetById(id, false); IFormFile file = Request.Form.Files[0]; RServiceResult image = await _imageFileService.Add(file, null, file.FileName, Path.Combine(Configuration.GetSection("PictureFileService")["StoragePath"], "PoetImages")); if (!string.IsNullOrEmpty(image.ExceptionString)) { return BadRequest(image.ExceptionString); } image = await _imageFileService.Store(image.Result); if (!string.IsNullOrEmpty(image.ExceptionString)) { return BadRequest(image.ExceptionString); } var res = await _ganjoorService.ChangePoetImageAsync(id, image.Result.Id); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); if(res.Result) { var cacheKey = $"poet/image/{poet.Result.Cat.UrlSlug}.png"; if (_memoryCache.TryGetValue(cacheKey, out string imagePath)) { _memoryCache.Remove(cacheKey); } } return Ok(res.Result); } catch (Exception exp) { return BadRequest(exp.ToString()); } } /// /// cat by id /// /// /// /// [HttpGet] [Route("cat/{id}")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorPoetCompleteViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task GetCatById(int id, bool poems = true) { var cacheKey = $"cat/byid/{id}/{poems}"; if (!_memoryCache.TryGetValue(cacheKey, out GanjoorPoetCompleteViewModel cat)) { RServiceResult res = await _ganjoorService.GetCatById(id, poems); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); if (res.Result == null) return NotFound(); cat = res.Result; if(AggressiveCacheEnabled) { _memoryCache.Set(cacheKey, cat); } } return Ok(cat); } /// /// cat by full url /// /// /// /// [HttpGet] [Route("cat")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorPoetCompleteViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task GetCatByUrl(string url, bool poems = true) { var cacheKey = $"cat/byurl/{url}/{poems}"; if (!_memoryCache.TryGetValue(cacheKey, out GanjoorPoetCompleteViewModel cat)) { RServiceResult res = await _ganjoorService.GetCatByUrl(url, poems); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); if (res.Result == null) return NotFound(); cat = res.Result; if (AggressiveCacheEnabled) _memoryCache.Set(cacheKey, cat); } return Ok(cat); } /// /// batch rename cat poems /// /// /// /// [HttpPut] [Route("cat/recaptionpoems/{id}")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorPageCompleteViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task BatchRenameCatPoemTitles(int id, [FromBody]GanjoorBatchNamingModel model) { Guid userId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _ganjoorService.BatchRenameCatPoemTitles(id, model, userId); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// starts assigning poem rhymes /// /// /// /// [HttpPut] [Route("cat/startassigningrhymes/{id}/{retag}")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public IActionResult FindCategoryPoemsRhymes(int id, bool retag) { RServiceResult res = _ganjoorService.FindCategoryPoemsRhymes(id, retag); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// start assigning poem rhythms /// /// /// /// /// [HttpPut] [Route("cat/startassigningrhythms/{id}/{retag}")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public IActionResult FindCategoryPoemsRhythms(int id, bool retag, string rhythm = "") { RServiceResult res = _ganjoorService.FindCategoryPoemsRhythms(id, retag, rhythm); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// Start Finding Missing Rhythms /// /// /// /// [HttpPost] [Route("startfindingmissingrhythms")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public IActionResult StartFindingMissingRhythms(bool onlyPoemsWithRhymes = true, int poemsNum = 1000) { RServiceResult res = _ganjoorService.StartFindingMissingRhythms(onlyPoemsWithRhymes, poemsNum); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// generate category toc /// /// /// /// [HttpGet] [Route("cat/toc/{id}/{options}")] [Produces("text/plain")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GenerateTableOfContents(int id, GanjoorTOC options = GanjoorTOC.Analyse) { var res = await _ganjoorService.GenerateTableOfContents(id, options); if(!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// start generating sub cats TOC /// /// /// [HttpPut("cat/subcats/startgentoc/{id}")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public IActionResult StartGeneratingSubCatsTOC(int id) { Guid userId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); var res = _ganjoorService.StartGeneratingSubCatsTOC(userId, id); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(); } /// /// page by url /// /// /// /// [HttpGet] [Route("page")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorPageCompleteViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task GetPageByUrl(string url, bool catPoems = false) { RServiceResult res = await _ganjoorService.GetPageByUrl(url, catPoems); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); if (res.Result == null) return NotFound(); return Ok(res.Result); } /// /// modify page /// /// /// /// [HttpPut] [Route("page/{id}")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorPageCompleteViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task ModifyPage(int id, [FromBody]GanjoorModifyPageViewModel page) { Guid userId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _ganjoorService.UpdatePageAsync(id, userId, page); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); if (res.Result == null) return NotFound(); return Ok(res.Result); } /// /// clean cache by id /// /// /// [HttpDelete] [Route("page/cache/{id}")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorPageCompleteViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task CacheCleanForPageById(int id) { await _ganjoorService.CacheCleanForPageById(id); return Ok(); } /// /// delete page /// /// /// [HttpDelete] [Route("page/{id}")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorPageCompleteViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task DeletePageAsync(int id) { var res = await _ganjoorService.DeletePageAsync(id); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(); } /// /// older versions of a page (modifications history except for current version) /// /// /// [HttpGet] [Route("page/oldversions/{id}")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorPageSnapshotSummaryViewModel[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetOlderVersionsOfPage(int id) { RServiceResult res = await _ganjoorService.GetOlderVersionsOfPage(id); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// get old version of page /// /// /// [HttpGet] [Route("oldversion/{id}")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorModifyPageViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetOldVersionOfPage(int id) { RServiceResult res = await _ganjoorService.GetOldVersionOfPage(id); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// page url by id /// /// /// [HttpGet] [Route("pageurl")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task GetPageUrlById(int id) { RServiceResult res = await _ganjoorService.GetPageUrlById(id); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); if (string.IsNullOrEmpty(res.Result)) return NotFound(); return Ok(res.Result); } /// /// get poem by id /// /// /// /// /// /// /// /// /// not implemented yet /// /// next/previous /// /// [HttpGet] [Route("poem/{id}")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorPoemCompleteViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task GetPoemById(int id, bool catInfo = true, bool catPoems = false, bool rhymes = true, bool recitations = true, bool images = true, bool songs = true, bool comments = true, bool verseDetails = true, bool navigation = true, bool relatedpoems = true) { RServiceResult res = await _ganjoorService.GetPoemById(id, catInfo, catPoems, rhymes, recitations, images, songs, comments, verseDetails, navigation, relatedpoems); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); if (res.Result == null) return NotFound(); return Ok(res.Result); } /// /// get poem by url /// /// /// /// /// not implemented yet /// /// /// not implemented yet /// not implemented yet /// /// next/previous /// [HttpGet] [Route("poem")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorPoemCompleteViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task GetPoemByUrl(string url, bool catInfo = true, bool catPoems = false, bool rhymes = true, bool recitations = true, bool images = true, bool songs = true, bool comments = true, bool verseDetails = true, bool navigation = true) { RServiceResult res = await _ganjoorService.GetPoemByUrl(url, catInfo, catPoems, rhymes, recitations, images, songs, comments, verseDetails, navigation); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); if (res.Result == null) return NotFound(); return Ok(res.Result); } /// /// get poem recitations (PlainText/HtmlText are intentionally empty) /// /// /// [HttpGet] [Route("poem/{id}/recitations")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(PublicRecitationViewModel[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetPoemRecitations(int id) { RServiceResult res = await _ganjoorService.GetPoemRecitations(id); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// get user upvoted recitations of a poem /// /// /// [HttpGet] [Route("poem/{id}/recitations/upvotes")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(int[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetUserPoemRecitationsUpVotes(int id) { var loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _ganjoorService.GetUserPoemRecitationsUpVotes(id, loggedOnUserId); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// get poem images (PlainText/HtmlText are intentionally empty) /// /// /// [HttpGet] [Route("poem/{id}/images")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(PoemRelatedImage[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetPoemImages(int id) { RServiceResult res = await _ganjoorService.GetPoemImages(id); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// get poem songs /// /// /// /// /// [HttpGet] [Route("poem/{id}/songs")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(PoemMusicTrackViewModel[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetPoemSongs(int id, bool approved, PoemMusicTrackType trackType = PoemMusicTrackType.All) { RServiceResult res = await _ganjoorService.GetPoemSongs(id, approved, trackType); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// Get Poem Comments /// /// /// /// [HttpGet] [Route("poem/{id}/comments")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorCommentSummaryViewModel[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetPoemComments(int id, int? coupletIndex) { RServiceResult res = await _ganjoorService.GetPoemComments(id, Guid.Empty, coupletIndex); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// Get Poem Related ones /// /// /// /// zero or less than it means all /// [HttpGet] [Route("poem/{id}/related")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorCachedRelatedPoem[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetRelatedPoems(int id, int skip = 0, int itemsCount = 0) { RServiceResult res = await _ganjoorService.GetRelatedPoems(id, skip, itemsCount); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// send poem corrections /// /// /// [HttpPost] [Route("poem/correction")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorPoemCorrectionViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task SuggestPoemCorrection([FromBody] GanjoorPoemCorrectionViewModel correction) { if (ReadOnlyMode) return BadRequest("سایت به دلایل فنی مثل انتقال سرور موقتاً در حالت فقط خواندنی قرار دارد. لطفاً ساعاتی دیگر مجدداً تلاش کنید."); correction.UserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _ganjoorService.SuggestPoemCorrection(correction); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); if (res.Result == null) return NotFound(); return Ok(res.Result); } /// /// delete unreviewed user corrections for a poem /// /// /// [HttpDelete] [Route("poem/correction/{id}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorPoemCorrectionViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task DeletePoemCorrections(int id) { if (ReadOnlyMode) return BadRequest("سایت به دلایل فنی مثل انتقال سرور موقتاً در حالت فقط خواندنی قرار دارد. لطفاً ساعاتی دیگر مجدداً تلاش کنید."); var userId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); var res = await _ganjoorService.DeletePoemCorrections(userId, id); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(); } /// /// returns last unreviewed correction from the user for a poem /// /// /// [HttpGet] [Route("poem/correction/last/{id}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorPoemCorrectionViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task GetLastUnreviewedUserCorrectionForPoem(int id) { Guid userId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _ganjoorService.GetLastUnreviewedUserCorrectionForPoem(userId, id); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result);//might be null } /// /// get list of user suggested corrections /// /// /// [HttpGet] [Route("corrections/mine")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(IEnumerable))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetUserCorrections([FromQuery] PagingParameterModel paging) { Guid userId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); var res = await _ganjoorService.GetUserCorrections(userId, paging); // Paging Header HttpContext.Response.Headers.Add("paging-headers", JsonConvert.SerializeObject(res.Result.PagingMeta)); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result.Items); } /// /// get list of all suggested corrections /// /// /// [HttpGet] [Route("corrections/all")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(IEnumerable))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetAllCorrections([FromQuery] PagingParameterModel paging) { var res = await _ganjoorService.GetUserCorrections(Guid.Empty, paging); // Paging Header HttpContext.Response.Headers.Add("paging-headers", JsonConvert.SerializeObject(res.Result.PagingMeta)); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result.Items); } /// /// effective corrections for poem /// /// /// /// [HttpGet] [Route("poem/{id}/corrections/effective")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(IEnumerable))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task GetPoemEffectiveCorrections(int id,[FromQuery] PagingParameterModel paging) { var res = await _ganjoorService.GetPoemEffectiveCorrections(id, paging); // Paging Header HttpContext.Response.Headers.Add("paging-headers", JsonConvert.SerializeObject(res.Result.PagingMeta)); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result.Items); } /// /// get correction by id /// /// /// [HttpGet] [Route("correction/{id}")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorPoemCorrectionViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task GetCorrectionById(int id) { Guid userId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _ganjoorService.GetCorrectionById(id); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result);//might be null } /// /// get next unreviewed correction /// /// /// [HttpGet] [Route("poem/correction/next")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorPoemCorrectionViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task GetNextUnreviewedCorrection(int skip = 0) { RServiceResult res = await _ganjoorService.GetNextUnreviewedCorrection(skip); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); var resCount = await _ganjoorService.GetUnreviewedCorrectionCount(); if (!string.IsNullOrEmpty(resCount.ExceptionString)) return BadRequest(resCount.ExceptionString); // Paging Header HttpContext.Response.Headers.Add("paging-headers", JsonConvert.SerializeObject( new PaginationMetadata() { totalCount = resCount.Result, pageSize = -1, currentPage = -1, hasNextPage = false, hasPreviousPage = false, totalPages = -1 }) ); return Ok(res.Result);//might be null } /// /// moderate poem correction /// /// /// [HttpPost] [Route("correction/moderate")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorPoemCorrectionViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task ModeratePoemCorrection([FromBody] GanjoorPoemCorrectionViewModel correction) { if (ReadOnlyMode) return BadRequest("سایت به دلایل فنی مثل انتقال سرور موقتاً در حالت فقط خواندنی قرار دارد. لطفاً ساعاتی دیگر مجدداً تلاش کنید."); Guid userId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _ganjoorService.ModeratePoemCorrection(userId, correction); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); if (res.Result == null) return NotFound(); return Ok(res.Result); } /// /// break a poem from a verse forward /// /// /// id of new poem [HttpPost] [Route("poem/break")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(int))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task BreakPoemAsync([FromBody] PoemVerseOrder verse) { if (ReadOnlyMode) return BadRequest("سایت به دلایل فنی مثل انتقال سرور موقتاً در حالت فقط خواندنی قرار دارد. لطفاً ساعاتی دیگر مجدداً تلاش کنید."); var userId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _ganjoorService.BreakPoemAsync(verse.PoemId, verse.VOrder, userId); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// suggest song for poem /// /// /// [HttpPost] [Route("song")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(PoemMusicTrackViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Forbidden)] public async Task SuggestSong([FromBody] PoemMusicTrackViewModel song) { if (ReadOnlyMode) return BadRequest("سایت به دلایل فنی مثل انتقال سرور موقتاً در حالت فقط خواندنی قرار دارد. لطفاً ساعاتی دیگر مجدداً تلاش کنید."); Guid userId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); Guid sessionId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "SessionId").Value); RServiceResult sessionCheckResult = await _appUserService.SessionExists(userId, sessionId); if (!string.IsNullOrEmpty(sessionCheckResult.ExceptionString)) { return StatusCode((int)HttpStatusCode.Forbidden); } var res = await _ganjoorService.SuggestSong(userId, song); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// get next unreviewed song /// /// /// /// [HttpGet] [Route("song")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(PoemMusicTrackViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Forbidden)] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task GetNextUnreviewedSong(int skip = 0, bool onlyMine = false) { Guid userId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); Guid sessionId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "SessionId").Value); RServiceResult sessionCheckResult = await _appUserService.SessionExists(userId, sessionId); if (!string.IsNullOrEmpty(sessionCheckResult.ExceptionString)) { return StatusCode((int)HttpStatusCode.Forbidden); } var res = await _ganjoorService.GetNextUnreviewedSong(skip, onlyMine ? userId : Guid.Empty); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); if (res.Result == null) return NotFound(); var resCount = await _ganjoorService.GetUnreviewedSongsCount(onlyMine ? userId : Guid.Empty); if (!string.IsNullOrEmpty(resCount.ExceptionString)) return BadRequest(resCount.ExceptionString); // Paging Header HttpContext.Response.Headers.Add("paging-headers", JsonConvert.SerializeObject( new PaginationMetadata() { totalCount = resCount.Result, pageSize = -1, currentPage = -1, hasNextPage = false, hasPreviousPage = false, totalPages = -1 }) ); return Ok(res.Result); } /// /// get song by id /// /// /// [HttpGet] [Route("song/{id}")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + RMuseumSecurableItem.ReviewSongs)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(PoemMusicTrackViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Forbidden)] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task GetPoemSongById(int id) { var res = await _ganjoorService.GetPoemSongById(id); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// history of suggested songs by a user /// [HttpGet] [Route("song/user/stats/{userId}")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + RMuseumSecurableItem.ReviewSongs)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(UserSongSuggestionsHistory))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Forbidden)] public async Task GetUserSongsSuggestionsStatistics(Guid userId) { var res = await _ganjoorService.GetUserSongsSuggestionsStatistics(userId); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// review song /// /// /// [HttpPut] [Route("song")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + RMuseumSecurableItem.ReviewSongs)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(PoemMusicTrackViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Forbidden)] public async Task ReviewSong([FromBody] PoemMusicTrackViewModel song) { if (ReadOnlyMode) return BadRequest("سایت به دلایل فنی مثل انتقال سرور موقتاً در حالت فقط خواندنی قرار دارد. لطفاً ساعاتی دیگر مجدداً تلاش کنید."); var res = await _ganjoorService.ReviewSong(song); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// modify a published song /// /// /// [HttpPut] [Route("song/update")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + RMuseumSecurableItem.ReviewSongs)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(PoemMusicTrackViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Forbidden)] public async Task ModifyPublishedSong([FromBody] PoemMusicTrackViewModel song) { if (ReadOnlyMode) return BadRequest("سایت به دلایل فنی مثل انتقال سرور موقتاً در حالت فقط خواندنی قرار دارد. لطفاً ساعاتی دیگر مجدداً تلاش کنید."); var res = await _ganjoorService.ModifyPublishedSong(song); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// delete a poem song by id /// /// /// [HttpDelete] [Route("song")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + RMuseumSecurableItem.ReviewSongs)] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Forbidden)] public async Task DeletePoemSongById(int id) { if (ReadOnlyMode) return BadRequest("سایت به دلایل فنی مثل انتقال سرور موقتاً در حالت فقط خواندنی قرار دارد. لطفاً ساعاتی دیگر مجدداً تلاش کنید."); var res = await _ganjoorService.DeletePoemSongById(id); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(); } /// /// directly insert a poem related song /// /// /// [HttpPost] [Route("song/add")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + RMuseumSecurableItem.AddSongs)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(PoemMusicTrackViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Forbidden)] public async Task DirectInsertSong([FromBody] PoemMusicTrackViewModel song) { if (ReadOnlyMode) return BadRequest("سایت به دلایل فنی مثل انتقال سرور موقتاً در حالت فقط خواندنی قرار دارد. لطفاً ساعاتی دیگر مجدداً تلاش کنید."); var res = await _ganjoorService.DirectInsertSong(song); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// get a random poem from hafez /// /// [HttpGet] [Route("hafez/faal")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorPoemCompleteViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task Faal() { RServiceResult res = await _ganjoorService.Faal(2, true); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// get a random poem from a poet (c.ganjoor.net replacement), 0 means random poet, /// حافظ (2)، خیام (3)، ابوسعید ابوالخیر (26)، صائب (22)، سعدی (7)، باباطاهر (28)، مولوی (5)، اوحدی (19)، خواجو (20)، شهریار (35)، عراقی (21)، فروغی بسطامی (32)، سلمان ساوجی (40)، محتشم کاشانی (29)، امیرخسرو دهلوی (34)، سیف فرغانی (31)، عبید زاکانی (33)، هاتف اصفهانی (25) یا رهی معیری (41) /// /// /// [HttpGet] [Route("poem/random")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorPoemCompleteViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetARandomPoem(int poetId) { RServiceResult res = await _ganjoorService.Faal(poetId, false); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// get recent comments /// /// /// /// [HttpGet] [Route("comments")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(IEnumerable))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetRecentComments([FromQuery] PagingParameterModel paging, Guid? filterUserId = null) { var comments = await _ganjoorService.GetRecentComments(paging, filterUserId == null ? Guid.Empty : (Guid)filterUserId, true); if (!string.IsNullOrEmpty(comments.ExceptionString)) { return BadRequest(comments.ExceptionString); } // Paging Header HttpContext.Response.Headers.Add("paging-headers", JsonConvert.SerializeObject(comments.Result.PagingMeta)); return Ok(comments.Result.Items); } /// /// get logged on users recent comments /// /// /// [HttpGet] [Route("comments/mine")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(IEnumerable))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetMyRecentComments([FromQuery] PagingParameterModel paging) { Guid userId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); Guid sessionId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "SessionId").Value); RServiceResult sessionCheckResult = await _appUserService.SessionExists(userId, sessionId); if (!string.IsNullOrEmpty(sessionCheckResult.ExceptionString)) { return StatusCode((int)HttpStatusCode.Forbidden); } var comments = await _ganjoorService.GetRecentComments(paging, userId, false); if (!string.IsNullOrEmpty(comments.ExceptionString)) { return BadRequest(comments.ExceptionString); } // Paging Header HttpContext.Response.Headers.Add("paging-headers", JsonConvert.SerializeObject(comments.Result.PagingMeta)); return Ok(comments.Result.Items); } /// /// get awaiting comments /// /// /// [HttpGet] [Route("comments/awaiting")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + RMuseumSecurableItem.ModerateOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(IEnumerable))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetAwaitingComments([FromQuery] PagingParameterModel paging) { var comments = await _ganjoorService.GetRecentComments(paging, Guid.Empty, false, true); if (!string.IsNullOrEmpty(comments.ExceptionString)) { return BadRequest(comments.ExceptionString); } // Paging Header HttpContext.Response.Headers.Add("paging-headers", JsonConvert.SerializeObject(comments.Result.PagingMeta)); return Ok(comments.Result.Items); } /// /// delete awaiting comment /// /// /// [HttpDelete] [Route("comment/awaiting/delete")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + RMuseumSecurableItem.ModerateOperationShortName)] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] [ProducesResponseType((int)HttpStatusCode.Forbidden)] public async Task DeleteAnybodyComment(int id) { if (ReadOnlyMode) return BadRequest("سایت به دلایل فنی مثل انتقال سرور موقتاً در حالت فقط خواندنی قرار دارد. لطفاً ساعاتی دیگر مجدداً تلاش کنید."); var res = await _ganjoorService.DeleteAnybodyComment(id); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); if (!res.Result) return NotFound(); return Ok(); } /// /// publish awaiting comment /// /// /// [HttpPut] [Route("comment/awaiting/publish")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + RMuseumSecurableItem.ModerateOperationShortName)] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] [ProducesResponseType((int)HttpStatusCode.Forbidden)] public async Task PublishAwaitingComment([FromBody]int id) { if (ReadOnlyMode) return BadRequest("سایت به دلایل فنی مثل انتقال سرور موقتاً در حالت فقط خواندنی قرار دارد. لطفاً ساعاتی دیگر مجدداً تلاش کنید."); var res = await _ganjoorService.PublishAwaitingComment(id); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); if (!res.Result) return NotFound(); return Ok(); } /// /// post new comment /// /// /// [HttpPost] [Route("comment")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorCommentSummaryViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Forbidden)] public async Task NewComment([FromBody] GanjoorCommentPostViewModel comment) { if (ReadOnlyMode) return BadRequest("سایت به دلایل فنی مثل انتقال سرور موقتاً در حالت فقط خواندنی قرار دارد. لطفاً ساعاتی دیگر مجدداً تلاش کنید."); string clientIPAddress = _httpContextAccessor.HttpContext.Connection.RemoteIpAddress.ToString(); Guid userId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); Guid sessionId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "SessionId").Value); RServiceResult sessionCheckResult = await _appUserService.SessionExists(userId, sessionId); if (!string.IsNullOrEmpty(sessionCheckResult.ExceptionString)) { return StatusCode((int)HttpStatusCode.Forbidden); } var res = await _ganjoorService.NewComment(userId, clientIPAddress, comment.PoemId, comment.HtmlComment, comment.InReplyToId, comment.CoupletIndex); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// edit user's own comment /// /// /// /// [HttpPut] [Route("comment/{id}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] [ProducesResponseType((int)HttpStatusCode.Forbidden)] public async Task EditMyComment(int id, [FromBody] string comment) { if (ReadOnlyMode) return BadRequest("سایت به دلایل فنی مثل انتقال سرور موقتاً در حالت فقط خواندنی قرار دارد. لطفاً ساعاتی دیگر مجدداً تلاش کنید."); Guid userId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); Guid sessionId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "SessionId").Value); RServiceResult sessionCheckResult = await _appUserService.SessionExists(userId, sessionId); if (!string.IsNullOrEmpty(sessionCheckResult.ExceptionString)) { return StatusCode((int)HttpStatusCode.Forbidden); } var res = await _ganjoorService.EditMyComment(userId, id, comment); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); if (!res.Result) return NotFound(); return Ok(); } /// /// link or unlink user's own comment to a coupletIndex /// /// /// /// couplet summary for linked comment [HttpPut] [Route("comment/{id}/editlink/{coupletIndex}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] [ProducesResponseType((int)HttpStatusCode.Forbidden)] public async Task LinkUnLinkMyComment(int id, int? coupletIndex) { if (ReadOnlyMode) return BadRequest("سایت به دلایل فنی مثل انتقال سرور موقتاً در حالت فقط خواندنی قرار دارد. لطفاً ساعاتی دیگر مجدداً تلاش کنید."); Guid userId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); Guid sessionId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "SessionId").Value); RServiceResult sessionCheckResult = await _appUserService.SessionExists(userId, sessionId); if (!string.IsNullOrEmpty(sessionCheckResult.ExceptionString)) { return StatusCode((int)HttpStatusCode.Forbidden); } var res = await _ganjoorService.LinkUnLinkMyComment(userId, id, coupletIndex); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); if (res.Result == null) return NotFound(); return Ok(res.Result); } /// /// delete user's own comment /// /// /// [HttpDelete] [Route("comment")] [Authorize] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] [ProducesResponseType((int)HttpStatusCode.Forbidden)] public async Task DeleteMyComment(int id) { if (ReadOnlyMode) return BadRequest("سایت به دلایل فنی مثل انتقال سرور موقتاً در حالت فقط خواندنی قرار دارد. لطفاً ساعاتی دیگر مجدداً تلاش کنید."); Guid userId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); Guid sessionId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "SessionId").Value); RServiceResult sessionCheckResult = await _appUserService.SessionExists(userId, sessionId); if (!string.IsNullOrEmpty(sessionCheckResult.ExceptionString)) { return StatusCode((int)HttpStatusCode.Forbidden); } var res = await _ganjoorService.DeleteMyComment(userId, id); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); if (!res.Result) return NotFound(); return Ok(); } /// /// report a comment /// /// /// id of reported record [HttpPost] [Route("comment/report")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(int))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Forbidden)] public async Task ReportComment([FromBody] GanjoorPostReportCommentViewModel report) { if (ReadOnlyMode) return BadRequest("سایت به دلایل فنی مثل انتقال سرور موقتاً در حالت فقط خواندنی قرار دارد. لطفاً ساعاتی دیگر مجدداً تلاش کنید."); Guid userId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); Guid sessionId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "SessionId").Value); RServiceResult sessionCheckResult = await _appUserService.SessionExists(userId, sessionId); if (!string.IsNullOrEmpty(sessionCheckResult.ExceptionString)) { return StatusCode((int)HttpStatusCode.Forbidden); } RServiceResult res = await _ganjoorService.ReportComment(userId, report); if (!string.IsNullOrEmpty(res.ExceptionString)) { return BadRequest(res.ExceptionString); } return Ok(res.Result); } /// /// delete a report (without deleting corresponding comment) /// /// /// [HttpDelete] [Route("comment/report/{id}")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + RMuseumSecurableItem.ModerateOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(int))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Forbidden)] public async Task DeleteReport(int id) { if (ReadOnlyMode) return BadRequest("سایت به دلایل فنی مثل انتقال سرور موقتاً در حالت فقط خواندنی قرار دارد. لطفاً ساعاتی دیگر مجدداً تلاش کنید."); RServiceResult res = await _ganjoorService.DeleteReport(id); if (!string.IsNullOrEmpty(res.ExceptionString)) { return BadRequest(res.ExceptionString); } if(!res.Result) { return NotFound(); } return Ok(); } /// /// get list of reported comments /// /// /// [HttpGet] [Route("comments/reported")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + RMuseumSecurableItem.ModerateOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(IEnumerable))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetReportedComments([FromQuery] PagingParameterModel paging) { var comments = await _ganjoorService.GetReportedComments(paging); if (!string.IsNullOrEmpty(comments.ExceptionString)) { return BadRequest(comments.ExceptionString); } // Paging Header HttpContext.Response.Headers.Add("paging-headers", JsonConvert.SerializeObject(comments.Result.PagingMeta)); return Ok(comments.Result.Items); } /// /// delete reported other users comment comment /// /// /// [HttpDelete] [Route("comment/reported/moderate/{reportid}")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + RMuseumSecurableItem.ModerateOperationShortName)] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] [ProducesResponseType((int)HttpStatusCode.Forbidden)] public async Task DeleteModerateComment(int reportid) { if (ReadOnlyMode) return BadRequest("سایت به دلایل فنی مثل انتقال سرور موقتاً در حالت فقط خواندنی قرار دارد. لطفاً ساعاتی دیگر مجدداً تلاش کنید."); var res = await _ganjoorService.DeleteModerateComment(reportid); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); if (!res.Result) return NotFound(); return Ok(); } /// /// imports data from ganjoor SQLite database (form file) /// /// /// [HttpPost] [Route("sqlite/import/{poetId}")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + RMuseumSecurableItem.ImportOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task ImportLocalSQLiteDb(int poetId) { IFormFile file = Request.Form.Files[0]; RServiceResult res = await _ganjoorService.ImportFromSqlite(poetId, file); if (res.Result) return Ok(); return BadRequest(res.ExceptionString); } /// /// Apply corrections from sqlite /// /// /// /// [HttpPost] [Route("sqlite/update/{poetId}")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + RMuseumSecurableItem.ImportOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task ApplyCorrectionsFromSqlite(int poetId, string note) { IFormFile file = Request.Form.Files[0]; RServiceResult res = await _ganjoorService.ApplyCorrectionsFromSqlite(poetId, file, note); if (res.Result) return Ok(); return BadRequest(res.ExceptionString); } /// /// export a poet to sqlite database /// /// /// [HttpGet] [Route("sqlite/export/{poetId}")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + RMuseumSecurableItem.ImportOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(FileStreamResult))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task ExportToSqlite(int poetId) { RServiceResult res = await _ganjoorService.ExportToSqlite(poetId); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return new FileStreamResult(new FileStream(res.Result, FileMode.Open, FileAccess.Read), "application/octet-stream"); } /// /// start exporting all poets /// /// [HttpPost("sqlite/batchexport")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + RMuseumSecurableItem.ReviewSongs)] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Unauthorized)] public IActionResult StartBatchGenerateGDBFiles() { try { var res = _ganjoorService.StartBatchGenerateGDBFiles(); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(); } catch (Exception exp) { return BadRequest(exp.ToString()); } } /// /// imports data from ganjoor MySql database /// /// [HttpPost] [Route("mysql/import")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + RMuseumSecurableItem.ImportOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public IActionResult ImportFromMySql() { RServiceResult res = _ganjoorService.ImportFromMySql(); if (res.Result) return Ok(); return BadRequest(res.ExceptionString); } /// /// Get user public profile /// /// /// [HttpGet("user/profile/{id}")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorUserPublicProfile))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task GetUserPublicProfile(Guid id) { RServiceResult userInfo = await _appUserService.GetUserInformation(id); if (userInfo.Result == null) { if (string.IsNullOrEmpty(userInfo.ExceptionString)) return NotFound(); return BadRequest(userInfo.ExceptionString); } return Ok ( new GanjoorUserPublicProfile() { Id = id, NickName = userInfo.Result.NickName, Bio = userInfo.Result.Bio, Website = userInfo.Result.Website, RImageId = userInfo.Result.RImageId } ); } /// /// Get Similar Poems accroding to prosody and rhyme informations /// /// /// cannot be empty /// can be empty /// send 0 for all /// return value is not complete or valid for some parts, you should use only the valid parts! [HttpGet] [Route("poems/similar")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(IEnumerable))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetSimilarPoems([FromQuery]PagingParameterModel paging, string metre, string rhyme, int poetId = 0) { var pagedResult = await _ganjoorService.GetSimilarPoems(paging, metre, rhyme, poetId == 0 ? (int?) null : poetId); if (!string.IsNullOrEmpty(pagedResult.ExceptionString)) return BadRequest(pagedResult.ExceptionString); // Paging Header HttpContext.Response.Headers.Add("paging-headers", JsonConvert.SerializeObject(pagedResult.Result.PagingMeta)); return Ok(pagedResult.Result.Items); } /// /// search /// /// /// /// /// /// [HttpGet] [Route("poems/search")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(IEnumerable))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task Search([FromQuery] PagingParameterModel paging, string term, int poetId = 0, int catId = 0) { var pagedResult = await _ganjoorService.Search(paging, term, poetId == 0 ? (int?)null : poetId, catId == 0 ? (int?)null: catId); if (!string.IsNullOrEmpty(pagedResult.ExceptionString)) return BadRequest(pagedResult.ExceptionString); // Paging Header HttpContext.Response.Headers.Add("paging-headers", JsonConvert.SerializeObject(pagedResult.Result.PagingMeta)); return Ok(pagedResult.Result.Items); } /// /// returns ganjoor metre list ordered by rhythm /// /// /// [HttpGet] [Route("rhythms")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(IEnumerable))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetGanjoorMetres(bool sortOnVerseCount = false) { var res = await _ganjoorService.GetGanjoorMetres(sortOnVerseCount); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// find poem rhyme /// /// /// [HttpGet] [Route("poem/analysisrhyme/{id}")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjooRhymeAnalysisResult))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task FindPoemRhyme(int id) { var res = await _ganjoorService.FindPoemRhyme(id); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// analysis poem to find its prosody information /// /// /// [HttpGet] [Route("poem/analysisrhythm/{id}")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task FindPoemRhythm(int id) { var res = await _ganjoorService.FindPoemRhythm(id); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// examine site pages for broken links /// /// [HttpPost] [Route("healthcheck")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + RMuseumSecurableItem.ImportOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public IActionResult HealthCheckContents() { RServiceResult res = _ganjoorService.HealthCheckContents(); if (res.Result) return Ok(); return BadRequest(res.ExceptionString); } /// /// examine comments for long links /// /// [HttpPost] [Route("fixlongurlsincomments")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + RMuseumSecurableItem.ImportOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public IActionResult FindAndFixLongUrlsInComments() { RServiceResult res = _ganjoorService.FindAndFixLongUrlsInComments(); if (res.Result) return Ok(); return BadRequest(res.ExceptionString); } /// /// start filling poems couplet indices /// /// [HttpPost] [Route("fillpoemscoupletindices")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + RMuseumSecurableItem.ImportOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public IActionResult StartFillingPoemsCoupletIndices() { RServiceResult res = _ganjoorService.StartFillingPoemsCoupletIndices(); if (res.Result) return Ok(); return BadRequest(res.ExceptionString); } /// /// separate verses in poem.PlainText with Environment.NewLine instead of SPACE /// /// if it is 0 it is ignored /// [HttpPost("regenplaintext/{catId}")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + RMuseumSecurableItem.ImportOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public IActionResult RegerneratePoemsPlainText(int catId) { RServiceResult res = _ganjoorService.RegerneratePoemsPlainText(catId); if (res.Result) return Ok(); return BadRequest(res.ExceptionString); } /// /// start building sitemap /// /// [HttpPost("sitemap")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public IActionResult StartBuildingSitemap() { var res = _ganjoorService.StartBuildingSitemap(); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(); } /// /// regenerate stats page /// /// [HttpPut("rebuild/stats")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Unauthorized)] public IActionResult StartUpdatingStatsPage() { try { Guid userId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); var res = _ganjoorService.StartUpdatingStatsPage(userId); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(); } catch (Exception exp) { return BadRequest(exp.ToString()); } } /// /// start updating mundex page /// /// [HttpPut("rebuild/mundex")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + RMuseumSecurableItem.ReviewSongs)] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Unauthorized)] public IActionResult StartUpdatingMundexPage() { try { Guid userId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); var res = _ganjoorService.StartUpdatingMundexPage(userId); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(); } catch (Exception exp) { return BadRequest(exp.ToString()); } } /// /// switch bookmark /// /// /// /// [HttpPost] [Route("bookmark/switch/{poemId}/{coupletIndex}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task SwitchCoupletBookmark(int poemId, int coupletIndex) { if (ReadOnlyMode) return BadRequest("سایت به دلایل فنی مثل انتقال سرور موقتاً در حالت فقط خواندنی قرار دارد. لطفاً ساعاتی دیگر مجدداً تلاش کنید."); Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _ganjoorService.SwitchCoupletBookmark(loggedOnUserId, poemId, coupletIndex); if (!string.IsNullOrEmpty(res.ExceptionString)) { if (res.ExceptionString == "verse not found") return NotFound(); return BadRequest(res.ExceptionString); } return Ok(res.Result != null); } /// /// Bookmark couplet if it is not /// /// /// /// [HttpPost] [Route("bookmark/{poemId}/{coupletIndex}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task BookmarkCoupletIfNotBookmarked(int poemId, int coupletIndex) { if (ReadOnlyMode) return BadRequest("سایت به دلایل فنی مثل انتقال سرور موقتاً در حالت فقط خواندنی قرار دارد. لطفاً ساعاتی دیگر مجدداً تلاش کنید."); Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _ganjoorService.BookmarkCoupletIfNotBookmarked(loggedOnUserId, poemId, coupletIndex); if (!string.IsNullOrEmpty(res.ExceptionString)) { if (res.ExceptionString == "verse not found") return NotFound(); return BadRequest(res.ExceptionString); } return Ok(res.Result != null); } /// /// delete bookmark /// /// /// [HttpDelete] [Route("bookmark/{bookmarkId}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task DeleteBookmark(Guid bookmarkId) { if (ReadOnlyMode) return BadRequest("سایت به دلایل فنی مثل انتقال سرور موقتاً در حالت فقط خواندنی قرار دارد. لطفاً ساعاتی دیگر مجدداً تلاش کنید."); Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _ganjoorService.DeleteGanjoorBookmark(bookmarkId, loggedOnUserId); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(); } /// /// modify bookmark private note /// /// /// /// [HttpPut] [Route("bookmark/{bookmarkId}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task ModifyBookmarkPrivateNoteAsync(Guid bookmarkId, [FromBody] string note) { if (ReadOnlyMode) return BadRequest("سایت به دلایل فنی مثل انتقال سرور موقتاً در حالت فقط خواندنی قرار دارد. لطفاً ساعاتی دیگر مجدداً تلاش کنید."); Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _ganjoorService.ModifyBookmarkPrivateNoteAsync(bookmarkId, loggedOnUserId, note); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(); } /// /// get poem user bookmarks (only Id, CoupletIndex and DateTime are valid in the output view model) /// /// /// [HttpGet] [Route("bookmark/{poemId}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorUserBookmarkViewModel[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetPoemUserBookmarks(int poemId) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _ganjoorService.GetPoemUserBookmarks(loggedOnUserId, poemId); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// is the poem couplet is bookmarked by user /// /// /// /// [HttpGet] [Route("bookmark/{poemId}/{coupletIndex}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task IsCoupletBookmarked(int poemId, int coupletIndex) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _ganjoorService.IsCoupletBookmarked(loggedOnUserId, poemId, coupletIndex); if (!string.IsNullOrEmpty(res.ExceptionString)) { if (res.ExceptionString == "verse not found") return NotFound(); return BadRequest(res.ExceptionString); } return Ok(res.Result); } /// /// user bookmarks /// /// [HttpGet] [Route("bookmark")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorUserBookmarkViewModel[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetUserBookmarks([FromQuery] PagingParameterModel paging) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult<(PaginationMetadata PagingMeta, GanjoorUserBookmarkViewModel[] Bookmarks)> res = await _ganjoorService.GetUserBookmarks(paging, loggedOnUserId); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); // Paging Header HttpContext.Response.Headers.Add("paging-headers", JsonConvert.SerializeObject(res.Result.PagingMeta)); return Ok(res.Result.Bookmarks); } /// /// start generating related poems info /// /// /// [HttpPost] [Route("generaterelatedpoemsinfo")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + RMuseumSecurableItem.ImportOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public IActionResult StartGeneratingRelatedPoemsInfo(bool regenerate = true) { RServiceResult res = _ganjoorService.StartGeneratingRelatedPoemsInfo(regenerate); if (res.Result) return Ok(); return BadRequest(res.ExceptionString); } /// /// get next ganjoor poem probable metre /// /// [HttpGet] [Route("probablemetre/next")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorPoemCompleteViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task GetNextGanjoorPoemProbableMetre() { RServiceResult res = await _ganjoorService.GetNextGanjoorPoemProbableMetre(); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); if (res.Result == null) return NotFound(); return Ok(res.Result); } /// /// get a list of ganjoor poems probable metres /// /// /// [HttpGet] [Route("probablemetre/list")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(IEnumerable))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task GetUnreviewedGanjoorPoemProbableMetres([FromQuery] PagingParameterModel paging) { var res = await _ganjoorService.GetUnreviewedGanjoorPoemProbableMetres(paging); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); // Paging Header HttpContext.Response.Headers.Add("paging-headers", JsonConvert.SerializeObject(res.Result.PagingMeta)); return Ok(res.Result.Items); } /// /// save ganjoor poem probable metre /// /// /// /// [HttpPut] [Route("probablemetre/save/{id}")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task SaveGanjoorPoemProbableMetre(int id, [FromBody] string metre) { RServiceResult res = await _ganjoorService.SaveGanjoorPoemProbableMetre(id, metre); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(); } /// /// dismiss ganjoor poem probable metre /// /// /// [HttpDelete] [Route("probablemetre/dismiss/{id}")] [Authorize(Policy = RMuseumSecurableItem.GanjoorEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task DismissGanjoorPoemProbableMetre(int id) { RServiceResult res = await _ganjoorService.SaveGanjoorPoemProbableMetre(id, "dismissed"); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(); } /// /// readonly mode /// public bool ReadOnlyMode { get { try { return bool.Parse(Configuration["ReadOnlyMode"]); } catch { return false; } } } /// /// Ganjoor Service /// protected readonly IGanjoorService _ganjoorService; /// /// IAppUserService instance /// protected IAppUserService _appUserService; /// /// for client IP resolution /// protected IHttpContextAccessor _httpContextAccessor; /// /// Image Service /// protected readonly IImageFileService _imageFileService; /// /// IMemoryCache /// protected readonly IMemoryCache _memoryCache; /// /// aggressive cache /// private bool AggressiveCacheEnabled { get { try { return bool.Parse(Configuration["AggressiveCacheEnabled"]); } catch { return false; } } } /// /// Configuration /// protected IConfiguration Configuration { get; } /// /// constructor /// /// /// /// /// /// /// public GanjoorController( IGanjoorService ganjoorService, IAppUserService appUserService, IHttpContextAccessor httpContextAccessor, IImageFileService imageFileService, IMemoryCache memoryCache, IConfiguration configuration ) { _ganjoorService = ganjoorService; _appUserService = appUserService; _httpContextAccessor = httpContextAccessor; _imageFileService = imageFileService; _memoryCache = memoryCache; Configuration = configuration; } } }