public AllInOneDto Load(IBlock block, IContextBuilder contextBuilder, int appId, List <ItemIdentifier> items) { // Security check var wraplog = Log.Call($"load many a#{appId}, items⋮{items.Count}"); // do early permission check - but at this time it may be that we don't have the types yet // because they may be group/id combinations, without type information which we'll look up afterwards var appIdentity = State.Identity(null, appId); //var block = GetBlock(); items = new ContentGroupList(block, Log).ConvertListIndexToId(items, appIdentity); // now look up the types, and repeat security check with type-names // todo: 2020-03-20 new feat 11.01, may not check inner type permissions ATM var permCheck = new MultiPermissionsTypes().Init(block.Context, GetApp(appId, block), items, Log); if (!permCheck.EnsureAll(GrantSets.WriteSomething, out var error)) { throw HttpException.PermissionDenied(error); } // load items - similar var result = new AllInOneDto(); var entityApi = new EntityApi(appId, permCheck.EnsureAny(GrantSets.ReadDraft), Log); var typeRead = entityApi.AppRead.ContentTypes; var list = entityApi.GetEntitiesForEditing(items); var jsonSerializer = new JsonSerializer(); result.Items = list.Select(e => new BundleWithHeader <JsonEntity> { Header = e.Header, Entity = GetSerializeAndMdAssignJsonEntity(appId, e, jsonSerializer, typeRead) }).ToList(); // set published if some data already exists if (list.Any()) { result.IsPublished = list.First().Entity?.IsPublished ?? true; // Entity could be null (new), then true // only set draft-should-branch if this draft already has a published item if (!result.IsPublished) { result.DraftShouldBranch = list.First().Entity?.GetPublished() != null; } } // since we're retrieving data - make sure we're allowed to // this is to ensure that if public forms only have create permissions, they can't access existing data // important, this code is shared/duplicated in the EntitiesController.GetManyForEditing if (list.Any(set => set.Entity != null)) { if (!permCheck.EnsureAll(GrantSets.ReadSomething, out error)) { throw HttpException.PermissionDenied(error); } } // load content-types var types = UsedTypes(list, typeRead); result.ContentTypes = types .Select(ct => JsonSerializer.ToJson(ct, true)) .ToList(); // todo: ensure that sub-properties of the content-types are included var entList = types.SelectMany( // in all Content-Type attributes like title, body etc. t => t.Attributes.SelectMany( // check all metadata of these attributes - get possible sub-entities attached a => a.Metadata.SelectMany(m => m.Children()) ) ); result.ContentTypeItems = entList.Select(e => jsonSerializer.ToJson(e, 0, Log)).ToList(); // Fix not-supported input-type names; map to correct name result.ContentTypes .ForEach(jt => jt.Attributes .ForEach(at => at.InputType = InputTypes.MapInputTypeV10(at.InputType))); // load input-field configurations result.InputTypes = GetNecessaryInputTypes(result.ContentTypes, typeRead); // also include UI features result.Features = FeaturesHelpers.FeatureListWithPermissionCheck(permCheck).ToList(); // Attach context result.Context = contextBuilder.InitApp(appIdentity.ZoneId, permCheck.App) .Get(Ctx.AppBasic | Ctx.Language | Ctx.Site | Ctx.System); // done - return wraplog($"ready, sending items:{result.Items.Count}, " + $"types:{result.ContentTypes.Count}, " + $"inputs:{result.InputTypes.Count}, " + $"feats:{result.Features.Count}"); return(result); }
public Dictionary <Guid, int> Save([FromBody] AllInOneDto package, int appId, bool partOfPage) => new EditSaveBackend().Init(Log) .Save(GetBlock(), package, appId, partOfPage);
public Dictionary <Guid, int> Save(IBlock block, AllInOneDto package, int appId, bool partOfPage) { Log.Add($"save started with a#{appId}, i⋮{package.Items.Count}, partOfPage:{partOfPage}"); var validator = new SaveDataValidator(package, Log); // perform some basic validation checks if (!validator.ContainsOnlyExpectedNodes(out var exp)) { throw exp; } // todo: unsure about this - thought I should check contentblockappid in group-header, because this is where it should be saved! //var contextAppId = appId; //var targetAppId = package.Items.First().Header.Group.ContentBlockAppId; //if (targetAppId != 0) //{ // Log.Add($"detected content-block app to use: {targetAppId}; in context of app {contextAppId}"); // appId = targetAppId; //} var appMan = new AppManager(appId, Log); var appRead = appMan.Read; var ser = new JsonSerializer(appRead.AppState, Log) { // Since we're importing directly into this app, we would prefer local content-types PreferLocalAppTypes = true }; validator.PrepareForEntityChecks(appRead); #region check if it's an update, and do more security checks then - shared with EntitiesController.Save // basic permission checks var permCheck = new Save.SaveSecurity(block, Log) .DoPreSaveSecurityCheck(appId, package.Items); var foundItems = package.Items.Where(i => i.Entity.Id != 0 && i.Entity.Guid != Guid.Empty) .Select(i => i.Entity.Guid != Guid.Empty ? appRead.Entities.Get(i.Entity.Guid) // prefer guid access if available : appRead.Entities.Get(i.Entity.Id) // otherwise id ); if (foundItems.Any(i => i != null) && !permCheck.EnsureAll(GrantSets.UpdateSomething, out var error)) { throw HttpException.PermissionDenied(error); } #endregion var items = package.Items.Select(i => { var ent = ser.Deserialize(i.Entity, false, false) as Entity; var index = package.Items.IndexOf(i); // index is helpful in case of errors if (!validator.EntityIsOk(index, ent, out exp)) { throw exp; } if (!validator.IfUpdateValidateAndCorrectIds(index, ent, out exp)) { throw exp; } ent.IsPublished = package.IsPublished; ent.PlaceDraftInBranch = package.DraftShouldBranch; // new in 11.01 if (i.Header.ListHas()) { // Check if Add was true, and fix if it had already been saved (EntityId != 0) // the entityId is reset by the validator if it turns out to be an update // todo: verify use - maybe it's to set before we save, as maybe afterwards it's always != 0? var add = i.Header.ListAdd(); i.Header.Add = add; if (ent.EntityId > 0 && add) { i.Header.Add = false; } } return(new BundleWithHeader <IEntity> { Header = i.Header, Entity = ent }); }) .ToList(); Log.Add("items to save generated, all data tests passed"); var publishing = new SxcPagePublishing().Init(block, Log); return(publishing.SaveInPagePublishing(appId, items, partOfPage, forceSaveAsDraft => new EditSaveBackend().DoSave(appMan, items, forceSaveAsDraft), permCheck)); }