Skip to content

Commit

Permalink
Merge changes from release branch before release beta4.
Browse files Browse the repository at this point in the history
  • Loading branch information
tusmester committed Jul 21, 2017
1 parent b1f8759 commit aa31792
Show file tree
Hide file tree
Showing 27 changed files with 1,078 additions and 32 deletions.
64 changes: 64 additions & 0 deletions docs/snadmin-builtin-steps.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,70 @@ If the “import” directory contains a content “MyContent”, after the exec
### ImportSchema
>This step is deprecated, use the more generic **Import** step to import all kinds of content, even content types to the repository.
### SetField
- Full name: `SenseNet.Packaging.Steps.SetField`
- Default property: `Value`
- Additional properties: `Content, Name, Fields, Overwrite`

> This step can be placed in ForEach steps' Block sections.
Sets one or more field values on the provided content. By default the field values will be overwritten unconditionally, but if you set the *overwrite* property to false, fields that already contain a value will be skipped.

```xml
<SetField name="Description" content="/Root/MyContent"><![CDATA[New description]]></SetField>

<SetField name="IncomingEmailWorkflow" content="/Root/ContentTemplates/DocumentLibrary/Document_Library" overwrite="@overwrite">
<Value>
<Path>/Root/System/Schema/ContentTypes/GenericContent/Workflow/MailProcessorWorkflow</Path>
</Value>
</SetField>

<SetField content="/Root/ContentTemplates/EventList/Calendar" overwrite="@overwrite">
<Fields>
<Field name="IncomingEmailWorkflow">
<Value>
<Path>/Root/System/Schema/ContentTypes/GenericContent/Workflow/MailProcessorWorkflow</Path>
</Value>
</Field>
</Fields>
</SetField>
```

### AddReference
- Full name: `SenseNet.Packaging.Steps.AddReference`
- Default property: -
- Additional properties: `Content, Name, Value, Fields`

> This step can be placed in ForEach steps' Block sections.
Adds one or more content as a reference to a reference field. Previous list is preserved, this is an addition. Both path and id work.

```xml
<AddReference name="Members" content="/Root/IMS/BuiltIn/Portal/HR">
<Value>
<Path>/Root/IMS/BuiltIn/johnsmiths</Path>
<Id>12345</Id>
</Value>
</AddReference>
```

### RemoveReference
- Full name: `SenseNet.Packaging.Steps.RemoveReference`
- Default property: -
- Additional properties: `Content, Name, Value, Fields`

> This step can be placed in ForEach steps' Block sections.
Removes one or more content from a reference field. All other referenced values remain untouched. Both path and id work.

```xml
<RemoveReference name="Members" content="/Root/IMS/BuiltIn/Portal/HR">
<Value>
<Path>/Root/IMS/BuiltIn/johnsmiths</Path>
</Value>
</RemoveReference>
```

### Rename
- Full name: `SenseNet.Packaging.Steps.Rename`
- Default property: `NewName`
Expand Down
5 changes: 1 addition & 4 deletions src/Configuration/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
#if DEBUG
[assembly: AssemblyTitle("SenseNet.Configuration (Debug)")]
#else
Expand All @@ -19,7 +16,7 @@
[assembly: AssemblyCulture("")]
[assembly: AssemblyVersion("7.0.0.0")]
[assembly: AssemblyFileVersion("7.0.0.0")]
[assembly: AssemblyInformationalVersion("7.0.0-beta3")]
[assembly: AssemblyInformationalVersion("7.0.0-beta4")]

[assembly: ComVisible(false)]
[assembly: Guid("dfbdb163-d9bb-481c-b3fd-e9eb0e37d27d")]
Expand Down
3 changes: 3 additions & 0 deletions src/ContentRepository/ContentRepository.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@
<Compile Include="Packaging\SR.cs" />
<Compile Include="Packaging\Steps\AddField.cs" />
<Compile Include="Packaging\Steps\AddMembers.cs" />
<Compile Include="Packaging\Steps\RemoveReference.cs" />
<Compile Include="Packaging\Steps\AddReference.cs" />
<Compile Include="Packaging\Steps\AddResource.cs" />
<Compile Include="Packaging\Steps\IfComponentExists.cs" />
<Compile Include="Packaging\Steps\IfMatch.cs" />
Expand Down Expand Up @@ -223,6 +225,7 @@
<Compile Include="Packaging\Steps\PopulateIndex.cs" />
<Compile Include="Packaging\Steps\Rename.cs" />
<Compile Include="Packaging\Steps\ReplaceText.cs" />
<Compile Include="Packaging\Steps\SetField.cs" />
<Compile Include="Packaging\Steps\SetPermissions.cs" />
<Compile Include="Packaging\Steps\StartRepository.cs" />
<Compile Include="Packaging\Steps\Step.cs" />
Expand Down
14 changes: 14 additions & 0 deletions src/ContentRepository/Fields/ReferenceField.cs
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,20 @@ protected override bool ParseValue(string value)

}

