diff --git a/RMuseum/Controllers/ArtifactController.cs b/RMuseum/Controllers/ArtifactController.cs
index 28463542..514250f4 100644
--- a/RMuseum/Controllers/ArtifactController.cs
+++ b/RMuseum/Controllers/ArtifactController.cs
@@ -1423,7 +1423,7 @@ namespace RMuseum.Controllers
loggedOnUserId,
new Guid(User.Claims.FirstOrDefault(c => c.Type == "SessionId").Value),
RMuseumSecurableItem.NoteEntityShortName,
- RMuseumSecurableItem.ModerateCommentsOperationShortName
+ RMuseumSecurableItem.ModerateOperationShortName
);
if (!string.IsNullOrEmpty(canModerate.ExceptionString))
return BadRequest(canModerate.ExceptionString);
@@ -1460,7 +1460,7 @@ namespace RMuseum.Controllers
loggedOnUserId,
new Guid(User.Claims.FirstOrDefault(c => c.Type == "SessionId").Value),
RMuseumSecurableItem.NoteEntityShortName,
- RMuseumSecurableItem.ModerateCommentsOperationShortName
+ RMuseumSecurableItem.ModerateOperationShortName
);
if (!string.IsNullOrEmpty(canModerate.ExceptionString))
return BadRequest(canModerate.ExceptionString);
diff --git a/RMuseum/Controllers/AudioNarrationController.cs b/RMuseum/Controllers/AudioNarrationController.cs
index ca3448c8..b0012285 100644
--- a/RMuseum/Controllers/AudioNarrationController.cs
+++ b/RMuseum/Controllers/AudioNarrationController.cs
@@ -1,10 +1,14 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
+using Newtonsoft.Json;
using RMuseum.Models.Auth.Memory;
+using RMuseum.Models.GanjoorAudio;
+using RMuseum.Models.GanjoorAudio.ViewModels;
using RMuseum.Services;
using RSecurityBackend.Models.Generic;
using RSecurityBackend.Services;
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
@@ -16,6 +20,53 @@ namespace RMuseum.Controllers
public class AudioNarrationController : Controller
{
+ ///
+ /// Gets audio narrations, user must have narration::moderate permission to be able to see all users narrations
+ ///
+ ///
+ /// default: false, user must have narration::moderate permission to be able to see all users narrations
+ /// default: -1, unfiltered
+ ///
+ [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 )
+ {
+ 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.AudioNarrationEntityShortName,
+ RMuseumSecurableItem.ModerateOperationShortName
+ );
+ if (!string.IsNullOrEmpty(canView.ExceptionString))
+ return BadRequest(canView.ExceptionString);
+
+ if (!canView.Result)
+ return StatusCode((int)HttpStatusCode.Forbidden);
+ }
+
+ var res = await _audioService.GetAll(paging, allUsers ? Guid.Empty : loggedOnUserId, status);
+ 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);
+ }
+
+
///
/// imports data from ganjoor MySql database
///
diff --git a/RMuseum/Models/Auth/Memory/RMuseumSecurableItem.cs b/RMuseum/Models/Auth/Memory/RMuseumSecurableItem.cs
index 62a7b425..81127224 100644
--- a/RMuseum/Models/Auth/Memory/RMuseumSecurableItem.cs
+++ b/RMuseum/Models/Auth/Memory/RMuseumSecurableItem.cs
@@ -51,7 +51,7 @@ namespace RMuseum.Models.Auth.Memory
///
/// moderate
///
- public const string ModerateCommentsOperationShortName = "moderate";
+ public const string ModerateOperationShortName = "moderate";
///
/// review suggested ganjoor links
@@ -108,7 +108,7 @@ namespace RMuseum.Models.Auth.Memory
Description = "یادداشتها",
Operations = new SecurableItemOperation[]
{
- new SecurableItemOperation(ModerateCommentsOperationShortName, "بررسی", false)
+ new SecurableItemOperation(ModerateOperationShortName, "بررسی", false)
}
},
new SecurableItem()
@@ -118,7 +118,7 @@ namespace RMuseum.Models.Auth.Memory
Operations = new SecurableItemOperation[]
{
new SecurableItemOperation(ImportOperationShortName, "ورود اطلاعات", false),
- new SecurableItemOperation(ModerateCommentsOperationShortName, "بررسی", false)
+ new SecurableItemOperation(ModerateOperationShortName, "بررسی", false)
}
},
diff --git a/RMuseum/Models/GanjoorAudio/AudioReviewStatus.cs b/RMuseum/Models/GanjoorAudio/AudioReviewStatus.cs
index 16d730da..4df7a2cc 100644
--- a/RMuseum/Models/GanjoorAudio/AudioReviewStatus.cs
+++ b/RMuseum/Models/GanjoorAudio/AudioReviewStatus.cs
@@ -5,19 +5,27 @@
///
public enum AudioReviewStatus
{
+ ///
+ /// All / Unfiltered (for queris)
+ ///
+ All = -1,
+ ///
+ /// Draft
+ ///
+ Draft = 0,
///
/// pending for review
///
- Pending = 0,
+ Pending = 1,
///
/// approved
///
- Approved = 1,
+ Approved = 2,
///
/// Rejected
///
- Rejected = 2
+ Rejected = 3
}
}
diff --git a/RMuseum/Models/GanjoorAudio/PoemNarration.cs b/RMuseum/Models/GanjoorAudio/PoemNarration.cs
index 8da3ed50..3ecc3522 100644
--- a/RMuseum/Models/GanjoorAudio/PoemNarration.cs
+++ b/RMuseum/Models/GanjoorAudio/PoemNarration.cs
@@ -89,6 +89,11 @@ namespace RMuseum.Models.GanjoorAudio
///
public string RemoteXMLFilePath { get { return $"/i/{SoundFilesFolder}/x/{FileNameWithoutExtension}.xml"; } }
+ ///
+ /// XML url
+ ///
+ public string XMLUrl { get { return $"https://i.ganjoor.net/{SoundFilesFolder}/x/{FileNameWithoutExtension}.xml"; } }
+
///
/// Audio Title
///
diff --git a/RMuseum/Models/GanjoorAudio/ViewModels/PoemNarrationViewModel.cs b/RMuseum/Models/GanjoorAudio/ViewModels/PoemNarrationViewModel.cs
new file mode 100644
index 00000000..40d6288e
--- /dev/null
+++ b/RMuseum/Models/GanjoorAudio/ViewModels/PoemNarrationViewModel.cs
@@ -0,0 +1,216 @@
+using RSecurityBackend.Models.Auth.ViewModels;
+using System;
+using System.Collections.Generic;
+
+namespace RMuseum.Models.GanjoorAudio.ViewModels
+{
+ ///
+ /// Poem Narration view model
+ ///
+ public class PoemNarrationViewModel
+ {
+ ///
+ /// constructor
+ ///
+ ///
+ public PoemNarrationViewModel(PoemNarration src)
+ {
+ Id = src.Id;
+ Owner = new PublicRAppUser(src.Owner);
+ GanjoorAudioId = src.GanjoorAudioId;
+ GanjoorPostId = src.GanjoorPostId;
+ AudioOrder = src.AudioOrder;
+ FileNameWithoutExtension = src.FileNameWithoutExtension;
+ SoundFilesFolder = src.SoundFilesFolder;
+ AudioTitle = src.AudioTitle;
+ AudioArtist = src.AudioArtist;
+ AudioArtistUrl = src.AudioArtistUrl;
+ AudioSrc = src.AudioSrc;
+ AudioSrcUrl = src.AudioSrcUrl;
+ LegacyAudioGuid = src.LegacyAudioGuid;
+ Mp3FileCheckSum = src.Mp3FileCheckSum;
+ Mp3SizeInBytes = src.Mp3SizeInBytes;
+ OggSizeInBytes = src.OggSizeInBytes;
+ LocalMp3FilePath = src.LocalMp3FilePath;
+ LocalXmlFilePath = src.LocalXmlFilePath;
+ ReviewStatus = src.ReviewStatus;
+ UploadDate = src.UploadDate;
+ ReviewDate = src.ReviewDate;
+ List lst = new List();
+ foreach(AudioSyncStatus status in
+ new AudioSyncStatus[]
+ {
+ AudioSyncStatus.SynchronizedOrRejected,
+ AudioSyncStatus.NewItem,
+ AudioSyncStatus.MetadataChanged,
+ AudioSyncStatus.SoundFilesChanged,
+ AudioSyncStatus.XmlFileChanged,
+ AudioSyncStatus.Deleted
+ })
+ {
+ if(
+ src.AudioSyncStatus == (( (int)status )| src.AudioSyncStatus)
+ )
+ {
+ lst.Add(status);
+ }
+ }
+ AudioSyncStatusArray = lst.ToArray();
+ }
+
+ ///
+ /// Id
+ ///
+ public Guid Id { get; set; }
+
+ ///
+ /// Owner User
+ ///
+ public PublicRAppUser Owner { get; set; }
+
+ ///
+ /// Final data is actually exported to a MySQL database which this auto increment field is its key
+ ///
+ public int GanjoorAudioId { get; set; }
+
+ ///
+ /// Ganjoor Post Id
+ ///
+ public int GanjoorPostId { get; set; }
+
+ ///
+ /// This determines where an audio is displayed between a list of sounds related to a specfic poem
+ ///
+ public int AudioOrder { get; set; }
+
+ ///
+ /// Using this field content you would determine xml, mp3 and ogg file names
+ ///
+ public string FileNameWithoutExtension { get; set; }
+
+ ///
+ /// combining this with + .ext would preduce relative path of sound files on our file server the full path would become [HOMEPath] + '/i/' + this value
+ ///
+ ///
+ /// "a2"
+ ///
+ ///
+ /// We had previously used different pathes because when a directory became overcrowded our connection time would increase unbearably due to IRAN internet problems, so it is sensible to store it per record and not as a global option value
+ ///
+ public string SoundFilesFolder { get; set; }
+
+ ///
+ /// MP3 File Path
+ ///
+ public string RemoteMp3FilePath { get { return $"/i/{SoundFilesFolder}/{FileNameWithoutExtension}.mp3"; } }
+
+ ///
+ /// MP3 url
+ ///
+ public string Mp3Url { get { return $"https://i.ganjoor.net/{SoundFilesFolder}/{FileNameWithoutExtension}.mp3"; } }
+
+
+ ///
+ /// OGG File Path
+ ///
+ public string RemoteOggFilePath { get { return $"/i/{SoundFilesFolder}/{FileNameWithoutExtension}.ogg"; } }
+
+ ///
+ /// OGG url
+ ///
+ public string OggUrl { get { return $"https://i.ganjoor.net/{SoundFilesFolder}/{FileNameWithoutExtension}.ogg"; } }
+
+ ///
+ /// This is also a legacy field
+ ///
+ ///
+ /// "/i/a2/x"
+ ///
+ ///
+ /// XML Schema is defined based on Desktop Ganjoor (https://github.com/ganjoor/ganjoor) code, for
+ /// more information take a look at this code:
+ /// https://github.com/ganjoor/ganjoor/blob/master/ganjoor/Audio%20Support/PoemAudioListProcessor.cs
+ ///
+ public string RemoteXMLFilePath { get { return $"/i/{SoundFilesFolder}/x/{FileNameWithoutExtension}.xml"; } }
+
+ ///
+ /// XML url
+ ///
+ public string XMLUrl { get { return $"https://i.ganjoor.net/{SoundFilesFolder}/x/{FileNameWithoutExtension}.xml"; } }
+
+ ///
+ /// Audio Title
+ ///
+ public string AudioTitle { get; set; }
+
+ ///
+ /// Audio Artist
+ ///
+ public string AudioArtist { get; set; }
+
+ ///
+ /// Audio Artist Url
+ ///
+ public string AudioArtistUrl { get; set; }
+
+ ///
+ /// Audio Source
+ ///
+ public string AudioSrc { get; set; }
+
+ ///
+ /// Audio Src Url
+ ///
+ public string AudioSrcUrl { get; set; }
+
+ ///
+ /// Legacy Audio Guid
+ ///
+ public Guid LegacyAudioGuid { get; set; }
+
+ ///
+ /// Audio File CheckSum
+ ///
+ public string Mp3FileCheckSum { get; set; }
+
+ ///
+ /// mp3 size in bytes
+ ///
+ public int Mp3SizeInBytes { get; set; }
+
+ ///
+ /// ogg size in bytes
+ ///
+ public int OggSizeInBytes { get; set; }
+
+ ///
+ /// Upload Date
+ ///
+ public DateTime UploadDate { get; set; }
+
+ ///
+ /// Review Date (Approve or Reject)
+ ///
+ public DateTime ReviewDate { get; set; }
+
+ ///
+ /// MP3 File local path on Windows Server (if item is not rejected probably it is not valid and it is deleted)
+ ///
+ public string LocalMp3FilePath { get; set; }
+
+ ///
+ /// XML File local path on Windows Server (if item is not rejected probably it is not valid and it is deleted)
+ ///
+ public string LocalXmlFilePath { get; set; }
+
+ ///
+ /// Value is one or a combination of
+ ///
+ public AudioSyncStatus[] AudioSyncStatusArray { get; set; }
+
+ ///
+ /// Review Status
+ ///
+ public AudioReviewStatus ReviewStatus { get; set; }
+ }
+}
diff --git a/RMuseum/RMuseum.xml b/RMuseum/RMuseum.xml
index 2a51a003..d9821015 100644
--- a/RMuseum/RMuseum.xml
+++ b/RMuseum/RMuseum.xml
@@ -620,6 +620,15 @@
Captcha service
+
+
+ Gets audio narrations, user must have narration::moderate permission to be able to see all users narrations
+
+
+ default: false, user must have narration::moderate permission to be able to see all users narrations
+ default: -1, unfiltered
+
+
imports data from ganjoor MySql database
@@ -1404,7 +1413,7 @@
import
-
+
moderate
@@ -1534,6 +1543,16 @@
Audio Review Status
+
+
+ All / Unfiltered (for queris)
+
+
+
+
+ Draft
+
+
pending for review
@@ -1668,6 +1687,11 @@
https://github.com/ganjoor/ganjoor/blob/master/ganjoor/Audio%20Support/PoemAudioListProcessor.cs
+
+
+ XML url
+
+
Audio Title
@@ -1743,6 +1767,171 @@
Review Status
+
+
+ Poem Narration view model
+
+
+
+
+ constructor
+
+
+
+
+
+ Id
+
+
+
+
+ Owner User
+
+
+
+
+ Final data is actually exported to a MySQL database which this auto increment field is its key
+
+
+
+
+ Ganjoor Post Id
+
+
+
+
+ This determines where an audio is displayed between a list of sounds related to a specfic poem
+
+
+
+
+ Using this field content you would determine xml, mp3 and ogg file names
+
+
+
+
+ combining this with + .ext would preduce relative path of sound files on our file server the full path would become [HOMEPath] + '/i/' + this value
+
+
+ "a2"
+
+
+ We had previously used different pathes because when a directory became overcrowded our connection time would increase unbearably due to IRAN internet problems, so it is sensible to store it per record and not as a global option value
+
+
+
+
+ MP3 File Path
+
+
+
+
+ MP3 url
+
+
+
+
+ OGG File Path
+
+
+
+
+ OGG url
+
+
+
+
+ This is also a legacy field
+
+
+ "/i/a2/x"
+
+
+ XML Schema is defined based on Desktop Ganjoor (https://github.com/ganjoor/ganjoor) code, for
+ more information take a look at this code:
+ https://github.com/ganjoor/ganjoor/blob/master/ganjoor/Audio%20Support/PoemAudioListProcessor.cs
+
+
+
+
+ XML url
+
+
+
+
+ Audio Title
+
+
+
+
+ Audio Artist
+
+
+
+
+ Audio Artist Url
+
+
+
+
+ Audio Source
+
+
+
+
+ Audio Src Url
+
+
+
+
+ Legacy Audio Guid
+
+
+
+
+ Audio File CheckSum
+
+
+
+
+ mp3 size in bytes
+
+
+
+
+ ogg size in bytes
+
+
+
+
+ Upload Date
+
+
+
+
+ Review Date (Approve or Reject)
+
+
+
+
+ MP3 File local path on Windows Server (if item is not rejected probably it is not valid and it is deleted)
+
+
+
+
+ XML File local path on Windows Server (if item is not rejected probably it is not valid and it is deleted)
+
+
+
+
+ Value is one or a combination of
+
+
+
+
+ Review Status
+
+
ganjoor link for artifacts and items
@@ -3029,6 +3218,15 @@
Audio Narration Service
+
+
+ returns list of narrations
+
+
+ send Guid.Empty if you want all narrations
+
+
+
imports data from ganjoor MySql database
@@ -3749,6 +3947,15 @@
Audio Narration Service Implementation
+
+
+ returns list of narrations
+
+
+ send Guid.Empty if you want all narrations
+
+
+
imports data from ganjoor MySql database
diff --git a/RMuseum/Services/IAudioNarrationService.cs b/RMuseum/Services/IAudioNarrationService.cs
index 86286ee1..98687b32 100644
--- a/RMuseum/Services/IAudioNarrationService.cs
+++ b/RMuseum/Services/IAudioNarrationService.cs
@@ -1,4 +1,6 @@
-using RSecurityBackend.Models.Generic;
+using RMuseum.Models.GanjoorAudio;
+using RMuseum.Models.GanjoorAudio.ViewModels;
+using RSecurityBackend.Models.Generic;
using System;
using System.Threading.Tasks;
@@ -9,6 +11,15 @@ namespace RMuseum.Services
///
public interface IAudioNarrationService
{
+ ///
+ /// returns list of narrations
+ ///
+ ///
+ /// send Guid.Empty if you want all narrations
+ ///
+ ///
+ public Task> GetAll(PagingParameterModel paging, Guid filteredUserId, AudioReviewStatus status);
+
///
/// imports data from ganjoor MySql database
///
diff --git a/RMuseum/Services/Implementation/AudioNarrationService.cs b/RMuseum/Services/Implementation/AudioNarrationService.cs
index 6172bc66..b7e7843c 100644
--- a/RMuseum/Services/Implementation/AudioNarrationService.cs
+++ b/RMuseum/Services/Implementation/AudioNarrationService.cs
@@ -3,21 +3,64 @@ using Microsoft.Extensions.Configuration;
using MySql.Data.MySqlClient;
using RMuseum.DbContext;
using RMuseum.Models.GanjoorAudio;
+using RMuseum.Models.GanjoorAudio.ViewModels;
using RSecurityBackend.Models.Generic;
+using RSecurityBackend.Services.Implementation;
using System;
+using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
-using System.Security.Policy;
using System.Threading.Tasks;
namespace RMuseum.Services.Implementation
{
+
///
/// Audio Narration Service Implementation
///
public class AudioNarrationService : IAudioNarrationService
{
+ ///
+ /// returns list of narrations
+ ///
+ ///
+ /// send Guid.Empty if you want all narrations
+ ///
+ ///
+ public async Task> GetAll(PagingParameterModel paging, Guid filteredUserId, AudioReviewStatus status)
+ {
+ try
+ {
+ var source =
+
+ _context.AudioFiles
+ .Include(a => a.Owner)
+ .Where(a =>
+ (filteredUserId == Guid.Empty || a.OwnerId == filteredUserId)
+ &&
+ (status == AudioReviewStatus.All || a.ReviewStatus == status)
+ )
+ .OrderBy(a => a.UploadDate)
+ .AsQueryable();
+
+ (PaginationMetadata PagingMeta, PoemNarration[] Items) paginatedResult =
+ await QueryablePaginator.Paginate(source, paging);
+
+ List res = new List();
+ foreach(PoemNarration audio in paginatedResult.Items)
+ {
+ res.Add(new PoemNarrationViewModel(audio));
+ }
+
+ return new RServiceResult<(PaginationMetadata PagingMeta, PoemNarrationViewModel[] Items)>((paginatedResult.PagingMeta, res.ToArray()));
+ }
+ catch (Exception exp)
+ {
+ return new RServiceResult<(PaginationMetadata PagingMeta, PoemNarrationViewModel[] Items)>((PagingMeta: null, Items: null), exp.ToString());
+ }
+ }
+
///
/// imports data from ganjoor MySql database
///
diff --git a/RSecurityBackend/Models/Generic/PagingParameterModel.cs b/RSecurityBackend/Models/Generic/PagingParameterModel.cs
index 12243baa..114c6b5c 100644
--- a/RSecurityBackend/Models/Generic/PagingParameterModel.cs
+++ b/RSecurityBackend/Models/Generic/PagingParameterModel.cs
@@ -14,17 +14,17 @@
const int MaxPageSize = 1000;
///
- /// page number
+ /// page number starting from 1
///
public int PageNumber { get; set; } = 1;
///
- /// actual page size
+ /// actual page size (-1 == all items)
///
private int _pageSize { get; set; } = -1;
///
- /// settable page size
+ /// settable page size (-1 == all items, 1000 maxpagesize)
///
public int PageSize
{
diff --git a/RSecurityBackend/RSecurityBackend.xml b/RSecurityBackend/RSecurityBackend.xml
index 7f5fbf08..1c6f20f6 100644
--- a/RSecurityBackend/RSecurityBackend.xml
+++ b/RSecurityBackend/RSecurityBackend.xml
@@ -1669,17 +1669,17 @@
- page number
+ page number starting from 1
- actual page size
+ actual page size (-1 == all items)
- settable page size
+ settable page size (-1 == all items, 1000 maxpagesize)