protected virtual void ExtractLinks(BulkLoadContext context, BulkLoadItem item, BulkField field, LinkedList <BulkItemLink> links)
        {
            if (string.IsNullOrWhiteSpace(field.Value))
            {
                return;
            }
            if (IgnoredFields.Value.Contains(field.Name))
            {
                return;
            }

            var ids = IdRegex.Value.Matches(field.Value).Cast <Match>()
                      .Select(x =>
            {
                ID id;
                return(ID.TryParse(x.Value, out id) ? id : (ID)null);
            })
                      .Concat(LinkRegex.Value.Matches(field.Value).Cast <Match>().Select(x =>
            {
                Guid guid;
                return(Guid.TryParse(x.Value, out guid) ? new ID(guid) : (ID)null);
            }))
                      .Where(x => x != (ID)null);

            foreach (var link in ids
                     .Select(x => new BulkItemLink(
                                 context.Database, new ID(item.Id), new ID(field.Id),
                                 context.Database, x, x.ToString())))
            {
                link.ItemAction = item.LoadAction;
                links.AddLast(link);
            }
        }
예제 #2
0
        protected virtual void AddStatisticsFieldsWhenMissing(BulkLoadItem bulkItem, string language, int versionNumber = 1)
        {
            var user = global::Sitecore.Context.User.Name;

            if (bulkItem.GetField(FieldIDs.Created.Guid, language, versionNumber) == null)
            {
                bulkItem.AddVersionedField(FieldIDs.Created.Guid, language, versionNumber, DateUtil.IsoNow, name: "__Created");
            }

            if (bulkItem.GetField(FieldIDs.CreatedBy.Guid, language, versionNumber) == null)
            {
                bulkItem.AddVersionedField(FieldIDs.CreatedBy.Guid, language, versionNumber, user, name: "__Created by");
            }

            if (bulkItem.LoadAction == BulkLoadAction.Update || bulkItem.LoadAction == BulkLoadAction.UpdateExistingItem)
            {
                if (bulkItem.GetField(FieldIDs.UpdatedBy.Guid, language, versionNumber) == null)
                {
                    bulkItem.AddVersionedField(FieldIDs.UpdatedBy.Guid, language, versionNumber, user, name: "__Updated");
                }

                if (bulkItem.GetField(FieldIDs.Updated.Guid, language, versionNumber) == null)
                {
                    bulkItem.AddVersionedField(FieldIDs.Updated.Guid, language, versionNumber, DateUtil.IsoNowWithTicks, name: "__Updated by");
                }
            }
        }
 protected virtual void ExtractLinks(BulkLoadContext context, BulkLoadItem item, LinkedList <BulkItemLink> links)
 {
     foreach (var field in item.Fields)
     {
         ExtractLinks(context, item, field, links);
     }
 }
예제 #4
0
        public virtual BulkLoadItem ToBulkLoadItem(IItemData itemData, BulkLoadContext context,
                                                   BulkLoadAction loadAction)
        {
            if (itemData == null)
            {
                throw new ArgumentNullException(nameof(itemData));
            }
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var bulkItem = new BulkLoadItem(
                loadAction,
                itemData.Id,
                itemData.TemplateId,
                itemData.BranchId,
                itemData.ParentId,
                itemData.Path,
                sourceInfo: itemData.SerializedItemId);

            foreach (var sharedField in itemData.SharedFields)
            {
                AddSyncField(context, bulkItem, sharedField);
            }

            foreach (var languagedFields in itemData.UnversionedFields)
            {
                foreach (var field in languagedFields.Fields)
                {
                    AddSyncField(context, bulkItem, field, languagedFields.Language.Name);
                }
            }

            foreach (var versionFields in itemData.Versions)
            {
                foreach (var field in versionFields.Fields)
                {
                    AddSyncField(context, bulkItem, field, versionFields.Language.Name, versionFields.VersionNumber);
                }

                AddStatisticsFieldsWhenMissing(bulkItem, versionFields.Language.Name, versionFields.VersionNumber);
            }

            // Serialized items don't contain the original blob id.
            context.LookupBlobIds = true;

            return(bulkItem);
        }
예제 #5
0
        protected virtual void AddSyncField(BulkLoadContext context, BulkLoadItem bulkItem, IItemFieldValue itemField,
                                            string language = null, int versionNumber = 1)
        {
            var fieldId    = itemField.FieldId;
            var fieldValue = itemField.Value;
            var fieldName  = itemField.NameHint;
            var isBlob     = itemField.BlobId.HasValue;

            Func <Stream> blob = null;

            if (isBlob)
            {
                byte[] blobBytes;
                try
                {
                    blobBytes = Convert.FromBase64String(fieldValue);
                }
                catch (Exception ex)
                {
                    blobBytes = new byte[] { };
                    context.Log.Error(
                        $"Unable to read blob from field '{fieldId}' in item with id '{bulkItem.Id}', " +
                        $"item path '{bulkItem.ParentId}' and source info '{bulkItem.SourceInfo}', defaulting to empty value.",
                        ex);
                }
                blob = () => new MemoryStream(blobBytes);

                // Field value needs to be set to the blob id.
                fieldValue = itemField.BlobId.Value.ToString("B").ToUpper();
            }

            if (language == null)
            {
                bulkItem.AddSharedField(fieldId, fieldValue, blob, isBlob, fieldName);
            }
            else
            {
                bulkItem.AddVersionedField(fieldId, language, versionNumber, fieldValue, blob, isBlob, fieldName);
            }
        }
