예제 #1
0
        /// <summary>
        ///  Initialize the XElement with the core Key, Name, Level values
        /// </summary>
        protected virtual XElement InitializeNode(TObject item, string typeName, SyncSerializerOptions options)
        {
            var node = new XElement(this.ItemType,
                                    new XAttribute("Key", item.Key),
                                    new XAttribute("Alias", item.Name),
                                    new XAttribute("Level", GetLevel(item)));

            // are we only serizling some cultures ?
            var cultures = options.GetSetting(uSyncConstants.CultureKey, string.Empty);

            if (!string.IsNullOrWhiteSpace(cultures) && item.ContentType.VariesByCulture())
            {
                node.Add(new XAttribute(uSyncConstants.CultureKey, cultures));
            }

            // are we only serizling some segments ?
            var segments = options.GetSetting(uSyncConstants.SegmentKey, string.Empty);

            if (!string.IsNullOrWhiteSpace(segments) && item.ContentType.Variations.VariesBySegment())
            {
                node.Add(new XAttribute(uSyncConstants.SegmentKey, segments));
            }

            // are we including the default (not variant) values in the serialized result?
            if (options.GetSetting(uSyncConstants.DefaultsKey, false) && !item.ContentType.VariesByNothing())
            {
                node.Add(new XAttribute(uSyncConstants.DefaultsKey, true));
            }

            return(node);
        }
예제 #2
0
        /// <summary>
        ///  Initialize the XElement with the core Key, Name, Level values
        /// </summary>
        protected virtual XElement InitializeNode(TObject item, string typeName, SyncSerializerOptions options)
        {
            var node = new XElement(this.ItemType,
                                    new XAttribute("Key", item.Key),
                                    new XAttribute("Alias", item.Name),
                                    new XAttribute("Level", GetLevel(item)));

            // are we only serizling some cultures ?
            var cultures = options.GetSetting(uSyncConstants.CultureKey, string.Empty);

            if (IsPartialCultureElement(item, cultures))
            {
                node.Add(new XAttribute(uSyncConstants.CultureKey, cultures));
            }

            // are we only serizling some segments ?
            var segments = options.GetSetting(uSyncConstants.SegmentKey, string.Empty);

            if (IsPartialSegmentElement(item, segments))
            {
                node.Add(new XAttribute(uSyncConstants.SegmentKey, segments));
            }

            // are we including the default (not variant) values in the serialized result?
            // we only worry about this when we are passing partial cultures or segments
            // to the file, when we sync complte content items, this is reduntant.
            if (options.GetSetting(uSyncConstants.DefaultsKey, true) && IsPartialElement(item, cultures, segments))
            {
                node.Add(new XAttribute(uSyncConstants.DefaultsKey, true));
            }

            return(node);
        }
예제 #3
0
        protected override SyncAttempt <XElement> SerializeCore(IRelationType item, SyncSerializerOptions options)
        {
            var node = this.InitializeBaseNode(item, item.Alias);

            var isDependency = false;

            if (item is IRelationTypeWithIsDependency dependencyItem)
            {
                isDependency = dependencyItem.IsDependency;
            }

            node.Add(new XElement("Info",
                                  new XElement("Name", item.Name),
                                  new XElement("ParentType", GetGuidValue(item, nameof(item.ParentObjectType))),
                                  new XElement("ChildType", GetGuidValue(item, nameof(item.ChildObjectType))),
                                  new XElement("Bidirectional", item.IsBidirectional),
                                  new XElement("IsDependency", isDependency)));


            if (options.GetSetting <bool>("IncludeRelations", false))
            {
                node.Add(SerializeRelations(item));
            }

            return(SyncAttempt <XElement> .SucceedIf(
                       node != null,
                       item.Name,
                       node,
                       typeof(IRelationType),
                       ChangeType.Export));
        }
