using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using RMuseum.Models.Auth.Memory; using RMuseum.Models.GanjoorAudio; using RMuseum.Models.GanjoorAudio.ViewModels; using RMuseum.Models.UploadSession; using RMuseum.Models.UploadSession.ViewModels; using RMuseum.Services; using RMuseum.Services.Implementation; using RSecurityBackend.Models.Generic; 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/audio")] public class RecitationController : Controller { /// /// returns paginated published recitations, ordered by publish date descending /// /// if PageSize is -1 or is more than 100 it resets to 100 /// /// [HttpGet("published")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(IEnumerable))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetPublished([FromQuery] PagingParameterModel paging, string searchTerm = "") { if (paging.PageSize == -1 || paging.PageSize > 100) paging.PageSize = 100; var res = await _audioService.GetPublishedRecitations(paging, searchTerm); 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); } /// /// get published recitation by id /// /// /// [HttpGet("published/{id}")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(PublicRecitationViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound, Type = typeof(string))] public async Task GetPublishedRecitationById(int id) { var res = await _audioService.GetPublishedRecitationById(id); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); if (res.Result == null) return NotFound(); return Ok(res.Result); } /// /// creates an RSS file from recent published recitations /// /// [HttpGet("published/rss")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(FileStreamResult))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetRssFeed() { int count = 200; var res = await _audioService.GetPublishedRecitations(new PagingParameterModel() { PageNumber = 1, PageSize = count}, ""); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); string rss = RecitationsRssBuilder.Build(res.Result.Items); var stream = new MemoryStream(); var writer = new StreamWriter(stream); writer.Write(rss); writer.Flush(); stream.Position = 0; return new FileStreamResult(stream, "application/rss+xml"); } /// /// Gets audio narrations, user must have recitation::moderate permission to be able to see all users narrations /// /// /// default: false, user must have recitation::moderate permission to be able to see all users narrations /// default: -1, unfiltered /// /// additional headers: paging-headers, audio-upload-enabled /// [HttpGet] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(IEnumerable))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Forbidden, Type = typeof(string))] public async Task Get([FromQuery] PagingParameterModel paging, bool allUsers = false, AudioReviewStatus status = AudioReviewStatus.All, string searchTerm = "") { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); Guid sessionId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "SessionId").Value); if (allUsers) { RServiceResult canView = await _userPermissionChecker.Check ( loggedOnUserId, sessionId, RMuseumSecurableItem.AudioRecitationEntityShortName, RMuseumSecurableItem.ModerateOperationShortName ); if (!string.IsNullOrEmpty(canView.ExceptionString)) return BadRequest(canView.ExceptionString); if (!canView.Result) return StatusCode((int)HttpStatusCode.Forbidden); } var res = await _audioService.SecureGetAll(paging, allUsers ? Guid.Empty : loggedOnUserId, status, searchTerm); if(!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); // Paging Header HttpContext.Response.Headers.Add("paging-headers", JsonConvert.SerializeObject(res.Result.PagingMeta)); //adding audio upload enabled header to reduce need for a separate query HttpContext.Response.Headers.Add("audio-upload-enabled", JsonConvert.SerializeObject(_audioService.UploadEnabled)); return Ok(res.Result.Items); } /// /// get the corresponding mp3 file for the narration /// /// /// it could be protected (Authorized), but I guess I would have problems with available client components support, /// so I preferred it to be anonymous, as it does not harm anybody I guess /// /// /// [HttpGet("file/{id}.mp3")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(FileStreamResult))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound, Type = typeof(string))] public async Task GetMp3File(int id) { RServiceResult narration = await _audioService.Get(id); if (!string.IsNullOrEmpty(narration.ExceptionString)) return BadRequest(narration.ExceptionString); if (narration.Result == null) return NotFound(); Response.GetTypedHeaders().LastModified = narration.Result.UploadDate;//TODO: Add a FileLastUpdated field to narrations to indicate the last time the mp3/xml files have been updated var requestHeaders = Request.GetTypedHeaders(); if (requestHeaders.IfModifiedSince.HasValue && requestHeaders.IfModifiedSince.Value >= narration.Result.UploadDate) { return StatusCode(StatusCodes.Status304NotModified); } return new FileStreamResult(new FileStream(narration.Result.LocalMp3FilePath, FileMode.Open, FileAccess.Read), "audio/mpeg"); } /// /// get the corresponding xml file contents (xml) for the narration /// /// /// it could be protected (Authorized), but I guess I would have problems with available client components support, /// so I preferred it to be anonymous, as it does not harm anybody I guess /// /// /// [HttpGet("xml/{id}")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound, Type = typeof(string))] public async Task GetXMLContent(int id) { RServiceResult narration = await _audioService.Get(id); if (!string.IsNullOrEmpty(narration.ExceptionString)) return BadRequest(narration.ExceptionString); if (narration.Result == null) return NotFound(); Response.GetTypedHeaders().LastModified = narration.Result.UploadDate;//TODO: Add a FileLastUpdated field to narrations to indicate the last time the mp3/xml files have been updated var requestHeaders = Request.GetTypedHeaders(); if (requestHeaders.IfModifiedSince.HasValue && requestHeaders.IfModifiedSince.Value >= narration.Result.UploadDate) { return StatusCode(StatusCodes.Status304NotModified); } return Ok(System.IO.File.ReadAllText(narration.Result.LocalXmlFilePath)); } /// /// get the corresponding xml file for the recitation /// /// /// it could be protected (Authorized), but I guess I would have problems with available client components support, /// so I preferred it to be anonymous, as it does not harm anybody I guess /// /// /// [HttpGet("file/{id}.xml")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(FileStreamResult))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetXMLFile(int id) { RServiceResult narration = await _audioService.Get(id); if (!string.IsNullOrEmpty(narration.ExceptionString)) return BadRequest(narration.ExceptionString); if (narration.Result == null) return NotFound(); Response.GetTypedHeaders().LastModified = narration.Result.UploadDate;//TODO: Add a FileLastUpdated field to narrations to indicate the last time the mp3/xml files have been updated var requestHeaders = Request.GetTypedHeaders(); if (requestHeaders.IfModifiedSince.HasValue && requestHeaders.IfModifiedSince.Value >= narration.Result.UploadDate) { return StatusCode(StatusCodes.Status304NotModified); } return new FileStreamResult(new FileStream(narration.Result.LocalXmlFilePath, FileMode.Open, FileAccess.Read), "text/xml"); } /// /// Gets Verse Sync Information /// /// narration id /// [HttpGet("verses/{id}")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RecitationVerseSync[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetPoemNarrationVerseSyncArray(int id) { RServiceResult verses = await _audioService.GetPoemNarrationVerseSyncArray(id); if (!string.IsNullOrEmpty(verses.ExceptionString)) return BadRequest(verses.ExceptionString); return Ok(verses.Result); } /// /// updates narration metadata /// /// /// /// /// reviewstatus cannot be set to Approved or Rejected using this method, use moderate method instead /// only these set of fields are updatable: AudioTitle, AudioArtist, AudioArtistUrl, AudioSrc, AudioSrcUrl, ReviewStatus (Draft to Pending and vice versa and Approved/Rejected to Pending) /// only narrator or a moderator can update the narration /// /// [HttpPut("{id}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RecitationViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Forbidden, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound, Type = typeof(string))] public async Task UpdatePoemNarration(int id, [FromBody] RecitationViewModel metadata) { if (!_audioService.UploadEnabled) return BadRequest("این قابلیت به دلیل تغییرات فنی سایت موقتاً غیرفعال است."); Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); var narration = await _audioService.Get(id); if (!string.IsNullOrEmpty(narration.ExceptionString)) { return BadRequest(narration.ExceptionString); } if (narration.Result == null) return NotFound(); if(narration.Result.Owner.Id != loggedOnUserId) { Guid sessionId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "SessionId").Value); RServiceResult serviceResult = await _userPermissionChecker.Check ( loggedOnUserId, sessionId, RMuseumSecurableItem.AudioRecitationEntityShortName, RMuseumSecurableItem.ModerateOperationShortName ); if (!string.IsNullOrEmpty(serviceResult.ExceptionString)) return BadRequest(serviceResult.ExceptionString); if (!serviceResult.Result) return StatusCode((int)HttpStatusCode.Forbidden); } if(narration.Result.ReviewStatus != metadata.ReviewStatus) { if (metadata.ReviewStatus == AudioReviewStatus.Approved || metadata.ReviewStatus == AudioReviewStatus.Rejected) { return StatusCode((int)HttpStatusCode.Forbidden); } } var res = await _audioService.UpdatePoemNarration(id, metadata); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// Moderate pending narration (for moderating other users' recitations you also need recitation:moderate permission) /// /// /// /// [HttpPut("moderate/{id}")] [Authorize(Policy = RMuseumSecurableItem.AudioRecitationEntityShortName + ":" + RMuseumSecurableItem.PublishOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RecitationViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Forbidden, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound, Type = typeof(string))] public async Task ModeratePoemNarration(int id, [FromBody] RecitationModerateViewModel model) { if (!_audioService.UploadEnabled) return BadRequest("این قابلیت به دلیل تغییرات فنی سایت موقتاً غیرفعال است."); Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); var narration = await _audioService.Get(id); if (!string.IsNullOrEmpty(narration.ExceptionString)) { return BadRequest(narration.ExceptionString); } if (narration.Result == null) return NotFound(); if (narration.Result.Owner.Id != loggedOnUserId) { Guid sessionId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "SessionId").Value); RServiceResult serviceResult = await _userPermissionChecker.Check ( loggedOnUserId, sessionId, RMuseumSecurableItem.AudioRecitationEntityShortName, RMuseumSecurableItem.ModerateOperationShortName ); if (!string.IsNullOrEmpty(serviceResult.ExceptionString)) return BadRequest(serviceResult.ExceptionString); if (!serviceResult.Result) return StatusCode((int)HttpStatusCode.Forbidden); } var res = await _audioService.ModeratePoemNarration(id, loggedOnUserId, model); if (!string.IsNullOrEmpty(res.ExceptionString)) { if(res.ExceptionString == "404") { return NotFound(); } return BadRequest(res.ExceptionString); } return Ok(res.Result); } /// /// Delete a recitation /// /// /// [HttpDelete("{id}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Forbidden)] public async Task DeleteRecitation(int id) { if (!_audioService.UploadEnabled) return BadRequest("این قابلیت به دلیل تغییرات فنی سایت موقتاً غیرفعال است."); Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _audioService.Delete(id, loggedOnUserId); if (!string.IsNullOrEmpty(res.ExceptionString)) { return BadRequest(res.ExceptionString); } return Ok(res.Result); } /// /// Get User Uploads /// /// /// default: false, user must have recitation::moderate permission to be able to see all users uploads /// /// additional headers: paging-headers, audio-upload-enabled [HttpGet("uploads")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(IEnumerable))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Forbidden, Type = typeof(string))] public async Task GetUploads([FromQuery] PagingParameterModel paging, bool allUsers = false) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); Guid sessionId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "SessionId").Value); if (allUsers) { RServiceResult canView = await _userPermissionChecker.Check ( loggedOnUserId, sessionId, RMuseumSecurableItem.AudioRecitationEntityShortName, RMuseumSecurableItem.ModerateOperationShortName ); if (!string.IsNullOrEmpty(canView.ExceptionString)) return BadRequest(canView.ExceptionString); if (!canView.Result) return StatusCode((int)HttpStatusCode.Forbidden); } var res = await _audioService.GetUploads(paging, allUsers ? Guid.Empty : loggedOnUserId); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); // Paging Header HttpContext.Response.Headers.Add("paging-headers", JsonConvert.SerializeObject(res.Result.PagingMeta)); //adding audio upload enabled header to reduce need for a separate query HttpContext.Response.Headers.Add("audio-upload-enabled", JsonConvert.SerializeObject(_audioService.UploadEnabled)); return Ok(res.Result.Items); } /// /// upload, update, moderate and delete operations on recitations might temporarily become disabled, /// this method gets the current status /// remarks: the value of this flag is provided as a custom header called audio-upload-enabled in some common GET methods /// in order to reduce the need for a separate query /// /// [HttpGet("uploadenabled")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))] public IActionResult IsUploadEnabled() { return Ok(_audioService.UploadEnabled); } /// /// Reciation Upload /// /// /// if you send true to replace parameter, if there is an existing recitation for the poem from the user with the same Audio Artist name /// corresponding mp3+xml files are replaced an no other changes is applied (no new post, preserving recitation position) /// /// [HttpPost] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(UploadSession))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Unauthorized)] [ProducesResponseType((int)HttpStatusCode.Forbidden, Type = typeof(string))] public async Task UploadReciation(bool replace = false) { try { if (!_audioService.UploadEnabled) return BadRequest("ارسال خوانش جدید به دلیل تغییرات فنی سایت موقتاً غیرفعال است."); Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult resSession = await _audioService.InitiateNewUploadSession(loggedOnUserId, replace); if (!string.IsNullOrEmpty(resSession.ExceptionString)) return BadRequest(resSession.ExceptionString); List files = new List(); foreach(IFormFile file in Request.Form.Files) { RServiceResult rsFileResult = await _audioService.SaveUploadedFile(file); if(!string.IsNullOrEmpty(rsFileResult.ExceptionString)) { return BadRequest(rsFileResult.ExceptionString); } files.Add(rsFileResult.Result); } resSession = await _audioService.FinalizeNewUploadSession(resSession.Result, files.ToArray()); return Ok(resSession.Result); } catch (Exception exp) { return BadRequest(exp.ToString()); } } /// /// imports data from ganjoor MySql database /// /// [HttpPost] [Route("mysqlonetimeimport")] [Authorize(Policy = RMuseumSecurableItem.AudioRecitationEntityShortName + ":" + RMuseumSecurableItem.ImportOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task MysqlonetimeImport() { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _audioService.OneTimeImport(loggedOnUserId); if (res.Result) return Ok(); return BadRequest(res.ExceptionString); } /// /// Get User Profiles /// /// /// [HttpGet("profile")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(IEnumerable))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Forbidden, Type = typeof(string))] public async Task GetUserNarrationProfiles(string artistName) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); var res = await _audioService.GetUserNarrationProfiles(loggedOnUserId, artistName); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// Get User Default Profile /// /// [HttpGet("profile/def")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(UserRecitationProfileViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Forbidden, Type = typeof(string))] public async Task GetUserDefProfile() { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); var res = await _audioService.GetUserDefProfile(loggedOnUserId); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// Add a narration profile /// /// /// [HttpPost("profile")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(UserRecitationProfileViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Forbidden, Type = typeof(string))] public async Task AddUserNarrationProfiles([FromBody]UserRecitationProfileViewModel profile) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); profile.UserId = loggedOnUserId; var res = await _audioService.AddUserNarrationProfiles(profile); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// Update a narration profile /// /// /// [HttpPut("profile")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(UserRecitationProfileViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Forbidden, Type = typeof(string))] public async Task UpdateUserNarrationProfiles([FromBody] UserRecitationProfileViewModel profile) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); profile.UserId = loggedOnUserId; var res = await _audioService.UpdateUserNarrationProfiles(profile); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// Delete a narration profile /// /// /// [HttpDelete("profile/{id}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Forbidden)] public async Task DeleteUserNarrationProfiles(Guid id) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _audioService.DeleteUserNarrationProfiles(id, loggedOnUserId); if (!string.IsNullOrEmpty(res.ExceptionString)) { return BadRequest(res.ExceptionString); } return Ok(res.Result); } /// /// publishing tracker data /// /// /// /// [HttpGet("publishqueue")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(IEnumerable))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Forbidden, Type = typeof(string))] public async Task GetPublishingQueueStatus([FromQuery] PagingParameterModel paging, bool unfinished) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); Guid sessionId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "SessionId").Value); RServiceResult canViewAll = await _userPermissionChecker.Check ( loggedOnUserId, sessionId, RMuseumSecurableItem.AudioRecitationEntityShortName, RMuseumSecurableItem.ModerateOperationShortName ); if (!string.IsNullOrEmpty(canViewAll.ExceptionString)) return BadRequest(canViewAll.ExceptionString); var res = await _audioService.GetPublishingQueueStatus(paging, unfinished, canViewAll.Result ? Guid.Empty : 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.Items); } /// /// Transfer Recitations Ownership (for recitations owned by current user) /// /// /// /// number of transfered items [HttpPut("chown")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(int))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound, Type = typeof(string))] public async Task TransferRecitationsOwnership(string targetEmailAddress, string artistName) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); var userSearchResult = await _appUserService.FindUserByEmail(targetEmailAddress); if (!string.IsNullOrEmpty(userSearchResult.ExceptionString)) return BadRequest(userSearchResult); if (userSearchResult.Result == null) return NotFound(); var resExec = await _audioService.TransferRecitationsOwnership(loggedOnUserId, (Guid)userSearchResult.Result.Id, artistName); if (!string.IsNullOrEmpty(resExec.ExceptionString)) return BadRequest(resExec.ExceptionString); return Ok(resExec.Result); } /// /// Makes recitations of فریدون فرح‌اندوز first recitations /// /// [HttpPut("ff")] [Authorize(Policy = RMuseumSecurableItem.AudioRecitationEntityShortName + ":" + RMuseumSecurableItem.ReOrderOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(int))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task MakeFFRecitationsFirst() { if (!_audioService.UploadEnabled) return BadRequest("این قابلیت به دلیل تغییرات فنی سایت موقتاً غیرفعال است."); var resExec = await _audioService.MakeArtistRecitationsFirst("فریدون فرح‌اندوز"); if (!string.IsNullOrEmpty(resExec.ExceptionString)) return BadRequest(resExec.ExceptionString); return Ok(resExec.Result); } /// /// Synchronization Queue /// /// [HttpGet("syncqueue")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(IEnumerable))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Forbidden, Type = typeof(string))] public async Task GetSynchronizationQueue() { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); Guid sessionId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "SessionId").Value); RServiceResult canViewAll = await _userPermissionChecker.Check ( loggedOnUserId, sessionId, RMuseumSecurableItem.AudioRecitationEntityShortName, RMuseumSecurableItem.ModerateOperationShortName ); if (!string.IsNullOrEmpty(canViewAll.ExceptionString)) return BadRequest(canViewAll.ExceptionString); var res = await _audioService.GetSynchronizationQueue(canViewAll.Result ? Guid.Empty : loggedOnUserId); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// constructor /// /// /// /// public RecitationController(IRecitationService audioService, IUserPermissionChecker userPermissionChecker, IAppUserService appUserService) { _audioService = audioService; _userPermissionChecker = userPermissionChecker; _appUserService = appUserService; } /// /// Artifact Service /// protected readonly IRecitationService _audioService; /// /// IUserPermissionChecker instance /// protected IUserPermissionChecker _userPermissionChecker; /// /// IAppUserService instance /// protected IAppUserService _appUserService; } }