public void Test_TemporaryIds(long id, bool shouldRaiseException) { UserAccount userAccount = null; EntityType entityType = null; MockRepository mockRepository; Mock <IEntity> mockEntity = null; Mock <IEntityInternal> mockEntityInternal = null; EntityModificationToken entityModificationToken; userAccount = Entity.Create <UserAccount>(); userAccount.Name = "Test user " + Guid.NewGuid().ToString(); userAccount.Save(); entityType = new EntityType(); entityType.Inherits.Add(UserResource.UserResource_Type); entityType.Save(); new AccessRuleFactory().AddAllowCreate(userAccount.As <Subject>(), entityType.As <SecurableEntity>()); // Mock an Entity. Yes, I am completely insane. mockRepository = new MockRepository(MockBehavior.Loose); mockEntity = mockRepository.Create <IEntity>(); mockEntity.SetupGet(e => e.TypeIds).Returns(() => new[] { entityType.Id }); mockEntity.SetupGet(e => e.EntityTypes).Returns(() => new[] { entityType }); mockEntity.Setup(e => e.IsReadOnly).Returns(() => false); mockEntity.SetupGet(e => e.Id).Returns(() => id); mockEntityInternal = mockEntity.As <IEntityInternal>(); mockEntityInternal.SetupGet(ei => ei.IsTemporaryId).Returns(() => EntityTemporaryIdAllocator.IsAllocatedId(id)); entityModificationToken = new EntityModificationToken(); mockEntityInternal.SetupGet(ei => ei.ModificationToken).Returns(() => entityModificationToken); using (new SetUser(userAccount)) { Assert.That(() => Entity.Save(new [] { mockEntity.Object }, false), shouldRaiseException ? (Constraint)Throws.Nothing : Throws.TypeOf <PlatformSecurityException>()); } }
/// <summary> /// Walk the entity data tree, first creating any new entities, then updating /// the entities and finally deleting any marked for delete. /// </summary> /// <param name="entityDataRoot">The entity data root.</param> /// <param name="persistChanges">If false, the entities are created in memory, but not persisted.</param> /// <param name="retries">The retries.</param> /// <returns> /// A mapping of old to new entity ids. /// </returns> /// <exception cref="System.ArgumentException">entityData.TypeIds must be set when creating new instances. /// or /// Attempted to create an entity using a temporary entity Id</exception> /// <exception cref="System.InvalidOperationException">Entity ID was not set and DataState was not create. /// or /// Entity not found. Id= + entityDataNode.Id /// or /// We have a newly created object that was not marked as DataState.Create. Id= + entityDataNode.Id</exception> private Dictionary <long, IEntity> CreateUpdateDeleteImpl(EntityData entityDataRoot, bool persistChanges, int retries = 0) { Dictionary <long, IEntity> entityMap = null; DatabaseContext.RunWithRetry(() => { var originalRootState = entityDataRoot.DataState; // get the distinct nodes so we only have to walk the tree once var distinctNodes = WalkEntityDataTree(entityDataRoot, null); // ensure any deleted or created items cause entities that refer to them to be marked as changed CascadeUpRelationshipChanges(distinctNodes); ///// // Track the created id's. ///// entityMap = new Dictionary <long, IEntity>(); var toSave = new List <IEntity>(); var toDelete = new HashSet <long>(); // // Create the entities but do not save them // foreach (var entityDataNode in distinctNodes) { if (entityDataNode.DataState == DataState.Create) { bool hasId = entityDataNode.Id != null && entityDataNode.Id.HasId; long id = hasId ? entityDataNode.Id.Id : -1; if (!persistChanges && !hasId && !string.IsNullOrWhiteSpace(entityDataNode.Id?.Alias)) { // entity ref has no id but has an alias // resolve alias to id rather than creating a temp id = entityDataNode.Id.ResolveId(); hasId = true; } if (entityDataNode.TypeIds == null || entityDataNode.TypeIds.Count <= 0) { throw new ArgumentException("entityData.TypeIds must be set when creating new instances."); } if (entityDataNode.TypeIds.Any(tid => tid.Id > 0 && EntityTemporaryIdAllocator.IsAllocatedId(tid.Id))) { throw new ArgumentException("Attempted to create an entity using a temporary entity Id"); } Entity newEntity = !persistChanges && hasId ? new Entity(entityDataNode.TypeIds, id) : new Entity(entityDataNode.TypeIds); // if we were not given an Id to use as a reference, use new temporary one. if (!hasId) { id = newEntity.Id; entityDataNode.Id = id; } toSave.Add(newEntity); entityMap[id] = newEntity; entityDataNode.DataState = DataState.Update; } else { if (entityDataNode.Id == null) { throw new InvalidOperationException("Entity ID was not set and DataState was not create."); } long id = entityDataNode.Id.Id; if (id > 0 && !entityMap.ContainsKey(id)) { entityMap[id] = Entity.Get(id); if (entityMap[id] == null && entityDataNode.DataState != DataState.Delete) { throw new InvalidOperationException("Entity not found. Id=" + entityDataNode.Id); } } // This is not a nice test for a new node, but I don't have a better one if (entityDataNode.DataState == DataState.Update && id > EntityId.MinTemporary) { throw new InvalidOperationException("We have a newly created object that was not marked as DataState.Create. Id=" + entityDataNode.Id); } } } // Update the entities in memory UpdateImpl(distinctNodes, entityMap, toSave, toDelete); // Persist changes if (persistChanges) { // Gather the ids for deletion var delete = toDelete.Select(d => new EntityRef(d)).ToList(); delete.AddRange(distinctNodes.Where(n => n.DataState == DataState.Delete).Select(n => n.Id)); // Check delete permissions before the update takes place EntityAccessControlService.Demand(delete, new[] { Permissions.Read, Permissions.Delete }); // Save all the created and changed entities (allowing entities to move from nodes deleted above) Entity.Save(toSave.Distinct()); using (new SecurityBypassContext()) { Entity.Delete(delete); } } // Return the root entity if (originalRootState == DataState.Delete) { entityMap = null; } }); return(entityMap); }
public bool OnBeforeSave(IEnumerable <IEntity> entities, IDictionary <string, object> state) { foreach (Document document in from entity in entities where entity.Is <Document>() select entity.AsWritable <Document>()) { // Populate the document revision DocumentRevision revision = Entity.Create <DocumentRevision>(); bool createNewRevision = false; bool initialRevision = false; if (EntityTemporaryIdAllocator.IsAllocatedId(document.Id)) { // Populate the initial version string for the document revision.VersionComments = @"Initial Version"; revision.Version = @"1.0"; revision.Name = revision.Version; createNewRevision = true; initialRevision = true; } else { DocumentRevision currentRevision = document.CurrentDocumentRevision; if (currentRevision?.FileDataHash != document.FileDataHash) { // Extract the version number and increment it string newRevision = string.Format("{0}.0", Convert.ToInt32(currentRevision.Version.Split('.')[0]) + 1); revision.VersionComments = document.Description; // Need to modify the document entity to include a hidden field for comments ?? revision.Version = newRevision; revision.Name = newRevision; createNewRevision = true; } } if (createNewRevision) { revision.FileExtension = document.FileExtension; revision.ModifiedDate = DateTime.UtcNow; revision.Size = document.Size; // Get the entity that represents the user UserAccount userAccount = Entity.Get <UserAccount>(RequestContext.GetContext().Identity.Id); // Associate the revision to the account revision.RevisionUpdatedBy = userAccount; // Associate the file to this revision revision.FileDataHash = document.FileDataHash; SaveGraph saveGraph = EventTargetStateHelper.GetSaveGraph(state); saveGraph.Entities[revision.Id] = revision; document.CurrentDocumentRevision = revision; // Associate the document to the revision (documentHasDocumentRevision - used for version history listing) document.DocumentHasDocumentRevision.Add(revision); // Associate the last created user to the document if (initialRevision) { document.DocumentCreatedBy = userAccount; } // Associate the last modified user to the document document.DocumentModifiedBy = userAccount; } document.DocumentHasDocumentType = document.DocumentFileType; if (document.InFolder == null) { // Default document dumping ground if not specified document.InFolder = Entity.Get <DocumentFolder>(new EntityRef("core", "documentsDocumentFolder")); } } return(false); }
/// <summary> /// Gets the form data. /// </summary> /// <param name="request">The request.</param> /// <returns></returns> public FormDataResponse GetFormData(FormDataRequest request) { if (request == null) { throw new ArgumentNullException(nameof(request)); } var entityIdRef = new EntityRef(request.EntityId); // Get the entity data EntityData entityData = BulkRequestRunner.GetEntityData(entityIdRef, request.Query, request.Hint); // Set the result to NotFound for Basic and BasicWithDemand only if (entityData == null) { return(null); } var formId = new EntityRef(request.FormId).Id; EntityData formEntityData = null; // Get the form entity data for non gen forms if (!EntityTemporaryIdAllocator.IsAllocatedId(formId)) { try { formEntityData = GetFormAsEntityData(formId, false); } catch (Exception ex) { EventLog.Application.WriteError("Failed to get form with id {0}. Unable to get initial form control visibility. Error: {1}.", formId, ex); } } ISet <long> initiallyHiddenControls = null; if (formEntityData == null) { return(PackageFormDataResponse(entityData, null)); } IDictionary <long, IExpression> compiledExpressions = null; IDictionary <long, string> controlVisibilityCalculations; using (new SecurityBypassContext()) { // Have form. Get any visibility calculations controlVisibilityCalculations = GetControlVisibilityCalculations(formEntityData); long entityTypeId = GetTypeToEditWithForm(formEntityData); if (controlVisibilityCalculations.Count > 0 && entityTypeId > 0) { // Now we have all the calculations compiledExpressions = CompileVisibilityCalculations(new EntityRef(entityTypeId), controlVisibilityCalculations); } } if (controlVisibilityCalculations.Count > 0) { initiallyHiddenControls = GetHiddenControls(entityIdRef.Entity, controlVisibilityCalculations.Keys, compiledExpressions); } return(PackageFormDataResponse(entityData, initiallyHiddenControls)); }