diff --git a/Backend.Tests/Mocks/WordRepositoryMock.cs b/Backend.Tests/Mocks/WordRepositoryMock.cs index fe0124e5d3..128796b0c0 100644 --- a/Backend.Tests/Mocks/WordRepositoryMock.cs +++ b/Backend.Tests/Mocks/WordRepositoryMock.cs @@ -35,8 +35,7 @@ public Task> GetAllWords(string projectId) { try { - var foundWord = _words.Single(word => word.Id == wordId); - return Task.FromResult(foundWord.Clone()); + return Task.FromResult(_words.Single(w => w.ProjectId == projectId && w.Id == wordId).Clone()); } catch (InvalidOperationException) { @@ -44,6 +43,12 @@ public Task> GetAllWords(string projectId) } } + public Task> GetWords(string projectId, List wordIds) + { + return Task.FromResult( + _words.Where(w => w.ProjectId == projectId && wordIds.Contains(w.Id)).Select(w => w.Clone()).ToList()); + } + public Task Create(Word word) { word.Id = Guid.NewGuid().ToString(); diff --git a/Backend/Interfaces/IWordRepository.cs b/Backend/Interfaces/IWordRepository.cs index 5cb78e4a4d..36a6cc6938 100644 --- a/Backend/Interfaces/IWordRepository.cs +++ b/Backend/Interfaces/IWordRepository.cs @@ -8,6 +8,7 @@ public interface IWordRepository { Task> GetAllWords(string projectId); Task GetWord(string projectId, string wordId); + Task> GetWords(string projectId, List wordIds); Task Create(Word word); Task> Create(List words); Task Add(Word word); diff --git a/Backend/Repositories/WordRepository.cs b/Backend/Repositories/WordRepository.cs index 128185d904..ed0cf8f9bb 100644 --- a/Backend/Repositories/WordRepository.cs +++ b/Backend/Repositories/WordRepository.cs @@ -80,8 +80,17 @@ public async Task> GetAllWords(string projectId) } } - /// Removes all s from the WordsCollection and Frontier for specified - /// + /// Finds project s with specified ids + public async Task> GetWords(string projectId, List wordIds) + { + using var activity = OtelService.StartActivityWithTag(otelTagName, "getting words"); + + return await _words.Find(GetProjectWordsFilter(projectId, wordIds)).ToListAsync(); + } + + /// + /// Removes all s from the WordsCollection and Frontier for specified + /// /// A bool: success of operation public async Task DeleteAllWords(string projectId) { @@ -130,7 +139,6 @@ private static void PopulateBlankWordTimes(Word word) /// If the Created or Modified time fields are blank, they will automatically calculated using the current /// time. This allows services to set or clear the values before creation to control these fields. /// - /// /// The word created public async Task Create(Word word) { @@ -148,7 +156,6 @@ public async Task Create(Word word) /// If the Created or Modified time fields are blank, they will automatically calculated using the current /// time. This allows services to set or clear the values before creation to control these fields. /// - /// /// The words created public async Task> Create(List words) { diff --git a/Backend/Services/WordService.cs b/Backend/Services/WordService.cs index 75ae36bcff..4172e03840 100644 --- a/Backend/Services/WordService.cs +++ b/Backend/Services/WordService.cs @@ -92,22 +92,39 @@ private async Task Add(string userId, Word word) return (await Add(userId, word)).Id; } - /// Restores words to the Frontier - /// A bool: true if successful, false if any don't exist or are already in the Frontier. + /// Restores words to the Frontier that aren't in the Frontier + /// A bool: true if all successfully restored public async Task RestoreFrontierWords(string projectId, List wordIds) { using var activity = OtelService.StartActivityWithTag(otelTagName, "restoring words to Frontier"); - var words = new List(); - foreach (var id in wordIds) + // Allow calls that don't specify any wordIds, but don't do any work. + if (wordIds.Count == 0) { - var word = await _wordRepo.GetWord(projectId, id); - if (word is null || await _wordRepo.IsInFrontier(projectId, id)) - { - return false; - } - words.Add(word); + return true; } + + wordIds = wordIds.Distinct().ToList(); + + // Make sure none of the words are in the Frontier. + if (await _wordRepo.AreInFrontier(projectId, wordIds, 1)) + { + return false; + } + + // Make sure all the words exist and are valid. + var words = await _wordRepo.GetWords(projectId, wordIds); + if (words.Count != wordIds.Count) + { + return false; + } + if (words.Any(w => w.Accessibility == Status.Deleted)) + { + // We should be restoring words that were removed from the Frontier, + // and not their "Deleted" copies in the words collection. + return false; + } + await _wordRepo.AddFrontier(words); return true; }