20
20
using Blueprint . Api . Infrastructure . Options ;
21
21
using Blueprint . Api . ViewModels ;
22
22
using Blueprint . Api . Infrastructure . JsonConverters ;
23
+ using NuGet . Packaging . Licenses ;
24
+ using System . Data ;
23
25
24
26
namespace Blueprint . Api . Services
25
27
{
@@ -29,6 +31,7 @@ public interface IScenarioEventService
29
31
Task < ViewModels . ScenarioEvent > GetAsync ( Guid id , CancellationToken ct ) ;
30
32
Task < IEnumerable < ViewModels . ScenarioEvent > > CreateAsync ( ViewModels . ScenarioEvent scenarioEvent , CancellationToken ct ) ;
31
33
Task < IEnumerable < ViewModels . ScenarioEvent > > CreateFromInjectsAsync ( CreateFromInjectsForm createFromInjectsForm , CancellationToken ct ) ;
34
+ Task < IEnumerable < ViewModels . ScenarioEvent > > CopyScenarioEventsToMselAsync ( Guid mselId , List < Guid > scenarioEventIdList , CancellationToken ct ) ;
32
35
Task < IEnumerable < ViewModels . ScenarioEvent > > UpdateAsync ( Guid id , ViewModels . ScenarioEvent scenarioEvent , CancellationToken ct ) ;
33
36
Task < bool > DeleteAsync ( Guid id , CancellationToken ct ) ;
34
37
Task < bool > BatchDeleteAsync ( Guid [ ] idList , CancellationToken ct ) ;
@@ -339,6 +342,152 @@ public ScenarioEventService(
339
342
return _mapper . Map < IEnumerable < ViewModels . ScenarioEvent > > ( scenarioEventEnitities ) ;
340
343
}
341
344
345
+ public async Task < IEnumerable < ViewModels . ScenarioEvent > > CopyScenarioEventsToMselAsync ( Guid mselId , List < Guid > scenarioEventIdList , CancellationToken ct )
346
+ {
347
+ // make sure destination MSEL exists
348
+ var destinationMsel = await _context . Msels
349
+ . Include ( m => m . DataFields )
350
+ . SingleOrDefaultAsync ( v => v . Id == mselId , ct ) ;
351
+ if ( destinationMsel == null )
352
+ throw new EntityNotFoundException < ScenarioEventEntity > ( $ "MSEL not found { mselId } .") ;
353
+
354
+ // make sure the source MSEL and all scenarioEvents exist
355
+ var sourceMsel = await _context . ScenarioEvents
356
+ . Where ( m => m . Id == scenarioEventIdList [ 0 ] )
357
+ . Include ( m => m . Msel )
358
+ . ThenInclude ( m => m . DataFields )
359
+ . ThenInclude ( f => f . DataOptions )
360
+ . Include ( m => m . Msel )
361
+ . ThenInclude ( m => m . ScenarioEvents )
362
+ . ThenInclude ( s => s . DataValues )
363
+ . Select ( m => m . Msel )
364
+ . AsSplitQuery ( )
365
+ . AsNoTracking ( )
366
+ . SingleOrDefaultAsync ( ct ) ;
367
+
368
+ // user must be a Content Developer or a MSEL owner for both source and destination MSELs
369
+ if ( ! ( await _authorizationService . AuthorizeAsync ( _user , null , new ContentDeveloperRequirement ( ) ) ) . Succeeded &&
370
+ ! ( await MselOwnerRequirement . IsMet ( _user . GetId ( ) , mselId , _context ) &&
371
+ await MselOwnerRequirement . IsMet ( _user . GetId ( ) , sourceMsel . Id , _context ) ) )
372
+ throw new ForbiddenException ( ) ;
373
+
374
+ // get the sourceScenarioEvents
375
+ var sourceScenarioEvents = sourceMsel . ScenarioEvents . Where ( s => scenarioEventIdList . Contains ( s . Id ) ) ;
376
+ if ( sourceMsel == null || sourceScenarioEvents . Count ( ) != scenarioEventIdList . Count ( ) )
377
+ throw new DataException ( "The list of Scenario Event IDs was invalid." ) ;
378
+
379
+ // determine which data fields are used by these scenario events
380
+ var neededDataFields = new List < Guid > ( ) ;
381
+ foreach ( var scenarioEvent in sourceScenarioEvents )
382
+ {
383
+ foreach ( var dataValue in scenarioEvent . DataValues )
384
+ {
385
+ if ( dataValue . Value != null && ! neededDataFields . Contains ( dataValue . DataFieldId ) )
386
+ {
387
+ neededDataFields . Add ( dataValue . DataFieldId ) ;
388
+ }
389
+ }
390
+ }
391
+ // set some initial values
392
+ var userId = _user . GetId ( ) ;
393
+ var dateCreated = DateTime . UtcNow ;
394
+ var dataFieldDictionary = new Dictionary < Guid , Guid > ( ) ;
395
+ var displayOrder = destinationMsel . DataFields . Count > 0
396
+ ? destinationMsel . DataFields . Max ( m => m . DisplayOrder )
397
+ : 0 ;
398
+
399
+ // start a transaction
400
+ await _context . Database . BeginTransactionAsync ( ) ;
401
+
402
+ // get the data field map (create new data fields as necessary)
403
+ foreach ( var sourceDataField in sourceMsel . DataFields . Where ( m => neededDataFields . Contains ( m . Id ) ) )
404
+ {
405
+ var destinationDataField = destinationMsel . DataFields . SingleOrDefault ( m => m . Name == sourceDataField . Name && m . DataType == sourceDataField . DataType ) ;
406
+ if ( destinationDataField == null )
407
+ {
408
+ destinationDataField = new DataFieldEntity ( )
409
+ {
410
+ Id = Guid . NewGuid ( ) ,
411
+ MselId = destinationMsel . Id ,
412
+ Name = sourceDataField . Name ,
413
+ DataType = sourceDataField . DataType ,
414
+ DisplayOrder = ++ displayOrder ,
415
+ DateCreated = dateCreated ,
416
+ CreatedBy = userId ,
417
+ IsChosenFromList = sourceDataField . IsChosenFromList ,
418
+ OnScenarioEventList = sourceDataField . OnScenarioEventList ,
419
+ OnExerciseView = sourceDataField . OnExerciseView ,
420
+ } ;
421
+ _context . DataFields . Add ( destinationDataField ) ;
422
+ if ( sourceDataField . IsChosenFromList )
423
+ {
424
+ foreach ( var sourceDataOption in sourceDataField . DataOptions )
425
+ {
426
+ var destinationDataOption = new DataOptionEntity ( )
427
+ {
428
+ Id = Guid . NewGuid ( ) ,
429
+ DataFieldId = destinationDataField . Id ,
430
+ OptionName = sourceDataOption . OptionName ,
431
+ OptionValue = sourceDataOption . OptionValue ,
432
+ DisplayOrder = sourceDataOption . DisplayOrder ,
433
+ } ;
434
+ _context . DataOptions . Add ( destinationDataOption ) ;
435
+ }
436
+ }
437
+ }
438
+ dataFieldDictionary [ destinationDataField . Id ] = sourceDataField . Id ;
439
+ }
440
+ await _context . SaveChangesAsync ( ct ) ;
441
+ // get the new list of data field IDs
442
+ var dataFieldIdList = _context . DataFields
443
+ . Where ( df => df . MselId == destinationMsel . Id )
444
+ . Select ( df => df . Id ) ;
445
+ // Loop through the source scenario events
446
+ foreach ( var sourceScenarioEvent in sourceScenarioEvents )
447
+ {
448
+ var destinationScenarioEvent = new ScenarioEventEntity ( )
449
+ {
450
+ Id = Guid . NewGuid ( ) ,
451
+ MselId = destinationMsel . Id ,
452
+ GroupOrder = 0 ,
453
+ IsHidden = false ,
454
+ DeltaSeconds = sourceScenarioEvent . DeltaSeconds ,
455
+ ScenarioEventType = sourceScenarioEvent . ScenarioEventType ,
456
+ Description = sourceScenarioEvent . Description ,
457
+ InjectId = sourceScenarioEvent . InjectId ,
458
+ DateCreated = dateCreated ,
459
+ CreatedBy = userId ,
460
+ } ;
461
+ _context . ScenarioEvents . Add ( destinationScenarioEvent ) ;
462
+ // create blank data values
463
+ foreach ( var dataFieldId in dataFieldIdList )
464
+ {
465
+ var dataValue = new DataValueEntity ( ) ;
466
+ dataValue . DataFieldId = dataFieldId ;
467
+ dataValue . Id = Guid . NewGuid ( ) ;
468
+ dataValue . ScenarioEventId = destinationScenarioEvent . Id ;
469
+ dataValue . CreatedBy = userId ;
470
+ dataValue . DateCreated = dateCreated ;
471
+ dataValue . DateModified = null ;
472
+ dataValue . ModifiedBy = null ;
473
+ if ( dataFieldDictionary . Keys . Contains ( dataFieldId ) )
474
+ {
475
+ dataValue . Value = sourceScenarioEvent . DataValues . Single ( m => m . DataFieldId == dataFieldDictionary [ dataFieldId ] ) . Value ;
476
+ }
477
+ _context . DataValues . Add ( dataValue ) ;
478
+ }
479
+ }
480
+ await _context . SaveChangesAsync ( ct ) ;
481
+ // commit the transaction
482
+ await _context . Database . CommitTransactionAsync ( ct ) ;
483
+ // return all msel scenarioEvents
484
+ var scenarioEventEnitities = await _context . ScenarioEvents
485
+ . Include ( m => m . DataValues )
486
+ . Where ( m => m . MselId == destinationMsel . Id )
487
+ . ToListAsync ( ct ) ;
488
+ return _mapper . Map < IEnumerable < ViewModels . ScenarioEvent > > ( scenarioEventEnitities ) ;
489
+ }
490
+
342
491
public async Task < IEnumerable < ViewModels . ScenarioEvent > > UpdateAsync ( Guid id , ViewModels . ScenarioEvent scenarioEvent , CancellationToken ct )
343
492
{
344
493
var canUpdateScenarioEvent = ( await _authorizationService . AuthorizeAsync ( _user , null , new ContentDeveloperRequirement ( ) ) ) . Succeeded ||
0 commit comments