Last active
February 21, 2020 15:31
-
-
Save ivakhnov/819cf94d6e3f5a3be22a09b64b6dedb9 to your computer and use it in GitHub Desktop.
#[Asset versioning (Complete ActionScript)] The script receives two asset Ids, then takes the file related through MasterFile relation of one asset and makes this file entity as the new version of the MasterFile of the other asset. Updates the FileHistory of the second asset and entirely deletes the first asset. #sitecorecontenthub #contenthub #…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using Stylelabs.M.Sdk; | |
| using System.Linq; | |
| using System.Threading.Tasks; | |
| // People should not be calling the endpoint of this Script directly. | |
| // It's meant to be "behind" of the automatised raw component. | |
| var destinationAssetIdString = Context.Data["destinationAssetId"]?.ToString(); | |
| var sourceAssetIdString = Context.Data["sourceAssetId"]?.ToString(); | |
| var triggeringUserName = Context.Data["triggeringUserName"]?.ToString(); | |
| if (string.IsNullOrEmpty(triggeringUserName)) | |
| { | |
| throw new ValidationException( | |
| "Triggering user is lacking from the payload", | |
| new ValidationFailure("Please, specify the name of the triggering user!", "User")); | |
| } | |
| var userClient = await GetImpersonatedClientAsync(triggeringUserName).ConfigureAwait(false); | |
| if (string.IsNullOrEmpty(destinationAssetIdString)) | |
| { | |
| throw new ValidationException( | |
| "When merging assets, the destination Asset Id should not be null!", | |
| new ValidationFailure("Please, specify the id of the asset into which you want to merge the other asset!", "DestinationAssetId")); | |
| } | |
| var destinationAssetId = long.Parse(destinationAssetIdString); | |
| if (string.IsNullOrEmpty(sourceAssetIdString)) | |
| { | |
| throw new ValidationException( | |
| "When merging assets, the source Asset Id should not be null!", | |
| new ValidationFailure("Please, specify the id of the asset id which you want to merge into the other asset!", "SourceAssetId")); | |
| } | |
| var sourceAssetId = long.Parse(sourceAssetIdString); | |
| var sourceMasterFileIds = await GetMasterFilesAsync(sourceAssetId).ConfigureAwait(false); | |
| await MakeRoomForNewFileAsync(destinationAssetId).ConfigureAwait(false); | |
| await SetNewMasterFileAsync(destinationAssetId, sourceMasterFileIds).ConfigureAwait(false); | |
| await userClient.Entities.DeleteAsync(sourceAssetId).ConfigureAwait(false); | |
| // Done :) | |
| ///////////////// | |
| // Helper methods | |
| async Task<long[]> GetMasterFilesAsync(long assetId) | |
| { | |
| var entityLoadConfiguration = new EntityLoadConfiguration() | |
| { | |
| PropertyLoadOption = PropertyLoadOption.None, | |
| RelationLoadOption = new RelationLoadOption("MasterFile"), | |
| CultureLoadOption = CultureLoadOption.Default | |
| }; | |
| var asset = await MClient.Entities.GetAsync(assetId, entityLoadConfiguration).ConfigureAwait(false); | |
| var masterFileRelation = asset.GetRelation("MasterFile", RelationRole.Parent); | |
| if (masterFileRelation == null) | |
| { | |
| throw new ValidationException( | |
| $"The asset entity with id '{asset.Id}' does not have relation 'MasterFile'.", | |
| new ValidationFailure($"The asset entity with id '{asset.Id}' does not have relation 'MasterFile'.", "SourceAssetId")); | |
| } | |
| var masterFileIds = masterFileRelation.GetIds(); | |
| if (!masterFileIds.Any()) | |
| { | |
| throw new ValidationException( | |
| $"The asset entity with id '{asset.Id}' does have an empty 'MasterFile' relation.", | |
| new ValidationFailure($"The asset entity with id '{asset.Id}' does have an empty 'MasterFile' relation.", "SourceAssetId")); | |
| } | |
| return masterFileIds.ToArray(); | |
| } | |
| async Task MakeRoomForNewFileAsync(long destinationAssetId) | |
| { | |
| var entityLoadConfiguration = new EntityLoadConfiguration() | |
| { | |
| PropertyLoadOption = PropertyLoadOption.None, | |
| RelationLoadOption = new RelationLoadOption("MasterFile", "FileHistory"), | |
| CultureLoadOption = CultureLoadOption.Default | |
| }; | |
| var asset = await MClient.Entities.GetAsync(destinationAssetId, entityLoadConfiguration).ConfigureAwait(false); | |
| var masterFileRelation = asset.GetRelation("MasterFile", RelationRole.Parent); | |
| var fileHistoryRelation = asset.GetRelation("FileHistory", RelationRole.Parent); | |
| if (masterFileRelation == null) | |
| { | |
| throw new ValidationException( | |
| $"The asset entity with id '{asset.Id}' does not have relation 'MasterFile'.", | |
| new ValidationFailure($"The asset entity with id '{asset.Id}' does not have relation 'MasterFile'.", "DestinationAssetId")); | |
| } | |
| if (fileHistoryRelation == null) | |
| { | |
| throw new ValidationException( | |
| $"The asset entity with id '{asset.Id}' does not have relation 'FileHistory'.", | |
| new ValidationFailure($"The asset entity with id '{asset.Id}' does not have relation 'FileHistory'.", "DestinationAssetId")); | |
| } | |
| var masterFileIds = masterFileRelation.GetIds(); | |
| var historyFileIds = fileHistoryRelation.GetIds(); | |
| // Check all masterfiles and move them to filehistory if needed. eg: when importing files through our excel-import it can have (temporary) multiple masterfiles. | |
| foreach (var masterFileId in masterFileIds) | |
| { | |
| if (!historyFileIds.Contains(masterFileId)) | |
| { | |
| historyFileIds.Add(masterFileId); | |
| } | |
| } | |
| // Clear all master ids | |
| masterFileIds.Clear(); | |
| await userClient.Entities.SaveAsync(asset).ConfigureAwait(false); | |
| } | |
| async Task SetNewMasterFileAsync(long destinationAssetId, long[] sourceMasterFileIds) | |
| { | |
| // The renditions object proerty and the MainFile property needs to be updated on the Asset entity. It should recieve the same property values as it's main file | |
| // from MasterFile relation. This is done under the hood by M by listening on the saves of the M.File entities. | |
| // All this listening happens based on the saved entity which should contains the following relations and properties. | |
| // M SDK is operating on the API, hence they are loaded on the entity before saving for sure, but for Scripting that's not the case. We need to load them explicitly | |
| // into the entity before saving if we want to rely on the logic in SaveFileCommandHandler. | |
| var entityLoadConfiguration = new EntityLoadConfiguration() | |
| { | |
| PropertyLoadOption = new PropertyLoadOption( "FileName","MainFile","AlternateFile","Renditions","ExtraRenditions","Structure","Digest","VirusScanResult","DisableDuplicate" ), | |
| RelationLoadOption = new RelationLoadOption( "MasterFile","FileHistory","FileToSubFile" ), | |
| CultureLoadOption = CultureLoadOption.Default | |
| }; | |
| foreach (var masterFileId in sourceMasterFileIds) | |
| { | |
| var file = await MClient.Entities.GetAsync(masterFileId, entityLoadConfiguration).ConfigureAwait(false); | |
| var masterFileRelation = file.GetRelation("MasterFile", RelationRole.Child); | |
| masterFileRelation.SetIds(new long[] { destinationAssetId }); | |
| await userClient.Entities.SaveAsync(file).ConfigureAwait(false); | |
| } | |
| } | |
| async Task<IMClient> GetImpersonatedClientAsync(string userName) | |
| { | |
| var impersonatedClient = await MClient.ImpersonateAsync(userName).ConfigureAwait(false); | |
| return impersonatedClient; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment