1
+ using System ;
2
+ using System . Collections . Generic ;
3
+ using System . Linq ;
4
+ using System . Xml . Linq ;
5
+ using Newtonsoft . Json ;
6
+ using Newtonsoft . Json . Linq ;
7
+ using Umbraco . Core ;
8
+ using Umbraco . Core . Deploy ;
9
+ using Umbraco . Core . Models ;
10
+ using Umbraco . Core . Services ;
11
+
12
+ namespace Umbraco . Deploy . Contrib . Connectors . ValueConnectors
13
+ {
14
+ /// <summary>
15
+ /// A Deploy connector for the nuPickers property editor, when used with Umbraco content & media.
16
+ /// </summary>
17
+ public class NuPickersValueConnector : IValueConnector
18
+ {
19
+ private readonly IEntityService _entityService ;
20
+
21
+ private enum SaveFormat
22
+ {
23
+ CSV ,
24
+ JSON ,
25
+ XML
26
+ }
27
+
28
+ /// <summary>
29
+ /// Initializes a new instance of the <see cref="NuPickersValueConnector"/> class.
30
+ /// </summary>
31
+ /// <param name="entityService">An <see cref="IEntityService"/> implementation.</param>
32
+ public NuPickersValueConnector ( IEntityService entityService )
33
+ {
34
+ _entityService = entityService ?? throw new ArgumentNullException ( nameof ( entityService ) ) ;
35
+ }
36
+
37
+ public IEnumerable < string > PropertyEditorAliases => Enumerable . Empty < string > ( ) ;
38
+
39
+ /// <summary>
40
+ /// Gets the deploy property corresponding to a content property.
41
+ /// </summary>
42
+ /// <param name="property">The content property.</param>
43
+ /// <param name="dependencies">The content dependencies.</param>
44
+ /// <returns>The deploy property value.</returns>
45
+ public string GetValue ( Property property , ICollection < ArtifactDependency > dependencies )
46
+ {
47
+ // get the property value
48
+ var value = property . Value as string ;
49
+
50
+ if ( string . IsNullOrWhiteSpace ( value ) )
51
+ return null ;
52
+
53
+ // parse the value - checking the format - CSV, XML or JSON
54
+ SaveFormat format ;
55
+ var items = ParseValue ( value , out format ) ;
56
+
57
+ var result = new List < KeyValuePair < string , string > > ( ) ;
58
+
59
+ // loop over the values
60
+ foreach ( var item in items )
61
+ {
62
+ int nodeId ;
63
+ if ( int . TryParse ( item . Key , out nodeId ) )
64
+ {
65
+ // if an INT, attempt to get the UDI
66
+ var guidUdi = GetGuidUdi ( nodeId ) ;
67
+ if ( guidUdi != null )
68
+ {
69
+ dependencies . Add ( new ArtifactDependency ( guidUdi , false , ArtifactDependencyMode . Exist ) ) ;
70
+ result . Add ( new KeyValuePair < string , string > ( guidUdi . ToString ( ) , item . Value ) ) ;
71
+ }
72
+ else
73
+ {
74
+ // the value isn't a UDI, assume it's "just a string"
75
+ result . Add ( item ) ;
76
+ }
77
+ }
78
+ else
79
+ {
80
+ // the value isn't a node ID, assume it's "just a string"
81
+ result . Add ( item ) ;
82
+ }
83
+ }
84
+
85
+ // return the value in the correct format - CSV, XML, JSON, (whatevs)
86
+ return SerializeValue ( result , format ) ;
87
+ }
88
+
89
+ /// <summary>
90
+ /// Sets a content property value using a deploy property.
91
+ /// </summary>
92
+ /// <param name="content">The content item.</param>
93
+ /// <param name="alias">The property alias.</param>
94
+ /// <param name="value">The deploy property value.</param>
95
+ public void SetValue ( IContentBase content , string alias , string value )
96
+ {
97
+ // parse the value - checking the format - CSV, XML or JSON
98
+ SaveFormat format ;
99
+ var items = ParseValue ( value , out format ) ;
100
+
101
+ var result = new List < KeyValuePair < string , string > > ( ) ;
102
+
103
+ // loop over the values
104
+ foreach ( var item in items )
105
+ {
106
+ GuidUdi guidUdi ;
107
+ if ( GuidUdi . TryParse ( item . Key , out guidUdi ) && guidUdi . Guid != Guid . Empty )
108
+ {
109
+ // if an UDI, attempt to get the INT
110
+ var nodeId = GetIntId ( guidUdi . Guid ) ;
111
+ if ( nodeId > 0 )
112
+ {
113
+ result . Add ( new KeyValuePair < string , string > ( nodeId . ToString ( ) , item . Value ) ) ;
114
+ }
115
+ else
116
+ {
117
+ // the value isn't a node ID, assume it's "just a string"
118
+ result . Add ( item ) ;
119
+ }
120
+ }
121
+ else
122
+ {
123
+ // the value isn't a UDI, assume it's "just a string"
124
+ result . Add ( item ) ;
125
+ }
126
+ }
127
+
128
+ // re-assemble the values into the correct format - CSV, XML, JSON, (whatevs)
129
+ content . SetValue ( alias , SerializeValue ( result , format ) ) ;
130
+ }
131
+
132
+ private IEnumerable < KeyValuePair < string , string > > ParseValue ( string value , out SaveFormat format )
133
+ {
134
+ // code taken from nuPickers
135
+ // ref: https://github.com/uComponents/nuPickers/blob/master/source/nuPickers/Shared/SaveFormat/SaveFormat.cs#L43
136
+ if ( ! string . IsNullOrWhiteSpace ( value ) )
137
+ {
138
+ switch ( value [ 0 ] )
139
+ {
140
+ case '[' :
141
+ format = SaveFormat . JSON ;
142
+ return JsonConvert . DeserializeObject < JArray > ( value ) . Select ( x => new KeyValuePair < string , string > ( x [ "key" ] . ToString ( ) , x [ "label" ] . ToString ( ) ) ) ;
143
+
144
+ case '<' :
145
+ format = SaveFormat . XML ;
146
+ return XDocument . Parse ( value ) . Descendants ( "Picked" ) . Select ( x => new KeyValuePair < string , string > ( x . Attribute ( "Key" ) . Value , x . Value ) ) ;
147
+
148
+ default :
149
+ format = SaveFormat . CSV ;
150
+ return value . Split ( ',' ) . Select ( x => new KeyValuePair < string , string > ( x , null ) ) ; // NOTE: label is null
151
+ }
152
+ }
153
+
154
+ format = SaveFormat . CSV ;
155
+ return Enumerable . Empty < KeyValuePair < string , string > > ( ) ;
156
+ }
157
+
158
+ private string SerializeValue ( IEnumerable < KeyValuePair < string , string > > value , SaveFormat format )
159
+ {
160
+ // ref: https://github.com/uComponents/nuPickers/wiki/Save-Formats
161
+ // ref: https://github.com/uComponents/nuPickers/blob/master/source/nuPickers/Shared/SaveFormat/SaveFormatResource.js#L16
162
+
163
+ switch ( format )
164
+ {
165
+ case SaveFormat . JSON :
166
+ var json = value . Select ( x => $ "{{ 'key': '{ x . Key } ', 'label': '{ x . Value } ' }}") ;
167
+ return string . Concat ( "[" , string . Join ( "," , json , "]" ) ) ;
168
+
169
+ case SaveFormat . XML :
170
+ var xml = value . Select ( x => $ "<Picked Key=\" { x . Key } \" ><![CDATA[{ x . Value } ]]></Picked>") ;
171
+ return string . Concat ( "<Picker>" , string . Join ( "," , xml , "</Picker>" ) ) ;
172
+
173
+ case SaveFormat . CSV :
174
+ default :
175
+ return string . Join ( "," , value . Select ( x => x . Key ) ) ;
176
+ }
177
+ }
178
+
179
+ private GuidUdi GetGuidUdi ( int id )
180
+ {
181
+ var keyForId = _entityService . GetKeyForId ( id , UmbracoObjectTypes . Document ) ;
182
+ if ( keyForId . Success )
183
+ return new GuidUdi ( Constants . UdiEntityType . Document , keyForId . Result ) ;
184
+
185
+ keyForId = _entityService . GetKeyForId ( id , UmbracoObjectTypes . Media ) ;
186
+ if ( keyForId . Success )
187
+ return new GuidUdi ( Constants . UdiEntityType . Media , keyForId . Result ) ;
188
+
189
+ return null ;
190
+ }
191
+
192
+ private int GetIntId ( Guid id )
193
+ {
194
+ var idForKey = _entityService . GetIdForKey ( id , UmbracoObjectTypes . Document ) ;
195
+ if ( idForKey . Success )
196
+ return idForKey . Result ;
197
+
198
+ idForKey = _entityService . GetIdForKey ( id , UmbracoObjectTypes . Media ) ;
199
+ if ( idForKey . Success )
200
+ return idForKey . Result ;
201
+
202
+ return - 1 ;
203
+ }
204
+ }
205
+ }
0 commit comments