protected override SyncAttempt <FormDataSource> DeserializeCore(XElement node, SyncSerializerOptions options) { var item = FindItem(node.GetAlias()); if (item == null) { item = new FormDataSource(); item.Id = node.GetKey(); } var info = node.Element("Info"); if (info != null) { item.Name = info.Element("Name").ValueOrDefault(node.GetAlias()); item.FormDataSourceTypeId = info.Element("FormDataSourceTypeId").ValueOrDefault(Guid.Empty); } var settings = node.Element("Settings").ValueOrDefault(string.Empty); if (!string.IsNullOrWhiteSpace(settings)) { item.Settings = JsonConvert.DeserializeObject <Dictionary <string, string> >(settings); } // SaveItem(item); return(SyncAttempt <FormDataSource> .Succeed(item.Name, item, ChangeType.Import)); }
protected override SyncAttempt <IDataType> DeserializeCore(XElement node, SyncSerializerOptions options) { var info = node.Element("Info"); var name = info.Element("Name").ValueOrDefault(string.Empty); var key = node.GetKey(); var attempt = FindOrCreate(node); if (!attempt.Success) { throw attempt.Exception; } var details = new List <uSyncChange>(); var item = attempt.Result; // basic if (item.Name != name) { details.AddUpdate("Name", item.Name, name, "Name"); item.Name = name; } if (item.Key != key) { details.AddUpdate("Key", item.Key, key, "Key"); item.Key = key; } var editorAlias = info.Element("EditorAlias").ValueOrDefault(string.Empty); if (editorAlias != item.EditorAlias) { // change the editor type..... var newEditor = Current.DataEditors.FirstOrDefault(x => x.Alias.InvariantEquals(editorAlias)); if (newEditor != null) { details.AddUpdate("EditorAlias", item.EditorAlias, editorAlias, "EditorAlias"); item.Editor = newEditor; } } // removing sort order - as its not used on datatypes, // and can change based on minor things (so gives false out of sync results) // item.SortOrder = info.Element("SortOrder").ValueOrDefault(0); var dbType = info.Element("DatabaseType").ValueOrDefault(ValueStorageType.Nvarchar); if (item.DatabaseType != dbType) { details.AddUpdate("DatabaseType", item.DatabaseType, dbType, "DatabaseType"); item.DatabaseType = dbType; } // config if (ShouldDeserilizeConfig(name, editorAlias, options)) { details.AddRange(DeserializeConfiguration(item, node)); } details.AddNotNull(SetFolderFromElement(item, info.Element("Folder"))); return(SyncAttempt <IDataType> .Succeed(item.Name, item, ChangeType.Import, details)); }
public override SyncAttempt <IContent> DeserializeSecondPass(IContent item, XElement node, SyncSerializerOptions options) { var attempt = DeserializeProperties(item, node, options); if (!attempt.Success) { return(SyncAttempt <IContent> .Fail(item.Name, ChangeType.ImportFail, attempt.Exception)); } var changes = attempt.Result; // sort order var sortOrder = node.Element("Info").Element("SortOrder").ValueOrDefault(-1); changes.AddNotNull(HandleSortOrder(item, sortOrder)); var trashed = node.Element("Info").Element("Trashed").ValueOrDefault(false); changes.AddNotNull(HandleTrashedState(item, trashed)); var publishTimer = Stopwatch.StartNew(); // published status // this does the last save and publish var saveAttempt = DoSaveOrPublish(item, node, options); if (saveAttempt.Success) { var message = attempt.Status; if (publishTimer.ElapsedMilliseconds > 10000) { message += $" (Slow publish {publishTimer.ElapsedMilliseconds}ms)"; } // 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.NoChange, message, true, changes)); } return(SyncAttempt <IContent> .Fail(item.Name, item, ChangeType.ImportFail, $"{saveAttempt.Result} {attempt.Status}")); }
protected Attempt <List <uSyncChange>, string> DeserializeProperties(TObject item, XElement node, SyncSerializerOptions options) { string errors = ""; List <uSyncChange> changes = new List <uSyncChange>(); var activeCultures = options.GetDeserializedCultures(node); var properties = node.Element("Properties"); if (properties == null || !properties.HasElements) { return(Attempt.SucceedWithStatus(errors, changes)); // new Exception("No Properties in the content node")); } foreach (var property in properties.Elements()) { var alias = property.Name.LocalName; if (item.HasProperty(alias)) { var current = item.Properties[alias]; logger.Verbose(serializerType, "Derserialize Property {0} {1}", alias, current.PropertyType.PropertyEditorAlias); var values = property.Elements("Value").ToList(); foreach (var value in values) { var culture = value.Attribute("Culture").ValueOrDefault(string.Empty); var segment = value.Attribute("Segment").ValueOrDefault(string.Empty); var propValue = value.ValueOrDefault(string.Empty); logger.Verbose(serializerType, "{item} {Property} Culture {Culture} Segment {Segment}", item.Name, alias, culture, segment); try { if (!string.IsNullOrEmpty(culture) && activeCultures.IsValid(culture)) { // // check the culture is something we should and can be setting. // if (!current.PropertyType.VariesByCulture()) { logger.Debug(serializerType, "Item does not vary by culture - but .config file contains culture"); // if we get here, then things are wrong, so we will try to fix them. // // if the content config thinks it should vary by culture, but the document type doesn't // then we can check if this is default language, and use that to se the value if (!culture.InvariantEquals(localizationService.GetDefaultLanguageIsoCode())) { // this culture is not the default for the site, so don't use it to // set the single language value. logger.Warn(serializerType, "{item} Culture {culture} in file, but is not default so not being used", item.Name, culture); continue; } logger.Warn(serializerType, "{item} Cannot set value on culture {culture} because it is not avalible for this property - value in default language will be used", item.Name, culture); culture = string.Empty; } else if (!item.AvailableCultures.InvariantContains(culture)) { // this culture isn't one of the ones, that can be set on this language. logger.Warn(serializerType, "{item} Culture {culture} is not one of the avalible cultures, so we cannot set this value", item.Name, culture); continue; } } else { // no culture, but we have to check, because if the property now varies by culture, this can have a random no-cultured value in it? if (current.PropertyType.VariesByCulture()) { if (values.Count == 1) { // there is only one value - so we should set the default variant with this for consistancy? culture = localizationService.GetDefaultLanguageIsoCode(); logger.Debug(serializerType, "Property {Alias} contains a single value that has no culture setting default culture {Culture}", alias, culture); } else { logger.Warn(serializerType, "{item} Property {Alias} contains a value that has no culture but this property varies by culture so this value has no effect", item.Name, alias); continue; } } } // get here ... set the value var itemValue = GetImportValue(propValue, current.PropertyType, culture, segment); var currentValue = item.GetValue(alias, culture, segment); if (IsUpdatedValue(currentValue, itemValue)) { changes.AddUpdateJson(alias, currentValue, itemValue, $"Property/{alias}"); item.SetValue(alias, itemValue, string.IsNullOrEmpty(culture) ? null : culture, string.IsNullOrEmpty(segment) ? null : segment); logger.Debug(serializerType, "Property {item} set {alias} value", item.Name, alias); logger.Verbose(serializerType, "{Id} Property [{alias}] : {itemValue}", item.Id, alias, itemValue); } } catch (Exception ex) { // capture here to be less agressive with failure. // if one property fails the rest will still go in. logger.Warn(serializerType, "{item} Failed to set [{alias}] {propValue} Ex: {Exception}", item.Name, alias, propValue, ex.ToString()); errors += $"Failed to set [{alias}] {ex.Message} <br/>"; } } } else { logger.Warn(serializerType, "DeserializeProperties: item {Name} doesn't have property {alias} but its in the xml", item.Name, alias); errors += $"{item.Name} does not container property {alias}"; } } return(Attempt.SucceedWithStatus(errors, changes)); }
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) { // create var templatePath = IOHelper.MapPath(SystemDirectories.MvcViews + "/" + alias.ToSafeFileName() + ".cshtml"); if (System.IO.File.Exists(templatePath)) { logger.Debug <TemplateSerializer>("Reading {0} contents", templatePath); var content = System.IO.File.ReadAllText(templatePath); item = new Template(name, alias); item.Path = templatePath; item.Content = content; details.AddNew(alias, alias, "Template"); } else { // template is missing // we can't create return(SyncAttempt <ITemplate> .Fail(name, ChangeType.Import, "The template '.cshtml' file is missing.")); } } if (item == null) { // creating went wrong 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; } //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)); }
protected override SyncAttempt <IMedia> 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)); } var propertyAttempt = DeserializeProperties(item, node, options); if (!propertyAttempt.Success) { return(SyncAttempt <IMedia> .Fail(item.Name, item, ChangeType.Fail, "Failed to save properties", propertyAttempt.Exception)); } var info = node.Element("Info"); var sortOrder = info.Element("SortOrder").ValueOrDefault(-1); HandleSortOrder(item, sortOrder); if (details.HasWarning() && options.FailOnWarnings()) { // Fail on warning. means we don't save or publish because something is wrong ? return(SyncAttempt <IMedia> .Fail(item.Name, item, ChangeType.ImportFail, "Failed with warnings", details, new Exception("Import failed because of warnings, and fail on warnings is true"))); } var saveAttempt = mediaService.Save(item); if (!saveAttempt.Success) { var errors = saveAttempt.Result?.EventMessages?.FormatMessages() ?? ""; return(SyncAttempt <IMedia> .Fail(item.Name, item, ChangeType.Fail, errors, saveAttempt.Exception)); } // add warning messages if things are missing var message = ""; if (details.Any(x => x.Change == ChangeDetailType.Warning)) { message += $" with warning(s)"; } // setting the saved flag on the attempt to true, stops base classes from saving the item. return(SyncAttempt <IMedia> .Succeed(item.Name, item, ChangeType.Import, "", true, propertyAttempt.Result)); }
protected virtual IEnumerable <uSyncChange> DeserializeBase(TObject item, XElement node, SyncSerializerOptions options) { var info = node?.Element("Info"); if (info == null) { return(Enumerable.Empty <uSyncChange>()); } var changes = new List <uSyncChange>(); var parentId = -1; var nodeLevel = CalculateNodeLevel(item, default(TObject)); var nodePath = CalculateNodePath(item, default(TObject)); var parentNode = info.Element("Parent"); if (parentNode != null) { var parent = FindParent(parentNode, false); if (parent == null) { var friendlyPath = info.Element("Path").ValueOrDefault(string.Empty); if (!string.IsNullOrWhiteSpace(friendlyPath)) { logger.Debug(serializerType, "Find Parent failed, will search by path {FriendlyPath}", friendlyPath); parent = FindParentByPath(friendlyPath); } } if (parent != null) { parentId = parent.Id; nodePath = CalculateNodePath(item, parent); nodeLevel = CalculateNodeLevel(item, parent); } else { logger.Debug(serializerType, "Unable to find parent but parent node is set in config"); } } if (item.ParentId != parentId) { changes.AddUpdate("Parent", item.ParentId, parentId); logger.Verbose(serializerType, "{Id} Setting Parent {ParentId}", item.Id, parentId); item.ParentId = parentId; } // the following are calculated (not in the file // because they might change without this node being saved). if (item.Path != nodePath) { changes.AddUpdate("Path", item.Path, nodePath); logger.Debug(serializerType, "{Id} Setting Path {idPath} was {oldPath}", item.Id, nodePath, item.Path); item.Path = nodePath; } if (item.Level != nodeLevel) { changes.AddUpdate("Level", item.Level, nodeLevel); logger.Debug(serializerType, "{Id} Setting Level to {Level} was {OldLevel}", item.Id, nodeLevel, item.Level); item.Level = nodeLevel; } var key = node.GetKey(); if (key != Guid.Empty && item.Key != key) { changes.AddUpdate("Key", item.Key, key); logger.Verbose(serializerType, "{Id} Setting Key {Key}", item.Id, key); item.Key = key; } var createDate = info.Element("CreateDate").ValueOrDefault(item.CreateDate); if (item.CreateDate != createDate) { changes.AddUpdate("CreateDate", item.CreateDate, createDate); logger.Verbose(serializerType, "{id} Setting CreateDate", item.Id, createDate); item.CreateDate = createDate; } changes.AddRange(DeserializeName(item, node, options)); return(changes); }
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)); }
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, options)); } // this.SaveItem(item); return(SyncAttempt <IDictionaryItem> .Succeed(item.ItemKey, item, ChangeType.Import, details)); }
protected override Attempt <string> DoSaveOrPublish(IContent item, XElement node, SyncSerializerOptions options) { contentService.SaveBlueprint(item); return(Attempt.Succeed <string>("blueprint saved")); }
protected override SyncAttempt <IMacro> DeserializeCore(XElement node, SyncSerializerOptions options) { var details = new List <uSyncChange>(); if (node.Element("Name") == null) { throw new ArgumentNullException("XML missing Name parameter"); } var item = default(IMacro); var key = node.GetKey(); var alias = node.GetAlias(); var name = node.Element("Name").ValueOrDefault(string.Empty); var macroSource = node.Element("MacroSource").ValueOrDefault(string.Empty); // var macroType = node.Element("MacroType").ValueOrDefault(MacroTypes.PartialView); logger.LogDebug("Macro by Key [{0}]", key); item = macroService.GetById(key); if (item == null) { logger.LogDebug("Macro by Alias [{0}]", key); item = macroService.GetByAlias(alias); } if (item == null) { logger.LogDebug("Creating New [{0}]", key); item = new Macro(shortStringHelper, alias, name, macroSource); details.Add(uSyncChange.Create(alias, name, "New Macro")); } 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.MacroSource != macroSource) { details.AddUpdate("MacroSource", item.MacroSource, macroSource); item.MacroSource = macroSource; } //if (item.MacroType != macroType) //{ // details.AddUpdate("MacroType", item.MacroType, macroType); // item.MacroType = macroType; //} var useInEditor = node.Element("UseInEditor").ValueOrDefault(false); var dontRender = node.Element("DontRender").ValueOrDefault(false); var cacheByMember = node.Element("CachedByMember").ValueOrDefault(false); var cacheByPage = node.Element("CachedByPage").ValueOrDefault(false); var cacheDuration = node.Element("CachedDuration").ValueOrDefault(0); if (item.UseInEditor != useInEditor) { details.AddUpdate("UseInEditor", item.UseInEditor, useInEditor); item.UseInEditor = useInEditor; } if (item.DontRender != dontRender) { details.AddUpdate("DontRender", item.DontRender, dontRender); item.DontRender = dontRender; } if (item.CacheByMember != cacheByMember) { details.AddUpdate("CacheByMember", item.CacheByMember, cacheByMember); item.CacheByMember = cacheByMember; } if (item.CacheByPage != cacheByPage) { details.AddUpdate("CacheByPage", item.CacheByPage, cacheByPage); item.CacheByPage = cacheByPage; } if (item.CacheDuration != cacheDuration) { details.AddUpdate("CacheByMember", item.CacheDuration, cacheDuration); item.CacheDuration = cacheDuration; } var properties = node.Element("Properties"); if (properties != null && properties.HasElements) { foreach (var propNode in properties.Elements("Property")) { var propertyAlias = propNode.Element("Alias").ValueOrDefault(string.Empty); var editorAlias = propNode.Element("EditorAlias").ValueOrDefault(string.Empty); var propertyName = propNode.Element("Name").ValueOrDefault(string.Empty); var sortOrder = propNode.Element("SortOrder").ValueOrDefault(0); logger.LogDebug(" > Property {0} {1} {2} {3}", propertyAlias, editorAlias, propertyName, sortOrder); var propPath = $"{alias}: {propertyName}"; if (item.Properties.ContainsKey(propertyAlias)) { logger.LogDebug(" >> Updating {0}", propertyAlias); item.Properties.UpdateProperty(propertyAlias, propertyName, sortOrder, editorAlias); } else { logger.LogDebug(" >> Adding {0}", propertyAlias); details.Add(uSyncChange.Create(propPath, "Property", propertyAlias)); item.Properties.Add(new MacroProperty(propertyAlias, propertyName, sortOrder, editorAlias)); } } } if (options.DeleteItems()) { RemoveOrphanProperties(item, properties); } return(SyncAttempt <IMacro> .Succeed(item.Name, item, ChangeType.Import, details)); }
/// <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);
public IEnumerable <uSyncChange> GetChanges(XElement target, XElement source, SyncSerializerOptions options) { if (serializer.IsEmpty(target)) { return(GetEmptyFileChange(target, source).AsEnumerableOfOne()); } if (!serializer.IsValid(target)) { return(uSyncChange.Error("", "Invalid File", target.Name.LocalName).AsEnumerableOfOne()); } var changeType = GetChangeType(target, source, options); if (changeType == ChangeType.NoChange) { return(uSyncChange.NoChange("", target.GetAlias()).AsEnumerableOfOne()); } return(CalculateDiffrences(target, source)); }
protected IEnumerable <uSyncChange> DeserializeProperties(TObject item, XElement node, SyncSerializerOptions options) { logger.Debug(serializerType, "Deserializing Properties"); var propertiesNode = node?.Element("GenericProperties"); if (propertiesNode == null) { return(Enumerable.Empty <uSyncChange>()); } /// there are something we can't do in the loop, /// so we store them and do them once we've put /// things in. List <string> propertiesToRemove = new List <string>(); Dictionary <string, string> propertiesToMove = new Dictionary <string, string>(); List <uSyncChange> changes = new List <uSyncChange>(); foreach (var propertyNode in propertiesNode.Elements("GenericProperty")) { var alias = propertyNode.Element("Alias").ValueOrDefault(string.Empty); if (string.IsNullOrEmpty(alias)) { continue; } var key = propertyNode.Element("Key").ValueOrDefault(alias.GetHashCode().ToGuid()); var definitionKey = propertyNode.Element("Definition").ValueOrDefault(Guid.Empty); var propertyEditorAlias = propertyNode.Element("Type").ValueOrDefault(string.Empty); logger.Debug(serializerType, " > Property: {0} {1} {2} {3}", alias, key, definitionKey, propertyEditorAlias); bool IsNew = false; var property = GetOrCreateProperty(item, key, alias, definitionKey, propertyEditorAlias, out IsNew); if (property == null) { continue; } if (key != Guid.Empty && property.Key != key) { changes.AddUpdate("Key", property.Key, key, $"{alias}/Key"); property.Key = key; } if (property.Alias != alias) { changes.AddUpdate("Alias", property.Alias, alias, $"{alias}/Alias"); property.Alias = alias; } var name = propertyNode.Element("Name").ValueOrDefault(alias); if (property.Name != name) { changes.AddUpdate("Name", property.Name, name, $"{alias}/Name"); property.Name = name; } var description = propertyNode.Element("Description").ValueOrDefault(string.Empty); if (property.Description != description) { changes.AddUpdate("Description", property.Description, description, $"{alias}/Description"); property.Description = description; } var mandatory = propertyNode.Element("Mandatory").ValueOrDefault(false); if (property.Mandatory != mandatory) { changes.AddUpdate("Mandatory", property.Mandatory, mandatory, $"{alias}/Mandatory"); property.Mandatory = mandatory; } var regEx = propertyNode.Element("Validation").ValueOrDefault(string.Empty); if (property.ValidationRegExp != regEx) { changes.AddUpdate("Validation", property.ValidationRegExp, regEx, $"{alias}/RegEx"); property.ValidationRegExp = propertyNode.Element("Validation").ValueOrDefault(string.Empty); } var sortOrder = propertyNode.Element("SortOrder").ValueOrDefault(0); if (property.SortOrder != sortOrder) { changes.AddUpdate("SortOrder", property.SortOrder, sortOrder, $"{alias}/SortOrder"); property.SortOrder = sortOrder; } // added in v8.6 // reflection is fast but a a quick check of version is faster ! if (UmbracoVersion.LocalVersion.Major > 8 || UmbracoVersion.LocalVersion.Minor >= 6) { changes.AddNotNull(DeserializeNewProperty <string>(property, propertyNode, "MandatoryMessage")); changes.AddNotNull(DeserializeNewProperty <string>(property, propertyNode, "ValidationRegExpMessage")); } if (UmbracoVersion.LocalVersion.Major > 8 || UmbracoVersion.LocalVersion.Minor >= 10) { changes.AddNotNull(DeserializeNewProperty <bool>(property, propertyNode, "LabelOnTop")); } changes.AddRange(DeserializeExtraProperties(item, property, propertyNode)); var tab = propertyNode.Element("Tab").ValueOrDefault(string.Empty); if (IsNew) { changes.AddNew(alias, name, alias); logger.Debug(serializerType, "Property Is new adding to tab."); if (string.IsNullOrWhiteSpace(tab)) { item.AddPropertyType(property); } else { item.AddPropertyType(property, tab); } } else { logger.Debug(serializerType, "Property exists, checking tab location"); // we need to see if this one has moved. if (!string.IsNullOrWhiteSpace(tab)) { var tabGroup = item.PropertyGroups.FirstOrDefault(x => x.Name.InvariantEquals(tab)); if (tabGroup != null) { if (!tabGroup.PropertyTypes.Contains(property.Alias)) { // add to our move list. propertiesToMove[property.Alias] = tab; } } } } } // move things between tabs. changes.AddRange(MoveProperties(item, propertiesToMove)); if (options.DeleteItems()) { // remove what needs to be removed changes.AddRange(RemoveProperties(item, propertiesNode)); } else { logger.Debug(serializerType, "Property Removal disabled by config"); } return(changes); }
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?>(null); var childType = info.Element("ChildType").ValueOrDefault <Guid?>(null); var bidirectional = info.Element("Bidirectional").ValueOrDefault(false); var isDependency = info.Element("IsDependency").ValueOrDefault(true); var item = FindItem(node); if (item == null) { item = CreateRelation(name, alias, bidirectional, parentType, childType, isDependency); } 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; } var currentParentType = GetGuidValue(item, nameof(item.ParentObjectType)); if (currentParentType != parentType) { details.AddUpdate("ParentType", currentParentType, parentType); SetGuidValue(item, nameof(item.ParentObjectType), parentType); } var currentChildType = GetGuidValue(item, nameof(item.ChildObjectType)); if (currentChildType != childType) { details.AddUpdate("ChildType", currentChildType, childType); SetGuidValue(item, nameof(item.ChildObjectType), childType); } if (item.IsBidirectional = bidirectional) { details.AddUpdate("Bidirectional", item.IsBidirectional, bidirectional); item.IsBidirectional = bidirectional; } var hasBeenSaved = false; var message = ""; if (options.GetSetting <bool>("IncludeRelations", false)) { // we have to save before we can add the relations. this.SaveItem(item); hasBeenSaved = true; message = "Relation items included"; details.AddRange(DeserializeRelations(node, item, options)); } return(SyncAttempt <IRelationType> .Succeed(item.Name, item, ChangeType.Import, message, hasBeenSaved, details)); }
private IEnumerable <uSyncChange> DeserializeTranslations(IDictionaryItem item, XElement node, SyncSerializerOptions options) { var translationNode = node?.Element("Translations"); if (translationNode == null) { return(Enumerable.Empty <uSyncChange>()); } var currentTranslations = item.Translations.ToList(); var activeCultures = options.GetDeserializedCultures(node); var changes = new List <uSyncChange>(); foreach (var translation in translationNode.Elements("Translation")) { var language = translation.Attribute("Language").ValueOrDefault(string.Empty); if (language == string.Empty) { continue; } // only deserialize the active cultures passed to us (blank = all) if (!activeCultures.IsValid(language)) { continue; } var itemTranslation = item.Translations.FirstOrDefault(x => x.Language.IsoCode == language); if (itemTranslation != null && itemTranslation.Value != translation.Value) { changes.AddUpdate(language, itemTranslation.Value, translation.Value, $"{item.ItemKey}/{language}"); itemTranslation.Value = translation.Value; } else { var lang = localizationService.GetLanguageByIsoCode(language); if (lang != null) { changes.AddNew(language, translation.Value, $"{item.ItemKey}/{language}"); currentTranslations.Add(new DictionaryTranslation(lang, translation.Value)); } } } var translations = currentTranslations.SafeDistinctBy(x => x.Language.IsoCode).ToList(); // if we are syncing all cultures we do a delete, but when only syncing some, we // don't remove missing cultures from the list. if (activeCultures.Count == 0) { // if the count is wrong, we delete the item (shortly before we save it again). if (item.Translations.Count() > translations.Count) { var existing = FindItem(item.Key); if (existing != null) { DeleteItem(existing); item.Id = 0; // make this a new (so it will be inserted) } } } item.Translations = translations; //.SafeDistinctBy(x => x.Language.IsoCode); return(changes); }
public IEnumerable <uSyncChange> GetChanges <TObject>(XElement node, XElement currentNode, SyncSerializerOptions options) { if (currentNode == null) { return(GetChanges <TObject>(node, options)); } var changes = new List <uSyncChange>(); foreach (var tracker in GetTrackers <TObject>()) { changes.AddRange(tracker.GetChanges(node, currentNode, options)); } return(changes); }
public override SyncAttempt <IMediaType> DeserializeSecondPass(IMediaType item, XElement node, SyncSerializerOptions options) { var details = new List <uSyncChange>(); details.AddRange(DeserializeCompositions(item, node)); details.AddRange(DeserializeStructure(item, node)); if (!options.Flags.HasFlag(SerializerFlags.DoNotSave) && item.IsDirty()) { mediaTypeService.Save(item); } return(SyncAttempt <IMediaType> .Succeed(item.Name, item, ChangeType.Import, details)); }
/// <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); }
private IEnumerable <uSyncChange> DeserializeSchedules(IContent item, XElement node, SyncSerializerOptions options) { var schedules = node.Element("Info")?.Element("Schedule"); if (schedules != null && schedules.HasElements) { var changes = new List <uSyncChange>(); var currentSchedules = item.ContentSchedule.FullSchedule; var nodeSchedules = new List <ContentSchedule>(); foreach (var schedule in schedules.Elements("ContentSchedule")) { var importSchedule = GetContentScheduleFromNode(schedule); logger.Debug <ContentSerializer>("Schedule: {action} {culture} {date}", importSchedule.Action, importSchedule.Culture, importSchedule.Date); if (importSchedule.Date < DateTime.Now) { continue; // don't add schedules in the past } nodeSchedules.Add(importSchedule); var existing = FindSchedule(currentSchedules, importSchedule); if (existing != null) { item.ContentSchedule.Remove(existing); } item.ContentSchedule.Add(importSchedule); } // remove things that are in the current but not the import. var toRemove = currentSchedules.Where(x => FindSchedule(nodeSchedules, x) == null); foreach (var oldItem in toRemove) { item.ContentSchedule.Remove(oldItem); } return(changes); } return(Enumerable.Empty <uSyncChange>()); }
protected IEnumerable <uSyncChange> DeserializeName(TObject item, XElement node, SyncSerializerOptions options) { var nameNode = node.Element("Info")?.Element("NodeName"); if (nameNode == null) { return(Enumerable.Empty <uSyncChange>()); } var updated = false; var changes = new List <uSyncChange>(); var name = nameNode.Attribute("Default").ValueOrDefault(string.Empty); if (name != string.Empty && item.Name != name) { changes.AddUpdate("Name", item.Name, name); updated = true; item.Name = name; } if (nameNode.HasElements) { var activeCultures = options.GetDeserializedCultures(node); foreach (var cultureNode in nameNode.Elements("Name")) { var culture = cultureNode.Attribute("Culture").ValueOrDefault(string.Empty); if (culture == string.Empty) { continue; } if (activeCultures.IsValid(culture)) { var cultureName = cultureNode.ValueOrDefault(string.Empty); var currentCultureName = item.GetCultureName(culture); if (cultureName != string.Empty && cultureName != currentCultureName) { changes.AddUpdate($"Name ({culture})", currentCultureName, cultureName); updated = true; item.SetCultureName(cultureName, culture); } } } } if (updated) { CleanCaches(item.Id); } return(changes); }
public override SyncAttempt <IContentType> DeserializeSecondPass(IContentType item, XElement node, SyncSerializerOptions options) { logger.Debug <ContentTypeSerializer>("Deserialize Second Pass {0}", item.Alias); var details = new List <uSyncChange>(); details.AddRange(DeserializeCompositions(item, node)); details.AddRange(DeserializeStructure(item, node)); if (!options.Flags.HasFlag(SerializerFlags.DoNotSave) && item.IsDirty()) { contentTypeService.Save(item); } CleanFolder(item, node); return(SyncAttempt <IContentType> .Succeed(item.Name, item, ChangeType.Import, details)); }
public override SyncAttempt <ITemplate> DeserializeSecondPass(ITemplate item, XElement node, SyncSerializerOptions options) { var details = new List <uSyncChange>(); var master = node.Element("Parent").ValueOrDefault(string.Empty); if (master != string.Empty && item.MasterTemplateAlias != master) { logger.Debug <TemplateSerializer>("Looking for master {0}", master); var masterItem = fileService.GetTemplate(master); if (masterItem != null && item.MasterTemplateAlias != master) { details.AddUpdate("Parent", item.MasterTemplateAlias, master); logger.Debug <TemplateSerializer>("Setting Master {0}", masterItem.Alias); item.SetMasterTemplate(masterItem); if (!options.Flags.HasFlag(SerializerFlags.DoNotSave)) { SaveItem(item); } } } return(SyncAttempt <ITemplate> .Succeed(item.Name, item, ChangeType.Import, details)); }
public IEnumerable <uSyncChange> GetChanges <TObject>(XElement node, SyncSerializerOptions options) => syncTrackers.GetChanges <TObject>(node, options);
public override SyncAttempt <IMedia> DeserializeSecondPass(IMedia item, XElement node, SyncSerializerOptions options) { var propertyAttempt = DeserializeProperties(item, node, options); if (!propertyAttempt.Success) { return(SyncAttempt <IMedia> .Fail(item.Name, ChangeType.Fail, "Failed to save properties", propertyAttempt.Exception)); } var info = node.Element("Info"); var sortOrder = info.Element("SortOrder").ValueOrDefault(-1); HandleSortOrder(item, sortOrder); var trashed = info.Element("Trashed").ValueOrDefault(false); HandleTrashedState(item, trashed); var attempt = mediaService.Save(item); if (!attempt.Success) { return(SyncAttempt <IMedia> .Fail(item.Name, ChangeType.Fail, "")); } // setting the saved flag on the attempt to true, stops base classes from saving the item. return(SyncAttempt <IMedia> .Succeed(item.Name, item, ChangeType.NoChange, propertyAttempt.Status, true, propertyAttempt.Result)); }
public IEnumerable <uSyncChange> GetChanges <TObject>(XElement node, XElement currentNode, SyncSerializerOptions options) { if (currentNode == null) { return(syncTrackers.GetChanges <TObject>(node, options)); } else { return(syncTrackers.GetChanges <TObject>(node, currentNode, options)); } }
private IEnumerable <uSyncChange> DeserializeSchedules(IContent item, XElement node, SyncSerializerOptions options) { logger.Debug <ContentSerializer>("Deserialize Schedules"); var changes = new List <uSyncChange>(); var nodeSchedules = new List <ContentSchedule>(); var currentSchedules = item.ContentSchedule.FullSchedule; var cultures = options.GetDeserializedCultures(node); var schedules = node.Element("Info")?.Element("Schedule"); if (schedules != null && schedules.HasElements) { foreach (var schedule in schedules.Elements("ContentSchedule")) { var importSchedule = GetContentScheduleFromNode(schedule); if (cultures.IsValidOrBlank(importSchedule.Culture)) { if (importSchedule.Date < DateTime.Now) { continue; // don't add schedules in the past } logger.Debug <ContentSerializer>("Adding {action} {culture} {date}", importSchedule.Action, importSchedule.Culture, importSchedule.Date); nodeSchedules.Add(importSchedule); var existing = FindSchedule(currentSchedules, importSchedule); if (existing != null) { item.ContentSchedule.Remove(existing); } item.ContentSchedule.Add(importSchedule); changes.Add(uSyncChange.Update("Schedule", $"{importSchedule.Culture} {importSchedule.Action}", "", importSchedule.Date.ToString())); } } } if (currentSchedules != null && currentSchedules.Count > 0) { // remove things that are in the current but not the import. var toRemove = currentSchedules.Where(x => FindSchedule(nodeSchedules, x) == null); foreach (var oldItem in toRemove) { if (cultures.IsValidOrBlank(oldItem.Culture)) { logger.Debug <ContentSerializer>("Removing Schedule : {culture} {action} {date}", oldItem.Culture, oldItem.Action, oldItem.Date); // only remove a culture if this seralization included it. // we don't remove things we didn't serialize. item.ContentSchedule.Remove(oldItem); changes.Add(uSyncChange.Delete("Schedule", $"{oldItem.Culture} - {oldItem.Action}", oldItem.Date.ToString())); } } return(changes); } return(Enumerable.Empty <uSyncChange>()); }
/// <summary> /// Deserialize the relations for a relation type. /// </summary> private IEnumerable <uSyncChange> DeserializeRelations(XElement node, IRelationType relationType, SyncSerializerOptions options) { var changes = new List <uSyncChange>(); var existing = relationService .GetAllRelationsByRelationType(relationType.Id) .ToList(); var relations = node.Element("Relations"); // do we do this, or do we remove them all! if (relations == null) { return(Enumerable.Empty <uSyncChange>()); } var newRelations = new List <string>(); foreach (var relationNode in relations.Elements("Relation")) { var parentKey = relationNode.Element("Parent").ValueOrDefault(Guid.Empty); var childKey = relationNode.Element("Child").ValueOrDefault(Guid.Empty); if (parentKey == Guid.Empty || childKey == Guid.Empty) { continue; } var parentItem = entityService.Get(parentKey); var childItem = entityService.Get(childKey); if (parentItem == null || childItem == null) { continue; } if (!existing.Any(x => x.ParentId == parentItem.Id && x.ChildId == childItem.Id)) { // missing from the current list... add it. relationService.Save(new Relation(parentItem.Id, childItem.Id, relationType)); changes.Add(uSyncChange.Create(relationType.Alias, parentItem.Name, childItem.Name)); } newRelations.Add($"{parentItem.Id}_{childItem.Id}"); } if (options.DeleteItems()) { var obsolete = existing.Where(x => !newRelations.Contains($"{x.ParentId}_{x.ChildId}")); foreach (var obsoleteRelation in obsolete) { changes.Add(uSyncChange.Delete(relationType.Alias, obsoleteRelation.ParentId.ToString(), obsoleteRelation.ChildId.ToString())); relationService.Delete(obsoleteRelation); } } return(changes); }
protected virtual Attempt <string> DoSaveOrPublish(IContent item, XElement node, SyncSerializerOptions options) { var publishedNode = node.Element("Info")?.Element("Published"); if (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")); }
protected override SyncAttempt <ILanguage> DeserializeCore(XElement node, SyncSerializerOptions options) { var isoCode = node.Element("IsoCode").ValueOrDefault(string.Empty); logger.Debug <LanguageSerializer>("Derserializing {0}", isoCode); var item = localizationService.GetLanguageByIsoCode(isoCode); var details = new List <uSyncChange>(); if (item == null) { logger.Debug <LanguageSerializer>("Creating New Language: {0}", isoCode); item = new Language(isoCode); details.AddNew(isoCode, isoCode, "Language"); } if (item.IsoCode != isoCode) { details.AddUpdate("IsoCode", item.IsoCode, isoCode); item.IsoCode = isoCode; } try { var culture = CultureInfo.GetCultureInfo(isoCode); if (item.CultureName != culture.DisplayName) { details.AddUpdate("CultureName", item.CultureName, culture.DisplayName); item.CultureName = culture.DisplayName; } } catch { logger.Warn <LanguageSerializer>("Can't set culture name based on IsoCode"); } var mandatory = node.Element("IsMandatory").ValueOrDefault(false); if (item.IsMandatory != mandatory) { details.AddUpdate("IsMandatory", item.IsMandatory, mandatory); item.IsMandatory = mandatory; } var isDefault = node.Element("IsDefault").ValueOrDefault(false); if (item.IsDefault != isDefault) { details.AddUpdate("IsDefault", item.IsDefault, isDefault); item.IsDefault = isDefault; } var fallbackId = GetFallbackLanguageId(item, node); if (fallbackId > 0 && item.FallbackLanguageId != fallbackId) { details.AddUpdate("FallbackId", item.FallbackLanguageId, fallbackId); item.FallbackLanguageId = fallbackId; } // logger.Debug<ILanguage>("Saving Language"); //localizationService.Save(item); return(SyncAttempt <ILanguage> .Succeed(item.CultureName, item, ChangeType.Import, details)); }