16
16
using Serval . Client ;
17
17
using SIL . Converters . Usj ;
18
18
using SIL . ObjectModel ;
19
+ using SIL . Scripture ;
19
20
using SIL . XForge . Configuration ;
20
21
using SIL . XForge . DataAccess ;
21
22
using SIL . XForge . EventMetrics ;
@@ -380,7 +381,7 @@ CancellationToken cancellationToken
380
381
ServalBuildDto ? buildDto = null ;
381
382
382
383
// Ensure that the user has permission
383
- await EnsureProjectPermissionAsync ( curUserId , sfProjectId , isServalAdmin ) ;
384
+ SFProject project = await EnsureProjectPermissionAsync ( curUserId , sfProjectId , isServalAdmin ) ;
384
385
385
386
// Get the translation engine
386
387
string translationEngineId = await GetTranslationIdAsync ( sfProjectId , preTranslate : true ) ;
@@ -395,6 +396,91 @@ await translationEnginesClient.GetAllBuildsAsync(translationEngineId, cancellati
395
396
. MaxBy ( b => b . DateFinished ) ;
396
397
if ( translationBuild is not null )
397
398
{
399
+ // Verify that each book/chapter from the translationBuild is marked HasDraft = true
400
+ // If the projects texts chapters are not all marked as having a draft, then the webhook likely failed
401
+ // and we want to retrieve the pre-translation status to update the chapters as having a draft
402
+ Dictionary < string , List < int > > scriptureRanges = [ ] ;
403
+
404
+ IList < PretranslateCorpus > pretranslateCorpus = translationBuild . Pretranslate ?? [ ] ;
405
+
406
+ // Retrieve the user secret
407
+ Attempt < UserSecret > attempt = await userSecrets . TryGetAsync ( curUserId ) ;
408
+ if ( ! attempt . TryResult ( out UserSecret userSecret ) )
409
+ {
410
+ throw new DataNotFoundException ( "The user does not exist." ) ;
411
+ }
412
+
413
+ ScrVers versification = paratextService
414
+ . GetParatextSettings ( userSecret , project . ParatextId )
415
+ . Versification ;
416
+
417
+ ScriptureRangeParser scriptureRangeParser = new ScriptureRangeParser ( versification ) ;
418
+
419
+ // Create the dictionary of scripture range bookIds and bookNums to check against the project texts
420
+ Dictionary < string , int > scriptureRangeBooks = [ ] ;
421
+
422
+ foreach ( PretranslateCorpus ptc in pretranslateCorpus )
423
+ {
424
+ // We are using the TranslationBuild.Pretranslate.SourceFilters.ScriptureRange to find the
425
+ // books selected for drafting. Some projects may have used the now obsolete field
426
+ // TranslationBuild.Pretranslate.ScriptureRange and will not get checked for webhook failures.
427
+ foreach ( ParallelCorpusFilter source in ptc . SourceFilters ?? [ ] )
428
+ {
429
+ foreach (
430
+ ( string book , List < int > bookChapters ) in scriptureRangeParser . GetChapters (
431
+ source . ScriptureRange
432
+ )
433
+ )
434
+ {
435
+ int bookNum = Canon . BookIdToNumber ( book ) ;
436
+ scriptureRangeBooks . Add ( book , bookNum ) ;
437
+ // Ensure that if chapters is blank, it contains every chapter in the book
438
+ List < int > chapters = bookChapters ;
439
+ if ( chapters . Count == 0 )
440
+ {
441
+ chapters = [ .. Enumerable . Range ( 1 , versification . GetLastChapter ( bookNum ) ) ] ;
442
+ }
443
+
444
+ // Set or merge the list of chapters
445
+ if ( ! scriptureRanges . TryGetValue ( book , out List < int > existingChapters ) )
446
+ {
447
+ scriptureRanges [ book ] = chapters ;
448
+ }
449
+ else
450
+ {
451
+ // Merge new chapters into existing list, avoiding duplicates
452
+ foreach ( int chapter in chapters . Where ( chapter => ! existingChapters . Contains ( chapter ) ) )
453
+ {
454
+ existingChapters . Add ( chapter ) ;
455
+ }
456
+ // add existing chapters to the books chapter list
457
+ scriptureRanges [ book ] . AddRange ( existingChapters ) ;
458
+ }
459
+ }
460
+ }
461
+ }
462
+
463
+ string [ ] scriptureRangeIds = [ .. scriptureRanges . Keys ] ;
464
+
465
+ // check if any chapters from the scripture range are marked as HasDraft = false or null
466
+ bool hasDraftIsFalseOrNullInScriptureRange =
467
+ scriptureRangeBooks . Count > 0
468
+ ? scriptureRangeBooks . All ( kvp =>
469
+ {
470
+ return project . Texts . Any ( text =>
471
+ text . BookNum == kvp . Value
472
+ && text . Chapters . Where ( chapter => scriptureRanges [ kvp . Key ] . Contains ( chapter . Number ) )
473
+ . Any ( c => ! c . HasDraft ?? false )
474
+ ) ;
475
+ } )
476
+ : false ;
477
+
478
+ if ( hasDraftIsFalseOrNullInScriptureRange )
479
+ {
480
+ // Chapters HasDraft is missing or false but should be true, retrieve the pre-translation status to update them.
481
+ await RetrievePreTranslationStatusAsync ( sfProjectId , cancellationToken ) ;
482
+ }
483
+
398
484
buildDto = CreateDto ( translationBuild ) ;
399
485
}
400
486
}
0 commit comments