예제 #4
0
        /// <summary>
        ///  Checks the config to see if we should be deserializing the config element of a data type.
        /// </summary>
        /// <remarks>
        ///   a key value on the handler will allow users to add editorAliases that they don't want the
        ///   config importing for.
        ///   e.g - to not import all the colour picker values.
        ///   <code>
        ///      <Add Key="NoConfigEditors" Value="Umbraco.ColorPicker" />
        ///   </code>
        ///
        ///   To ignore just specific colour pickers (so still import config for other colour pickers)
        ///   <code>
        ///     <Add Key="NoConfigNames" Value="Approved Colour,My Colour Picker" />
        ///   </code>
        /// </remarks>
        private bool ShouldDeserilizeConfig(string itemName, string editorAlias, SyncSerializerOptions options)
        {
            var noConfigEditors = options.GetSetting("NoConfigEditors", string.Empty);

            if (!string.IsNullOrWhiteSpace(noConfigEditors) && noConfigEditors.InvariantContains(editorAlias))
            {
                return(false);
            }

            var noConfigAliases = options.GetSetting("NoConfigNames", string.Empty);

            if (!string.IsNullOrWhiteSpace(noConfigAliases) && noConfigAliases.InvariantContains(itemName))
            {
                return(false);
            }

            return(true);
        }
예제 #5
0
        protected override SyncAttempt <IDictionaryItem> DeserializeCore(XElement node, SyncSerializerOptions options)
        {
            var item = FindItem(node);

            var info  = node.Element("Info");
            var alias = node.GetAlias();

            var details = new List <uSyncChange>();

            Guid?parentKey     = null;
            var  parentItemKey = info.Element("Parent").ValueOrDefault(string.Empty);

            if (parentItemKey != string.Empty)
            {
                var parent = localizationService.GetDictionaryItemByKey(parentItemKey);
                if (parent != null)
                {
                    parentKey = parent.Key;
                }
            }

            var key = node.GetKey();

            if (item == null)
            {
                item     = new DictionaryItem(parentKey, alias);
                item.Key = key;
            }
            else
            {
                item.ParentId = parentKey;
            }

            if (item.ItemKey != alias)
            {
                details.AddUpdate("ItemKey", item.ItemKey, alias);
                item.ItemKey = alias;
            }

            if (item.Key != key)
            {
                details.AddUpdate("Key", item.Key, key);
                item.Key = key;
            }

            // key only translationm, would not add the translation values.
            if (!options.GetSetting("KeysOnly", false))
            {
                details.AddRange(DeserializeTranslations(item, node));
            }

            // this.SaveItem(item);


            return(SyncAttempt <IDictionaryItem> .Succeed(item.ItemKey, item, ChangeType.Import, details));
        }
예제 #6
0
        protected override SyncAttempt <XElement> SerializeCore(ITemplate item, SyncSerializerOptions options)
        {
            var node = this.InitializeBaseNode(item, item.Alias, this.CalculateLevel(item));

            node.Add(new XElement("Name", item.Name));
            node.Add(new XElement("Parent", item.MasterTemplateAlias));

            if (options.GetSetting(uSyncConstants.Conventions.IncludeContent, false))
            {
                node.Add(SerializeContent(item));
            }

            return(SyncAttempt <XElement> .Succeed(item.Name, node, typeof(ITemplate), ChangeType.Export));
        }
예제 #7
0
        public override SyncAttempt <ITemplate> DeserializeSecondPass(ITemplate item, XElement node, SyncSerializerOptions options)
        {
            var details = new List <uSyncChange>();
            var saved   = false;
            var msg     = "";

            var master = node.Element("Parent").ValueOrDefault(string.Empty);

            if (master != string.Empty && item.MasterTemplateAlias != master)
            {
                logger.LogDebug("Looking for master {0}", master);
                var masterItem = fileService.GetTemplate(master);
                if (masterItem != null && item.MasterTemplateAlias != master)
                {
                    details.AddUpdate("Parent", item.MasterTemplateAlias, master);

                    logger.LogDebug("Setting Master {0}", masterItem.Alias);
                    item.SetMasterTemplate(masterItem);

                    SaveItem(item);
                    saved = true;
                }
            }

            if (options.GetSetting("UsingRazorViews", false))
            {
                // using razor views - we delete the template file at the end (because its in a razor view).
                var templatePath = ViewPath(item.Alias);
                if (_viewFileSystem.FileExists(templatePath))
                {
                    var fullPath = _viewFileSystem.GetFullPath(templatePath);

                    if (System.IO.File.Exists(fullPath))
                    {
                        var content = System.IO.File.ReadAllText(fullPath);
                        if (content.Contains($"[uSyncMarker:{this.Id}]"))
                        {
                            logger.LogDebug($"Removing the file from disk, because it exists in a razor view {templatePath}");
                            msg = "Using Razor views";
                            _viewFileSystem.DeleteFile(templatePath);

                            // we have to tell the handlers we saved it - or they will and write the file back
                            return(SyncAttempt <ITemplate> .Succeed(item.Name, item, ChangeType.Import, "Razor view removed", true, details));
                        }
                    }
                }
            }

            return(SyncAttempt <ITemplate> .Succeed(item.Name, item, ChangeType.Import, msg, saved, details));
        }