public override bool HasValue()
{
var originalValue = OriginalValue;
if (originalValue == null)
return false;

var node = originalValue as Node;
if (node != null)
return true;

var nodes = originalValue as IEnumerable;
return nodes != null && nodes.Cast<Node>().Any();
}

/*======================================================= IXmlChildList Members ====*/

public string GetXmlChildName()
Expand Down
45 changes: 45 additions & 0 deletions src/ContentRepository/Packaging/Steps/AddReference.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using SenseNet.ContentRepository;
using SenseNet.ContentRepository.Fields;
using SenseNet.ContentRepository.Storage;

namespace SenseNet.Packaging.Steps
{
public class AddReference : SetField
{
public override void Execute(ExecutionContext context)
{
context.AssertRepositoryStarted();

Content content;
Dictionary<string, string> fieldValues;
bool overwrite;

ParseParameters(context, out content, out fieldValues, out overwrite);

Logger.LogMessage($"Updating: {content.Path}");

var xDoc = GetFieldXmlDocument(fieldValues);
var node = content.ContentHandler;

foreach (var fieldName in fieldValues.Keys)
{
var fieldNode = xDoc.DocumentElement.SelectSingleNode($"//{fieldName}");

if (!(content.Fields[fieldName] is ReferenceField))
throw new InvalidStepParameterException($"{fieldName} is not a reference field.");

var references = fieldNode.ChildNodes.Cast<XmlNode>()
.Select(x => Node.LoadNodeByIdOrPath(x.InnerText.Trim())).Where(n => n != null);

node.AddReferences(fieldName, references);
}

// wrap the node into a content just to make saving the same version easier
var editedContent = ContentRepository.Content.Create(node);
editedContent.SaveSameVersion();
}
}
}
48 changes: 48 additions & 0 deletions src/ContentRepository/Packaging/Steps/RemoveReference.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using SenseNet.ContentRepository;
using SenseNet.ContentRepository.Fields;
using SenseNet.ContentRepository.Storage;

namespace SenseNet.Packaging.Steps
{
public class RemoveReference : SetField
{
public override void Execute(ExecutionContext context)
{
context.AssertRepositoryStarted();

Content content;
Dictionary<string, string> fieldValues;
bool overwrite;

ParseParameters(context, out content, out fieldValues, out overwrite);

Logger.LogMessage($"Updating: {content.Path}");

var xDoc = GetFieldXmlDocument(fieldValues);
var node = content.ContentHandler;

foreach (var fieldName in fieldValues.Keys)
{
var fieldNode = xDoc.DocumentElement.SelectSingleNode($"//{fieldName}");

if (!(content.Fields[fieldName] is ReferenceField))
throw new InvalidStepParameterException($"{fieldName} is not a reference field.");

var references = fieldNode.ChildNodes.Cast<XmlNode>()
.Select(x => Node.LoadNodeByIdOrPath(x.InnerText.Trim())).Where(n => n != null);

foreach (var reference in references)
{
node.RemoveReference(fieldName, reference);
}
}

// wrap the node into a content just to make saving the same version easier
var editedContent = ContentRepository.Content.Create(node);
editedContent.SaveSameVersion();
}
}
}
170 changes: 170 additions & 0 deletions src/ContentRepository/Packaging/Steps/SetField.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using SenseNet.ContentRepository;
using SenseNet.ContentRepository.Storage;

