diff --git a/RMuseum/Controllers/RecitationController.cs b/RMuseum/Controllers/RecitationController.cs index cc684957..f384f4bb 100644 --- a/RMuseum/Controllers/RecitationController.cs +++ b/RMuseum/Controllers/RecitationController.cs @@ -258,6 +258,27 @@ namespace RMuseum.Controllers 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) + { + 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); + } + /// @@ -319,7 +340,7 @@ namespace RMuseum.Controllers [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Unauthorized)] [ProducesResponseType((int)HttpStatusCode.Forbidden, Type = typeof(string))] - public async Task ReciationNarrations(bool replace = false) + public async Task UploadReciation(bool replace = false) { try { @@ -469,6 +490,7 @@ namespace RMuseum.Controllers /// [HttpDelete("profile/{id}")] + [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Forbidden)] diff --git a/RMuseum/RMuseum.xml b/RMuseum/RMuseum.xml index 1cfb6805..64c6928b 100644 --- a/RMuseum/RMuseum.xml +++ b/RMuseum/RMuseum.xml @@ -753,6 +753,13 @@ + + + Delete a recitation + + + + Get User Uploads @@ -761,7 +768,7 @@ default: false, user must have narration::moderate permission to be able to see all users uploads - + Reciation Upload @@ -4973,6 +4980,14 @@ + + + Delete recitation + + + + + Gets Verse Sync Range Information @@ -5299,6 +5314,14 @@ + + + Delete recitation (recitation should belong to userId) + + + + + Gets Verse Sync Range Information diff --git a/RMuseum/Services/IRecitationService.cs b/RMuseum/Services/IRecitationService.cs index e76e2a23..c0caf388 100644 --- a/RMuseum/Services/IRecitationService.cs +++ b/RMuseum/Services/IRecitationService.cs @@ -30,6 +30,14 @@ namespace RMuseum.Services /// Task> Get(int id); + /// + /// Delete recitation (recitation should belong to userId) + /// + /// + /// + /// + Task> Delete(int id, Guid userId); + /// /// Gets Verse Sync Range Information /// diff --git a/RMuseum/Services/Implementation/RecitationService.cs b/RMuseum/Services/Implementation/RecitationService.cs index 76da3265..4e4a75b5 100644 --- a/RMuseum/Services/Implementation/RecitationService.cs +++ b/RMuseum/Services/Implementation/RecitationService.cs @@ -97,6 +97,77 @@ namespace RMuseum.Services.Implementation } } + /// + /// Delete recitation + /// + /// + /// + /// + public async Task> Delete(int id, Guid userId) + { + try + { + Recitation recitation = await _context.Recitations.Where(a => a.Id == id && a.OwnerId == userId).FirstOrDefaultAsync(); + if(recitation == null) + { + return new RServiceResult(false, "404"); + } + + + + if (recitation.ReviewStatus == AudioReviewStatus.Approved) + { + recitation.AudioSyncStatus = (int)AudioSyncStatus.Deleted; + _context.Recitations.Update(recitation); + await _context.SaveChangesAsync(); + + _backgroundTaskQueue.QueueBackgroundWorkItem + ( + async token => + { + using (RMuseumDbContext context = new RMuseumDbContext(Configuration)) //this is long running job, so _context might be already been freed/collected by GC + { + await _DeleteNarrationFromRemote(recitation, context); + } + + + }); + } + else + { + await _FinalizeDelete(_context, recitation); + } + + + return new RServiceResult(true); + } + catch (Exception exp) + { + return new RServiceResult(false, exp.ToString()); + } + } + + private async Task _FinalizeDelete(RMuseumDbContext context, Recitation recitation) + { + try + { + string mp3 = recitation.LocalMp3FilePath; + string xml = recitation.LocalXmlFilePath; + context.Recitations.Remove(recitation); + await context.SaveChangesAsync(); + + File.Delete(mp3); + File.Delete(xml); + + return ""; + } + catch(Exception exp) + { + return exp.ToString(); + } + } + + /// /// Gets Verse Sync Range Information /// @@ -945,6 +1016,58 @@ namespace RMuseum.Services.Implementation } } + private async Task _DeleteNarrationFromRemote(Recitation narration, RMuseumDbContext context) + { + using var client = new SftpClient + ( + Configuration.GetSection("AudioSFPServer")["Host"], + int.Parse(Configuration.GetSection("AudioSFPServer")["Port"]), + Configuration.GetSection("AudioSFPServer")["Username"], + Configuration.GetSection("AudioSFPServer")["Password"] + ); + try + { + client.Connect(); + client.DeleteFile($"{Configuration.GetSection("AudioSFPServer")["RootPath"]}{narration.RemoteXMLFilePath}"); + client.DeleteFile($"{Configuration.GetSection("AudioSFPServer")["RootPath"]}{narration.RemoteMp3FilePath}"); + + + + string sql = $"DELETE FROM ganja_gaudio WHERE audio_post_ID = {narration.GanjoorPostId} AND audio_order = {narration.AudioOrder} AND audio_guid = '{narration.LegacyAudioGuid}'"; + + using (MySqlConnection connection = new MySqlConnection + ( + $"server={Configuration.GetSection("AudioMySqlServer")["Server"]};uid={Configuration.GetSection("AudioMySqlServer")["Username"]};pwd={Configuration.GetSection("AudioMySqlServer")["Password"]};database={Configuration.GetSection("AudioMySqlServer")["Database"]};charset=utf8" + )) + { + await connection.OpenAsync(); + await connection.ExecuteAsync(sql); + } + + //We are using two database for different purposes on the remote + using (MySqlConnection connection = new MySqlConnection + ( + $"server={Configuration.GetSection("AudioMySqlServer")["Server"]};uid={Configuration.GetSection("AudioMySqlServer")["2ndUsername"]};pwd={Configuration.GetSection("AudioMySqlServer")["2ndPassword"]};database={Configuration.GetSection("AudioMySqlServer")["2ndDatabase"]};charset=utf8" + )) + { + await connection.OpenAsync(); + await connection.ExecuteAsync(sql); + } + + await _FinalizeDelete(context, narration); + + + } + catch + { + //if an error occurs, narration.AudioSyncStatus is not updated and narration can be idetified later to do "retrypublish" attempts + } + finally + { + client.Disconnect(); + } + } + /// /// retry publish unpublished narrations ///