예제 #8
0
        protected override SyncAttempt <XElement> SerializeCore(IDictionaryItem item, SyncSerializerOptions options)
        {
            var node = InitializeBaseNode(item, item.ItemKey, GetLevel(item));

            // if we are serializing by culture, then add the culture attribute here.
            var cultures = options.GetSetting(uSyncConstants.CultureKey, string.Empty);

            if (!string.IsNullOrWhiteSpace(cultures))
            {
                node.Add(new XAttribute(uSyncConstants.CultureKey, cultures));
            }

            var info = new XElement("Info");

            if (item.ParentId.HasValue)
            {
                var parent = FindItem(item.ParentId.Value);
                if (parent != null)
                {
                    info.Add(new XElement("Parent", parent.ItemKey));
                }
            }

            var activeCultures = options.GetCultures();

            var translationsNode = new XElement("Translations");

            foreach (var translation in item.Translations
                     .SafeDistinctBy(x => x.Language.IsoCode)
                     .OrderBy(x => x.Language.IsoCode))
            {
                if (activeCultures.IsValid(translation.Language.IsoCode))
                {
                    translationsNode.Add(new XElement("Translation", translation.Value,
                                                      new XAttribute("Language", translation.Language.IsoCode)));
                }
            }

            node.Add(info);
            node.Add(translationsNode);

            return(SyncAttempt <XElement> .Succeed(
                       item.ItemKey, node, typeof(IDictionaryItem), ChangeType.Export));
        }
예제 #9
0
        protected override SyncAttempt <XElement> SerializeCore(IRelationType item, SyncSerializerOptions options)
        {
            var node = this.InitializeBaseNode(item, item.Alias);

            node.Add(new XElement("Info",
                                  new XElement("Name", item.Name),
                                  new XElement("ParentType", item.ParentObjectType),
                                  new XElement("ChildType", item.ChildObjectType),
                                  new XElement("Bidirectional", item.IsBidirectional)));

            if (options.GetSetting <bool>("IncludeRelations", true))
            {
                node.Add(SerializeRelations(item));
            }

            return(SyncAttempt <XElement> .SucceedIf(
                       node != null,
                       item.Name,
                       node,
                       typeof(IRelationType),
                       ChangeType.Export));
        }
예제 #10
0
        protected override SyncAttempt <XElement> SerializeCore(IMedia item, SyncSerializerOptions options)
        {
            var node = InitializeNode(item, item.ContentType.Alias, options);

            var info       = SerializeInfo(item, options);
            var properties = SerializeProperties(item, options);

            node.Add(info);
            node.Add(properties);

            // serializing the file hash, will mean if the image changes, then the media item will
            // trigger as a change - this doesn't mean the image will be updated other methods are
            // used to copy media between servers (uSync.Complete)
            if (options.GetSetting("IncludeFileHash", true))
            {
                info.Add(SerializeFileHash(item));
            }

            return(SyncAttempt <XElement> .Succeed(
                       item.Name,
                       node,
                       typeof(IMedia),
                       ChangeType.Export));
        }