예제 #6
0
        protected virtual void AddStatisticsFieldsWhenMissing(BulkLoadItem bulkItem, string language,
                                                              int versionNumber = 1)
        {
            var user = Sitecore.Context.User.Name;

            // Make sure revision is updated when item is created or updated so that smart publish works.
            // Unicorn doesn't track revisions, so we need to generate one ourselves.
            if (bulkItem.GetField(FieldIDs.Revision.Guid, language, versionNumber) == null)
            {
                bulkItem.AddVersionedField(FieldIDs.Revision.Guid, language, versionNumber, Guid.NewGuid().ToString("D"), name: "__Revision",
                                           postProcessor: x => x.DependsOnCreate = x.DependsOnUpdate = true);
            }

            if (bulkItem.GetField(FieldIDs.Created.Guid, language, versionNumber) == null)
            {
                bulkItem.AddVersionedField(FieldIDs.Created.Guid, language, versionNumber, DateUtil.IsoNow, name: "__Created",
                                           postProcessor: x => x.DependsOnCreate = true);
            }

            if (bulkItem.GetField(FieldIDs.CreatedBy.Guid, language, versionNumber) == null)
            {
                bulkItem.AddVersionedField(FieldIDs.CreatedBy.Guid, language, versionNumber, user, name: "__Created by",
                                           postProcessor: x => x.DependsOnCreate = true);
            }

            if (bulkItem.GetField(FieldIDs.Updated.Guid, language, versionNumber) == null)
            {
                bulkItem.AddVersionedField(FieldIDs.Updated.Guid, language, versionNumber, DateUtil.IsoNow, name: "__Updated",
                                           postProcessor: x => x.DependsOnCreate = x.DependsOnUpdate = true);
            }

            if (bulkItem.GetField(FieldIDs.UpdatedBy.Guid, language, versionNumber) == null)
            {
                bulkItem.AddVersionedField(FieldIDs.UpdatedBy.Guid, language, versionNumber, user, name: "__Updated by",
                                           postProcessor: x => x.DependsOnCreate = x.DependsOnUpdate = true);
            }
        }
        protected virtual IEnumerable <BulkLoadItem> EnsureAncestorBulkItems(BulkLoadItem item,
                                                                             ItemReference root, Template ancestorTemplate, Guid dependsOnItemCreation,
                                                                             BulkLoadContext context)
        {
            if (item == null)
            {
                throw new ArgumentNullException(nameof(item));
            }
            if (root == null)
            {
                throw new ArgumentNullException(nameof(root));
            }
            if (ancestorTemplate == null)
            {
                throw new ArgumentNullException(nameof(ancestorTemplate));
            }
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
            if (!item.ItemPath.StartsWith(root.ItemPath))
            {
                throw new ArgumentException("Bulk item should be a descendant of the root.");
            }

            // Detect all the ancestors to generate.
            var ancestorNames = item.ItemPath.Substring(root.ItemPath.Length)
                                .Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);

            ancestorNames = ancestorNames.Take(ancestorNames.Length - 1).ToArray(); // Don't include item.

            // Generate all ancestors.
            var parent = root;

            foreach (var name in ancestorNames)
            {
                var itemPath = $"{parent.ItemPath}/{name}";

                // Maybe we have already generated this path in a previous call to EnsureAncestors within the same context.
                var itemId = context.GetProcessedPath(itemPath);
                if (itemId.HasValue)
                {
                    // Continue with next.
                    parent = new ItemReference(itemId.Value, itemPath);
                    continue;
                }

                // Generate stable guid for this ancestor item within its parent.
                itemId = _guidUtility.Create(parent.ItemId, name);

                // In case of forced updates, also update the child item. This will result in an ItemChange which makes sure the item gets re-published.
                var childLoadAction = context.ForceUpdates ? BulkLoadAction.Update : BulkLoadAction.AddOnly;

                // Create new bulk item.
                var child = new BulkLoadItem(childLoadAction, itemId.Value, ancestorTemplate.ID.Guid,
                                             Guid.Empty, parent.ItemId, itemPath,
                                             templateName: ancestorTemplate.Name, sourceInfo: item.SourceInfo)
                {
                    // Only create ancestor when child is created, skip ancestor creation when child is updated.
                    DependsOnItemCreation = dependsOnItemCreation
                };

                // Attach asap to context, because import profiles might eagerly bucket.
                context.TrackPathAndTemplateInfo(child);

                yield return(child);

                parent = new ItemReference(child.Id, child.ItemPath);
            }

            // Reset parent reference for initial item.
            item.ParentId = parent.ItemId;
        }
 /// <summary>
 /// Returns ancestor items for every needed level between the item and the root.
 /// </summary>
 /// <param name="item">Item to generate ancestors for.</param>
 /// <param name="root">Root that marks the ancestor that should already exist or be present in the stream.</param>
 /// <param name="ancestorTemplate">Template for the ancestors to generate.</param>
 /// <param name="context">Context to generate the ancestors in.</param>
 /// <returns>Stream of generated ancestors, migh be empty if ancestors were already created,
 /// or it might be partial if shared ancestors were already created for another item in the same context.</returns>
 public virtual IEnumerable <BulkLoadItem> EnsureAncestorBulkItems(BulkLoadItem item, ItemReference root,
                                                                   Template ancestorTemplate, BulkLoadContext context)
 {
     return(EnsureAncestorBulkItems(item, root, ancestorTemplate, item.Id, context));
 }
