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); }
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")); }
private IEnumerable <uSyncChange> DeserializeSchedules(IContent item, XElement node, SyncSerializerOptions options) { logger.LogDebug("Deserialize Schedules"); var changes = new List <uSyncChange>(); var nodeSchedules = new ContentScheduleCollection(); var currentSchedules = contentService.GetContentScheduleByContentId(item.Id); 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.LogDebug("Adding {action} {culture} {date}", importSchedule.Action, importSchedule.Culture, importSchedule.Date); nodeSchedules.Add(importSchedule); var existing = FindSchedule(currentSchedules, importSchedule); if (existing != null) { currentSchedules.Remove(existing); } currentSchedules.Add(importSchedule); changes.Add(uSyncChange.Update("Schedule", $"{importSchedule.Culture} {importSchedule.Action}", "", importSchedule.Date.ToString())); } } } if (currentSchedules != null) { // remove things that are in the current but not the import. var toRemove = currentSchedules.FullSchedule.Where(x => FindSchedule(nodeSchedules, x) == null); foreach (var oldItem in toRemove) { if (cultures.IsValidOrBlank(oldItem.Culture)) { logger.LogDebug("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. currentSchedules.Remove(oldItem); changes.Add(uSyncChange.Delete("Schedule", $"{oldItem.Culture} - {oldItem.Action}", oldItem.Date.ToString())); } } if (changes.Any()) { contentService.PersistContentSchedule(item, currentSchedules); return(changes); } return(Enumerable.Empty <uSyncChange>()); } return(Enumerable.Empty <uSyncChange>()); }
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 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); // TODO: I think this is the wrong way around? 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")); }
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); }