예제 #11
0
        protected override SyncAttempt <IRelationType> DeserializeCore(XElement node, SyncSerializerOptions options)
        {
            var key   = node.GetKey();
            var alias = node.GetAlias();

            var info = node.Element("Info");

            var name          = info.Element("Name").ValueOrDefault(string.Empty);
            var parentType    = info.Element("ParentType").ValueOrDefault(Guid.Empty);
            var childType     = info.Element("ChildType").ValueOrDefault(Guid.Empty);
            var bidirectional = info.Element("Bidirectional").ValueOrDefault(false);

            var item = FindItem(node);

            if (item == null)
            {
                item = new RelationType(childType, parentType, alias);
            }

            var details = new List <uSyncChange>();

            if (item.Key != key)
            {
                details.AddUpdate("Key", item.Key, key);
                item.Key = key;
            }

            if (item.Name != name)
            {
                details.AddUpdate("Name", item.Name, name);
                item.Name = name;
            }

            if (item.Alias != alias)
            {
                details.AddUpdate("Alias", item.Alias, alias);
                item.Alias = alias;
            }

            if (item.ParentObjectType != parentType)
            {
                details.AddUpdate("ParentType", item.ParentObjectType, parentType);
                item.ParentObjectType = parentType;
            }

            if (item.ChildObjectType != childType)
            {
                details.AddUpdate("ChildType", item.ChildObjectType, childType);
                item.ChildObjectType = childType;
            }

            if (item.IsBidirectional = bidirectional)
            {
                details.AddUpdate("Bidirectional", item.IsBidirectional, bidirectional);
                item.IsBidirectional = bidirectional;
            }

            var hasBeenSaved = false;

            if (options.GetSetting <bool>("IncludeRelations", true))
            {
                // we have to save before we can add the relations.
                this.SaveItem(item);
                hasBeenSaved = true;
                details.AddRange(DeserializeRelations(node, item));
            }

            return(SyncAttempt <IRelationType> .Succeed(item.Name, item, ChangeType.Import, hasBeenSaved, details));
        }
예제 #12
0
        protected override SyncAttempt <ITemplate> DeserializeCore(XElement node, SyncSerializerOptions options)
        {
            var key   = node.GetKey();
            var alias = node.GetAlias();

            var name = node.Element("Name").ValueOrDefault(string.Empty);
            var item = default(ITemplate);

            var details = new List <uSyncChange>();

            if (key != Guid.Empty)
            {
                item = fileService.GetTemplate(key);
            }

            if (item == null)
            {
                item = fileService.GetTemplate(alias);
            }

            if (item == null)
            {
                item = new Template(shortStringHelper, name, alias);
                details.AddNew(alias, alias, "Template");

                if (ShouldGetContentFromNode(node, options))
                {
                    logger.LogDebug("Getting content for Template from XML");
                    item.Content = GetContentFromConfig(node);
                }
                else
                {
                    logger.LogDebug("Loading template content from disk");

                    var templatePath = ViewPath(alias);
                    if (_viewFileSystem.FileExists(templatePath))
                    {
                        logger.LogDebug("Reading {0} contents", templatePath);
                        item.Content = GetContentFromFile(templatePath);
                        item.Path    = templatePath;
                    }
                    else
                    {
                        if (!options.GetSetting <bool>("UsingRazorViews", false))
                        {
                            // template is missing
                            // we can't create
                            logger.LogWarning("Failed to create template {path} the local file is missing", templatePath);
                            return(SyncAttempt <ITemplate> .Fail(name, ChangeType.Import, $"The template {templatePath} file is missing."));
                        }
                        else
                        {
                            // template is not on disk, we could use the viewEngine to find the view
                            // if this finds the view it tells us that the view is somewhere else ?

                            logger.LogDebug("Failed to find content, but UsingRazorViews so will create anyway, then delete the file");
                            item.Content = $"<!-- [uSyncMarker:{this.Id}]  template content - will be removed -->";
                        }
                    }
                }
            }

            if (item == null)
            {
                // creating went wrong
                logger.LogWarning("Failed to create template");
                return(SyncAttempt <ITemplate> .Fail(name, ChangeType.Import, "Failed to create template"));
            }

            if (item.Key != key)
            {
                details.AddUpdate("Key", item.Key, key);
                item.Key = key;
            }

            if (item.Name != name)
            {
                details.AddUpdate("Name", item.Name, name);
                item.Name = name;
            }

            if (item.Alias != alias)
            {
                details.AddUpdate("Alias", item.Alias, alias);
                item.Alias = alias;
            }

            if (ShouldGetContentFromNode(node, options))
            {
                var content = GetContentFromConfig(node);
                if (content != item.Content)
                {
                    details.AddUpdate("Content", item.Content, content);
                    item.Content = content;
                }
            }

            //var master = node.Element("Parent").ValueOrDefault(string.Empty);
            //if (master != string.Empty)
            //{
            //    var masterItem = fileService.GetTemplate(master);
            //    if (masterItem != null)
            //        item.SetMasterTemplate(masterItem);
            //}

            // Deserialize now takes care of the save.
            // fileService.SaveTemplate(item);

            return(SyncAttempt <ITemplate> .Succeed(item.Name, item, ChangeType.Import, details));
        }