예제 #9
0
        protected virtual IEnumerable <BulkLoadItem> Bucket(BulkLoadItem item, BulkLoadContext context, bool skipIfNotBucket)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
            if (item == null)
            {
                throw new ArgumentNullException(nameof(item));
            }

            if (item.Bucketed)
            {
                yield return(item);

                yield break;
            }

            var db         = Factory.GetDatabase(context.Database);
            var bucketItem = db.GetItem(new ID(item.ParentId));

            if (bucketItem == null && !skipIfNotBucket)
            {
                throw new ArgumentException(
                          $"Unable to bucket item because parent with id '{item.ParentId}' doesn't exist.");
            }
            if (bucketItem == null)
            {
                yield return(item);

                yield break;
            }

            if (!bucketItem.IsABucket())
            {
                if (skipIfNotBucket)
                {
                    yield return(item);

                    yield break;
                }
                throw new InvalidOperationException(
                          $"Item with path '{bucketItem.Paths.Path}' is not bucket.");
            }

            // Get template for ancestors.
            var bucketFolderTemplate = TemplateManager.GetTemplate(new ID(BucketFolderTemplate), db);

            // Default to configured bucket folder generation.
            if (context.BucketFolderPath == null)
            {
                context.BucketFolderPath = new BucketFolderPathResolver();
            }

            // Try to find out when item was created.
            var createdField = item.Fields.FirstOrDefault(
                x => x.Id == FieldIDs.Created.Guid && !string.IsNullOrWhiteSpace(x.Value));
            var created = createdField == null ? DateTime.UtcNow : DateUtil.IsoDateToDateTime(createdField.Value);

            var bucketFolderPath = context.BucketFolderPath.GetFolderPath(db,
                                                                          item.Name.Replace(' ', '0'), // Sitecore's name based bucket folder generation doesn't handle spaces.
                                                                          new ID(item.TemplateId), new ID(item.Id), bucketItem.ID, created);

            item.ItemPath = bucketItem.Paths.Path + "/" + bucketFolderPath + "/" + item.Name;
            item.Bucketed = true;

            // Check if bucket folder path depends on creation date.
            if (context.GetState <bool?>("Load.BucketByDate") == null)
            {
                created = new DateTime(2000, 01, 01, 01, 01, 01);
                var testBucketFolderPath = context.BucketFolderPath.GetFolderPath(db,
                                                                                  item.Name, new ID(item.TemplateId), new ID(item.Id), bucketItem.ID, created);
                if (!bucketFolderPath.Equals(testBucketFolderPath, StringComparison.OrdinalIgnoreCase))
                {
                    context.Log.Warn(
                        "Bucket strategy is based on creation date, this will affect import performance, " +
                        "but might also not be repeatable.");
                    context.GetOrAddState <bool?>("Load.BucketByDate", () => true);
                }
            }

            // If bucketing depends on date, lookup item by name with wildcard.
            var dependsOnDate = context.GetState <bool?>("Load.BucketsByDate", false);

            if (dependsOnDate.GetValueOrDefault(false))
            {
                context.LookupItemIds = true;
                item.ItemLookupPath   = bucketItem.Paths.Path + "/**/" + item.Name;
            }

            foreach (var ancestor in _ancestorGenerator.EnsureAncestorBulkItems(item,
                                                                                new ItemReference(bucketItem.ID.Guid, bucketItem.Paths.Path), bucketFolderTemplate, context))
            {
                // Make sure ancestor doesn't get re-bucketed.
                ancestor.Bucketed = true;
                yield return(ancestor);
            }

            yield return(item);
        }