Skip to content

Commit

Permalink
Add audio Speaker (#2795)
Browse files Browse the repository at this point in the history
* Add Backend model/repo/controller for speaker
* Add audio consent api; Add speaker to project state
* Add Speaker types to Startup.cs
* Add skeleton setting for project speakers
* Enable add/edit/delete speaker
* Add consent image upload interface
* Enable hearing/seeing speaker consent
* Add speaker menu
* Consolidate consent icon
* Add Pronunciation model for audio
* Export audio speaker in pronunciation label
* Protect audio with English label to prevent overwriting
* Implement FileWithSpeakerId extends File
* Enable changing audio speaker
* Include consent files in export
* Add py script for db update
* Remove old one-shot script
* Update db script: protect audio; add execute permission
  • Loading branch information
imnasnainaec authored Jan 9, 2024
1 parent 965112d commit 6d03bc3
Show file tree
Hide file tree
Showing 86 changed files with 4,902 additions and 622 deletions.
101 changes: 72 additions & 29 deletions Backend.Tests/Controllers/AudioControllerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ protected virtual void Dispose(bool disposing)
}

private string _projId = null!;
private string _wordId = null!;
private const string FileName = "sound.mp3"; // file in Backend.Tests/Assets/
private readonly Stream _stream = File.OpenRead(Path.Combine(Util.AssetsDir, FileName));
private FileUpload _fileUpload = null!;

[SetUp]
public void Setup()
Expand All @@ -45,65 +49,104 @@ public void Setup()
_audioController = new AudioController(_wordRepo, _wordService, _permissionService);

_projId = _projRepo.Create(new Project { Name = "AudioControllerTests" }).Result!.Id;
_wordId = _wordRepo.Create(Util.RandomWord(_projId)).Result.Id;

var formFile = new FormFile(_stream, 0, _stream.Length, "Name", FileName);
_fileUpload = new FileUpload { File = formFile, Name = "FileName" };
}

[TearDown]
public void TearDown()
[Test]
public void TestUploadAudioFileUnauthorized()
{
_projRepo.Delete(_projId);
_audioController.ControllerContext.HttpContext = PermissionServiceMock.UnauthorizedHttpContext();
var result = _audioController.UploadAudioFile(_projId, _wordId, _fileUpload).Result;
Assert.That(result, Is.InstanceOf<ForbidResult>());

result = _audioController.UploadAudioFile(_projId, _wordId, "", _fileUpload).Result;
Assert.That(result, Is.InstanceOf<ForbidResult>());
}

[Test]
public void TestDownloadAudioFileInvalidArguments()
public void TestUploadAudioFileInvalidArguments()
{
var result = _audioController.DownloadAudioFile("invalid/projId", "wordId", "fileName");
var result = _audioController.UploadAudioFile("invalid/projId", _wordId, _fileUpload).Result;
Assert.That(result, Is.TypeOf<UnsupportedMediaTypeResult>());

result = _audioController.DownloadAudioFile("projId", "invalid/wordId", "fileName");
result = _audioController.UploadAudioFile(_projId, "invalid/wordId", _fileUpload).Result;
Assert.That(result, Is.TypeOf<UnsupportedMediaTypeResult>());

result = _audioController.DownloadAudioFile("projId", "wordId", "invalid/fileName");
result = _audioController.UploadAudioFile("invalid/projId", _wordId, "speakerId", _fileUpload).Result;
Assert.That(result, Is.TypeOf<UnsupportedMediaTypeResult>());

result = _audioController.UploadAudioFile(_projId, "invalid/wordId", "speakerId", _fileUpload).Result;
Assert.That(result, Is.TypeOf<UnsupportedMediaTypeResult>());
}

[Test]
public void TestDownloadAudioFileNoFile()
public void TestUploadConsentNullFile()
{
var result = _audioController.DownloadAudioFile("projId", "wordId", "fileName");
Assert.That(result, Is.TypeOf<BadRequestObjectResult>());
var result = _audioController.UploadAudioFile(_projId, _wordId, new()).Result;
Assert.That(result, Is.InstanceOf<BadRequestObjectResult>());

result = _audioController.UploadAudioFile(_projId, _wordId, "speakerId", new()).Result;
Assert.That(result, Is.InstanceOf<BadRequestObjectResult>());
}

[Test]
public void TestAudioImport()
public void TestUploadConsentEmptyFile()
{
const string soundFileName = "sound.mp3";
var filePath = Path.Combine(Util.AssetsDir, soundFileName);
// Use 0 for the third argument
var formFile = new FormFile(_stream, 0, 0, "Name", FileName);
_fileUpload = new FileUpload { File = formFile, Name = FileName };

var result = _audioController.UploadAudioFile(_projId, _wordId, _fileUpload).Result;
Assert.That(result, Is.InstanceOf<BadRequestObjectResult>());
result = _audioController.UploadAudioFile(_projId, _wordId, "speakerId", _fileUpload).Result;
Assert.That(result, Is.InstanceOf<BadRequestObjectResult>());
}

// Open the file to read to controller.
using var stream = File.OpenRead(filePath);
var formFile = new FormFile(stream, 0, stream.Length, "name", soundFileName);
var fileUpload = new FileUpload { File = formFile, Name = "FileName" };
[Test]
public void TestUploadAudioFile()
{
// `_fileUpload` contains the file stream and the name of the file.
_ = _audioController.UploadAudioFile(_projId, _wordId, "speakerId", _fileUpload).Result;

var word = _wordRepo.Create(Util.RandomWord(_projId)).Result;
var foundWord = _wordRepo.GetWord(_projId, _wordId).Result;
Assert.That(foundWord?.Audio, Is.Not.Null);
}