예제 #13
0
        protected virtual Attempt <string> DoSaveOrPublish(IContent item, XElement node, SyncSerializerOptions options)
        {
            if (options.GetSetting(uSyncConstants.DefaultSettings.OnlyPublishDirty, uSyncConstants.DefaultSettings.OnlyPublishDirty_Default) && !item.IsDirty())
            {
                logger.LogDebug("{name} not publishing because nothing is dirty [{dirty} {userDirty}]", item.Name, item.IsDirty(), item.IsAnyUserPropertyDirty());
                return(Attempt.Succeed("No Changes"));
            }

            var publishedNode = node.Element("Info")?.Element("Published");

            if (!item.Trashed && publishedNode != null)
            {
                var schedules = GetSchedules(node.Element("Info")?.Element("Schedule"));

                if (publishedNode.HasElements)
                {
                    // culture based publishing.
                    var cultures = options.GetDeserializedCultures(node);

                    // Only unpublish other cultures, when we are not already filtered by cultures
                    // this stops things we don't care about this time being unpublished.
                    var unpublishMissingCultures = cultures.Count == 0;

                    var cultureStatuses = new Dictionary <string, uSyncContentState>();

                    foreach (var culturePublish in publishedNode.Elements("Published"))
                    {
                        var culture = culturePublish.Attribute("Culture").ValueOrDefault(string.Empty);

                        if (!string.IsNullOrWhiteSpace(culture) && cultures.IsValid(culture))
                        {
                            // is the item published in the config file
                            var configState = culturePublish.ValueOrDefault(false)
                                ? uSyncContentState.Published
                                : uSyncContentState.Unpublished;

                            // pending or outstanding scheduled actions can change the action we take.
                            cultureStatuses[culture] =
                                schedules.CalculateCultureState(culture, configState);
                        }
                    }

                    if (cultureStatuses.Count > 0)
                    {
                        return(PublishItem(item, cultureStatuses, unpublishMissingCultures));
                    }
                }
                else
                {
                    var state = publishedNode.Attribute("Default").ValueOrDefault(false)
                        ? uSyncContentState.Published
                        : uSyncContentState.Unpublished;

                    state = schedules.CalculateCultureState(string.Empty, state);

                    if (state == uSyncContentState.Published)
                    {
                        return(PublishItem(item));
                    }
                    else if (state == uSyncContentState.Unpublished && item.Published == true)
                    {
                        contentService.Unpublish(item);
                    }
                }
            }

            this.SaveItem(item);
            return(Attempt.Succeed("Saved"));
        }