namespace SenseNet.Packaging.Steps
{
/// <summary>
/// Modifies a value of one or more fields on a content.
/// </summary>
public class SetField : Step
{
[Annotation("Repository path of the content to be edited.")]
public string Content { get; set; }
[Annotation("Name of the field to be set.")]
public string Name { get; set; }

[Annotation("List of field values to be set.")]
public string Fields { get; set; }

[DefaultProperty]
[Annotation("Field value in the same format as in the import .Content files.")]
public string Value { get; set; }

[Annotation("Whether the field should be overwritten if not empty. Default: true")]
public string Overwrite { get; set; }

public override void Execute(ExecutionContext context)
{
context.AssertRepositoryStarted();

Content content;
Dictionary<string, string> fieldValues;
bool overwrite;

ParseParameters(context, out content, out fieldValues, out overwrite);

var xDoc = GetFieldXmlDocument(fieldValues);

// ReSharper disable once PossibleNullReferenceException
var importContext = new ImportContext(xDoc.DocumentElement.ChildNodes, null, false, true, true);
var changed = false;

foreach (var fieldName in fieldValues.Keys)
{
if (!overwrite && content.Fields[fieldName].HasValue())
continue;

var fieldNode = xDoc.DocumentElement.SelectSingleNode($"//{fieldName}");
content.Fields[fieldName].Import(fieldNode, importContext);

changed = true;
}

if (changed)
{
Logger.LogMessage($"Updating: {content.Path}");
content.SaveSameVersion();
}
else
{
Logger.LogMessage($"SKIPPED: {content.Path}");
}
}

protected void ParseParameters(ExecutionContext context,
out Content content,
out Dictionary<string, string> fieldValues,
out bool overwrite)
{
if (string.IsNullOrEmpty(Content))
throw new PackagingException(SR.Errors.InvalidParameters);

var path = context.ResolveVariable(Content) as string;
if (RepositoryPath.IsValidPath(path) != RepositoryPath.PathResult.Correct)
throw new PackagingException(SR.Errors.InvalidParameters);

content = ContentRepository.Content.Load(path);
if (content == null)
throw new PackagingException("Content not found: " + path);

fieldValues = new Dictionary<string, string>();

// either Field or Fields should be filled, but not both
if ((string.IsNullOrEmpty(Name) && string.IsNullOrEmpty(Fields)) ||
(!string.IsNullOrEmpty(Name) && !string.IsNullOrEmpty(Fields)))
throw new PackagingException(SR.Errors.InvalidParameters);

if (!string.IsNullOrEmpty(Name))
{
// simple syntax, single field definition
var fieldName = context.ResolveVariable(Name) as string;
if (string.IsNullOrEmpty(fieldName) || !content.Fields.ContainsKey(fieldName))
throw new PackagingException($"Field '{fieldName}' not found on content {path}");

fieldValues[fieldName] = context.ResolveVariable(Value) as string;
}
else
{
// complex syntax, multiple field values are provided
var xDoc = new XmlDocument();
xDoc.LoadXml($"<Fields>{context.ResolveVariable(Fields) as string}</Fields>");

if (xDoc.DocumentElement != null)
{
foreach (XmlNode fieldNode in xDoc.DocumentElement.ChildNodes)
{
var fieldName = fieldNode?.Attributes?["name"]?.Value;
if (string.IsNullOrEmpty(fieldName))
throw new InvalidStepParameterException("Field name is missing.");

if (!content.Fields.ContainsKey(fieldName))
throw new InvalidStepParameterException(
$"Content {content.Path} does not have a field with the name {fieldName}.");

if (fieldNode.FirstChild == null || fieldNode.ChildNodes.Count > 1)
throw new InvalidStepParameterException("Incorrect field xml definition.");

fieldValues[fieldName] = fieldNode.FirstChild.InnerXml;
}
}
}

overwrite = ParseOverwrite(context);
}

protected bool ParseOverwrite(ExecutionContext context)
{
var overwrite = true;
var overwriteValue = context.ResolveVariable(Overwrite);

if (overwriteValue is bool)
{
overwrite = (bool)overwriteValue;
}
else
{
var overwriteText = overwriteValue as string;

if (!string.IsNullOrEmpty(overwriteText))
{
bool result;
if (bool.TryParse(overwriteText, out result))
overwrite = result;
else
throw new InvalidParameterException("Value could not be converted to bool: " + overwriteText);
}
}

return overwrite;
}

/// <summary>
/// Constructs an xml document from field values in a format that is recognised by the import API.
/// </summary>
protected XmlDocument GetFieldXmlDocument(Dictionary<string, string> fieldValues)
{
// load the values in a fake xml document
var xDoc = new XmlDocument();
xDoc.LoadXml($"<Fields>{string.Join(Environment.NewLine, fieldValues.Select(f => $"<{f.Key}>{f.Value}</{f.Key}>"))}</Fields>");

if (xDoc.DocumentElement == null)
throw new PackagingException("Invalid field value xml.");

return xDoc;
}
}
}
2 changes: 1 addition & 1 deletion src/ContentRepository/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@
[assembly: AssemblyCulture("")]
[assembly: AssemblyVersion("7.0.0.0")]
[assembly: AssemblyFileVersion("7.0.0.0")]
[assembly: AssemblyInformationalVersion("7.0.0-beta3")]
[assembly: AssemblyInformationalVersion("7.0.0-beta4")]
Loading

0 comments on commit aa31792

Please sign in to comment.