// `fileUpload` contains the file stream and the name of the file.
_ = _audioController.UploadAudioFile(_projId, word.Id, fileUpload).Result;
[Test]
public void TestDownloadAudioFileInvalidArguments()
{
var result = _audioController.DownloadAudioFile("invalid/projId", "wordId", "fileName");
Assert.That(result, Is.TypeOf<UnsupportedMediaTypeResult>());

var foundWord = _wordRepo.GetWord(_projId, word.Id).Result;
Assert.That(foundWord?.Audio, Is.Not.Null);
result = _audioController.DownloadAudioFile("projId", "invalid/wordId", "fileName");
Assert.That(result, Is.TypeOf<UnsupportedMediaTypeResult>());

result = _audioController.DownloadAudioFile("projId", "wordId", "invalid/fileName");
Assert.That(result, Is.TypeOf<UnsupportedMediaTypeResult>());
}

[Test]
public void DeleteAudio()
public void TestDownloadAudioFileNoFile()
{
// Fill test database
var origWord = _wordRepo.Create(Util.RandomWord(_projId)).Result;
var result = _audioController.DownloadAudioFile("projId", "wordId", "fileName");
Assert.That(result, Is.TypeOf<BadRequestObjectResult>());
}

// Add audio file to word
origWord.Audio.Add("a.wav");
[Test]
public void DeleteAudio()
{
// Refill test database
_wordRepo.DeleteAllWords(_projId);
var origWord = Util.RandomWord(_projId);
var fileName = "a.wav";
origWord.Audio.Add(new Pronunciation(fileName));
var wordId = _wordRepo.Create(origWord).Result.Id;

// Test delete function
_ = _audioController.DeleteAudioFile(_projId, origWord.Id, "a.wav").Result;
_ = _audioController.DeleteAudioFile(_projId, wordId, fileName).Result;

// Original word persists
Assert.That(_wordRepo.GetAllWords(_projId).Result, Has.Count.EqualTo(2));
Expand All @@ -119,7 +162,7 @@ public void DeleteAudio()

// Ensure the word with deleted audio is in the frontier
Assert.That(frontier, Has.Count.EqualTo(1));
Assert.That(frontier[0].Id, Is.Not.EqualTo(origWord.Id));
Assert.That(frontier[0].Id, Is.Not.EqualTo(wordId));
Assert.That(frontier[0].Audio, Has.Count.EqualTo(0));
Assert.That(frontier[0].History, Has.Count.EqualTo(1));
}
Expand Down
20 changes: 12 additions & 8 deletions Backend.Tests/Controllers/LiftControllerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public class LiftControllerTests : IDisposable
{
private IProjectRepository _projRepo = null!;
private ISemanticDomainRepository _semDomRepo = null!;
private ISpeakerRepository _speakerRepo = null!;
private IWordRepository _wordRepo = null!;
private ILiftService _liftService = null!;
private IHubContext<CombineHub> _notifyService = null!;
Expand Down Expand Up @@ -54,8 +55,9 @@ public void Setup()
{
_projRepo = new ProjectRepositoryMock();
_semDomRepo = new SemanticDomainRepositoryMock();
_speakerRepo = new SpeakerRepositoryMock();
_wordRepo = new WordRepositoryMock();
_liftService = new LiftService(_semDomRepo);
_liftService = new LiftService(_semDomRepo, _speakerRepo);
_notifyService = new HubContextMock();
_permissionService = new PermissionServiceMock();
_wordService = new WordService(_wordRepo);
Expand Down Expand Up @@ -512,17 +514,18 @@ public void TestRoundtrip(RoundTripObj roundTripObj)
// We are currently only testing guids and imported audio on the single-entry data sets.
if (allWords.Count == 1)
{
var word = allWords[0].Clone();
Assert.That(roundTripObj.EntryGuid, Is.Not.EqualTo(""));
Assert.That(allWords[0].Guid.ToString(), Is.EqualTo(roundTripObj.EntryGuid));
Assert.That(word.Guid.ToString(), Is.EqualTo(roundTripObj.EntryGuid));
if (roundTripObj.SenseGuid != "")
{
Assert.That(allWords[0].Senses[0].Guid.ToString(), Is.EqualTo(roundTripObj.SenseGuid));
Assert.That(word.Senses[0].Guid.ToString(), Is.EqualTo(roundTripObj.SenseGuid));
}
foreach (var audioFile in allWords[0].Audio)
foreach (var audio in word.Audio)
{
Assert.That(roundTripObj.AudioFiles, Does.Contain(Path.GetFileName(audioFile)));
Assert.That(roundTripObj.AudioFiles, Does.Contain(Path.GetFileName(audio.FileName)));
Assert.That(audio.Protected, Is.True);
}

}

// Assert that the first SemanticDomain doesn't have an empty MongoId.
Expand Down Expand Up @@ -588,10 +591,11 @@ public void TestRoundtrip(RoundTripObj roundTripObj)
// We are currently only testing guids on the single-entry data sets.
if (roundTripObj.EntryGuid != "" && allWords.Count == 1)
{
Assert.That(allWords[0].Guid.ToString(), Is.EqualTo(roundTripObj.EntryGuid));
var word = allWords[0];
Assert.That(word.Guid.ToString(), Is.EqualTo(roundTripObj.EntryGuid));
if (roundTripObj.SenseGuid != "")
{
Assert.That(allWords[0].Senses[0].Guid.ToString(), Is.EqualTo(roundTripObj.SenseGuid));
Assert.That(word.Senses[0].Guid.ToString(), Is.EqualTo(roundTripObj.SenseGuid));
}
}

Expand Down
Loading

0 comments on commit 6d03bc3

Please sign in to comment.