예제 #14
0
        protected override SyncAttempt <IContent> DeserializeCore(XElement node, SyncSerializerOptions options)
        {
            var attempt = FindOrCreate(node);

            if (!attempt.Success)
            {
                throw attempt.Exception;
            }

            var item = attempt.Result;

            var details = new List <uSyncChange>();

            details.AddRange(DeserializeBase(item, node, options));

            if (node.Element("Info") != null)
            {
                var trashed = node.Element("Info").Element("Trashed").ValueOrDefault(false);
                details.AddNotNull(HandleTrashedState(item, trashed));
            }

            details.AddNotNull(DeserializeTemplate(item, node));

            var propertiesAttempt = DeserializeProperties(item, node, options);

            if (!propertiesAttempt.Success)
            {
                return(SyncAttempt <IContent> .Fail(item.Name, item, ChangeType.ImportFail, "Failed to deserialize properties", attempt.Exception));
            }

            details.AddRange(propertiesAttempt.Result);

            // sort order
            var sortOrder = node.Element("Info").Element("SortOrder").ValueOrDefault(-1);

            details.AddNotNull(HandleSortOrder(item, sortOrder));

            var publishTimer = Stopwatch.StartNew();


            if (details.HasWarning() && options.FailOnWarnings())
            {
                // Fail on warning. means we don't save or publish because something is wrong ?
                return(SyncAttempt <IContent> .Fail(item.Name, item, ChangeType.ImportFail, "Failed with warnings", details,
                                                    new Exception("Import failed because of warnings, and fail on warnings is true")));
            }

            // published status
            // this does the last save and publish
            var saveAttempt = DoSaveOrPublish(item, node, options);

            if (saveAttempt.Success)
            {
                var message = saveAttempt.Result;

                if (details.Any(x => x.Change == ChangeDetailType.Warning))
                {
                    message += $" with warning(s)";
                }

                if (publishTimer.ElapsedMilliseconds > 10000)
                {
                    message += $" (Slow publish {publishTimer.ElapsedMilliseconds}ms)";
                }

                var changeType = options.GetSetting(uSyncConstants.DefaultSettings.OnlyPublishDirty, uSyncConstants.DefaultSettings.OnlyPublishDirty_Default) && !item.IsDirty()
                    ? ChangeType.NoChange : ChangeType.Import;

                // we say no change back, this stops the core second pass function from saving
                // this item (which we have just done with DoSaveOrPublish)
                return(SyncAttempt <IContent> .Succeed(item.Name, item, changeType, message, true, details));
            }
            else
            {
                return(SyncAttempt <IContent> .Fail(item.Name, item, ChangeType.ImportFail, saveAttempt.Result, saveAttempt.Exception));
            }
        }
예제 #15
0
        /// <summary>
        ///  serialize all the properties for the item
        /// </summary>
        protected virtual XElement SerializeProperties(TObject item, SyncSerializerOptions options)
        {
            var cultures        = options.GetCultures();
            var segments        = options.GetSegments();
            var includeDefaults = (cultures.Count == 0 && segments.Count == 0) ||
                                  options.GetSetting(uSyncConstants.DefaultsKey, false);

            var node = new XElement("Properties");

            foreach (var property in item.Properties
                     .Where(x => !dontSerialize.InvariantContains(x.Alias))
                     .OrderBy(x => x.Alias))
            {
                var propertyNode = new XElement(property.Alias);

                // this can cause us false change readings
                // but we need to preserve the values if they are blank
                // because we have to be able to set them to blank on deserialization
                foreach (var value in property.Values)
                {
                    var valueNode = new XElement("Value");

                    // valid if there is no culture, or segment and
                    // we are includeing default values
                    var validNode = string.IsNullOrWhiteSpace(value.Culture) &&
                                    string.IsNullOrWhiteSpace(value.Segment) &&
                                    includeDefaults;


                    // or b) it is a valid culture/segment.
                    if (!string.IsNullOrWhiteSpace(value.Culture) && cultures.IsValid(value.Culture))
                    {
                        valueNode.Add(new XAttribute("Culture", value.Culture ?? string.Empty));
                        validNode = true;
                    }


                    if (!string.IsNullOrWhiteSpace(value.Segment) && segments.IsValid(value.Segment))
                    {
                        valueNode.Add(new XAttribute("Segment", value.Segment ?? string.Empty));
                        validNode = true;
                    }

                    if (validNode)
                    {
                        valueNode.Add(new XCData(GetExportValue(GetPropertyValue(value), property.PropertyType, value.Culture, value.Segment)));
                        propertyNode.Add(valueNode);
                    }
                }

                if (property.Values == null || property.Values.Count == 0 && includeDefaults)
                {
                    // add a blank one, for change clarity
                    // we do it like this because then it doesn't get collapsed in the XML serialization
                    var emptyValue = new XElement("Value");
                    emptyValue.Add(new XCData(string.Empty));

                    propertyNode.Add(emptyValue);
                }

                if (propertyNode.HasElements)
                {
                    node.Add(propertyNode);
                }
            }

            return(node);
        }
예제 #16
0
 /// <summary>
 ///  perform the removal of properties and items.
 /// </summary>
 public static bool DeleteItems(this SyncSerializerOptions options)
 => !options.GetSetting <bool>(uSyncConstants.DefaultSettings.NoRemove, uSyncConstants.DefaultSettings.NoRemove_Default);