Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add audio Speaker #2795

Merged
merged 71 commits into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
5e0f72d
Add Backend model/repo/controller for speaker
imnasnainaec Nov 16, 2023
9799ebb
Add audio consent api; Add speaker to project state
imnasnainaec Nov 16, 2023
9613cea
Negotiate with CodeQL
imnasnainaec Nov 17, 2023
f26a00b
Add Speaker types to Startup.cs
imnasnainaec Nov 17, 2023
239e764
Add skeleton setting for project speakers
imnasnainaec Nov 17, 2023
32a888d
Enable add/edit/delete speaker
imnasnainaec Nov 17, 2023
b1b1723
Merge branch 'master' into speaker
imnasnainaec Nov 17, 2023
8b07ee4
Use mic icon
imnasnainaec Nov 17, 2023
344072c
Add consent image upload interface
imnasnainaec Nov 17, 2023
2d27bfb
Finish consent upload interfaces and api
imnasnainaec Nov 17, 2023
4d678cd
Fix tests
imnasnainaec Nov 17, 2023
e581134
Enable hearing/seeing speaker consent
imnasnainaec Nov 20, 2023
76046f1
Adjust play button size
imnasnainaec Nov 20, 2023
26c5129
Fix up consent buttons and api functions
imnasnainaec Nov 20, 2023
8798839
Fix comment
imnasnainaec Nov 20, 2023
9457914
Add speaker menu
imnasnainaec Nov 30, 2023
5686e6f
Merge branch 'master' into speaker
imnasnainaec Nov 30, 2023
b9499d8
Consolidate consent icon
imnasnainaec Dec 1, 2023
75bf989
Merge branch 'master' into speaker
imnasnainaec Dec 1, 2023
c97d9b2
Add Pronunciation model for audio
imnasnainaec Dec 1, 2023
775cba4
Export audio speaker in pronunciation label
imnasnainaec Dec 4, 2023
f8d5c82
Protect audio with English label to prevent overwriting
imnasnainaec Dec 4, 2023
1a98f72
Merge branch 'master' into speaker
imnasnainaec Dec 4, 2023
6c30b7d
Add null check to fix tests
imnasnainaec Dec 4, 2023
79cad3d
Merge branch 'master' into speaker
imnasnainaec Dec 4, 2023
969e96f
Fix frontend tests
imnasnainaec Dec 4, 2023
144751d
Attach current speaker id to new audio recordings
imnasnainaec Dec 4, 2023
79fcc43
Fix backend test
imnasnainaec Dec 4, 2023
225f407
Merge branch 'master' into speaker
imnasnainaec Dec 5, 2023
a8fccd6
Implement FileWithSpeakerId extends File
imnasnainaec Dec 5, 2023
c98435c
uploadFileFromUrl -> uploadFileFromPronunciation
imnasnainaec Dec 5, 2023
8b7bdae
Enable changing audio speaker
imnasnainaec Dec 5, 2023
fc908d5
Fix several bugs
imnasnainaec Dec 6, 2023
4bbfa05
Add tests for SpeakerController
imnasnainaec Dec 6, 2023
17bf947
Include consent files in export
imnasnainaec Dec 7, 2023
03f4214
Show message in speaker menu when no project speakers
imnasnainaec Dec 7, 2023
46569dc
Update WordService tests
imnasnainaec Dec 7, 2023
6601526
Update LiftController tests
imnasnainaec Dec 7, 2023
f70c4c3
Merge branch 'master' into speaker
imnasnainaec Dec 7, 2023
9ecbbf9
Fix comments
imnasnainaec Dec 7, 2023
e70d1a8
Merge branch 'master' into speaker
imnasnainaec Dec 7, 2023
589309d
Remove unnecessary deduplication
imnasnainaec Dec 7, 2023
684915a
Update AppBar ProjectButtons tests
imnasnainaec Dec 7, 2023
1e51b5d
Alphabetize
imnasnainaec Dec 7, 2023
a6350b1
Add SpeakerMenu tests
imnasnainaec Dec 7, 2023
bce11e1
Update ReviewEntriesActions tests
imnasnainaec Dec 7, 2023
99a7fd9
Add SpeakerConsentListItemIcon tests
imnasnainaec Dec 8, 2023
0989a19
Add ProjectSpeakersList test
imnasnainaec Dec 8, 2023
0ea477a
Merge branch 'master' into speaker
imnasnainaec Dec 8, 2023
f880bc3
Fix up speaker management consent dialogs
imnasnainaec Dec 8, 2023
d10b368
Add missing s
imnasnainaec Dec 8, 2023
1daa473
Fix bug in row-edit mode: tooltip no update when speakerId removed
imnasnainaec Dec 8, 2023
ab0c35e
Fix bug is row-edit mode: audio w/ diff speakerId are lost
imnasnainaec Dec 8, 2023
cc19299
Fix _protected bug
imnasnainaec Dec 8, 2023
1fd42ad
Add speakers to User Guide
imnasnainaec Dec 11, 2023
1095dc0
Protect all imported audio
imnasnainaec Dec 11, 2023
e16e058
Tidy
imnasnainaec Dec 11, 2023
2ec600e
Merge branch 'master' into speaker
imnasnainaec Dec 12, 2023
7c58b18
Merge branch 'master' into speaker
imnasnainaec Dec 14, 2023
d5466f1
Merge branch 'master' into speaker
imnasnainaec Dec 15, 2023
b47fef4
Expand AudioController tests
imnasnainaec Jan 2, 2024
7d3869c
Add py script for db update
imnasnainaec Jan 2, 2024
be3faa3
Make tox earn its keep
imnasnainaec Jan 2, 2024
d2ca75b
Merge branch 'master' into speaker
imnasnainaec Jan 2, 2024
fe76805
Remove old one-shot script
imnasnainaec Jan 3, 2024
d170691
Update db script: protect audio; add execute permission
imnasnainaec Jan 4, 2024
f4b9e6d
Tidy tests and docs
imnasnainaec Jan 4, 2024
5382b9d
Add speaker export details to docs
imnasnainaec Jan 4, 2024
ed821be
Add icon spacer to avoid close button overlapping title
imnasnainaec Jan 4, 2024
e5f10b6
Merge branch 'master' into speaker
imnasnainaec Jan 5, 2024
f92115b
Merge branch 'master' into speaker
imnasnainaec Jan 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading