├── .artifactignore
├── .editorconfig
├── .gitattributes
├── .gitignore
├── .globalconfig
├── CONTRIBUTING.md
├── Directory.Build.props
├── Directory.Packages.props
├── LICENSE.md
├── README.md
├── Umbraco.Deploy.Contrib.sln
├── azure-pipelines.yml
├── global.json
├── icon.png
├── nuget.config
├── src
└── Umbraco.Deploy.Contrib
│ ├── DataTypeConfigurationConnectors
│ └── DocTypeGridEditorDataTypeConfigurationConnector.cs
│ ├── Extensions
│ ├── ArtifactMigratorCollectionBuilderExtensions.cs
│ └── ArtifactTypeResolverCollectionBuilderExtensions.cs
│ ├── GridCellValueConnectors
│ └── DocTypeGridEditorCellValueConnector.cs
│ ├── Migrators
│ └── Legacy
│ │ ├── Content
│ │ ├── CheckBoxListPropertyValueArtifactMigrator.cs
│ │ ├── DocumentArtifactJsonMigrator.cs
│ │ ├── DropDownListFlexiblePropertyValueArtifactMigrator.cs
│ │ ├── PrevaluePropertyValueArtifactMigratorBase.cs
│ │ └── RadioButtonListPropertyValueArtifactMigrator.cs
│ │ ├── ContentType
│ │ ├── ContentTypeArtifactJsonMigrator.cs
│ │ └── ElementTypeArtifactMigratorBase.cs
│ │ └── DataType
│ │ ├── CheckBoxListDataTypeArtifactMigrator.cs
│ │ ├── ColorPickerAliasDataTypeArtifactMigrator.cs
│ │ ├── ContentPicker2DataTypeArtifactMigrator.cs
│ │ ├── ContentPickerAliasDataTypeArtifactMigrator.cs
│ │ ├── ContentPickerReplaceDataTypeArtifactMigratorBase.cs
│ │ ├── DateDataTypeArtifactMigrator.cs
│ │ ├── DropDownDataTypeArtifactMigrator.cs
│ │ ├── DropDownFlexibleDataTypeArtifactMigrator.cs
│ │ ├── DropDownMultipleDataTypeArtifactMigrator.cs
│ │ ├── DropDownReplaceDataTypeArtifactMigratorBase.cs
│ │ ├── DropdownlistMultiplePublishKeysDataTypeArtifactMigrator.cs
│ │ ├── DropdownlistPublishingKeysDataTypeArtifactMigrator.cs
│ │ ├── MediaPicker2DataTypeArtifactMigrator.cs
│ │ ├── MediaPickerDataTypeArtifactMigrator.cs
│ │ ├── MediaPickerReplaceDataTypeArtifactMigratorBase.cs
│ │ ├── MemberPicker2DataTypeArtifactMigrator.cs
│ │ ├── MultiNodeTreePicker2DataTypeArtifactMigrator.cs
│ │ ├── MultiNodeTreePickerDataTypeArtifactMigrator.cs
│ │ ├── MultiUrlPickerReplaceDataTypeArtifactMigratorBase.cs
│ │ ├── MultipleMediaPickerDataTypeArtifactMigrator.cs
│ │ ├── NoEditDataTypeArtifactMigrator.cs
│ │ ├── PreValuesDataTypeArtifactJsonMigrator.cs
│ │ ├── RadioButtonListDataTypeArtifactMigrator.cs
│ │ ├── RelatedLinks2DataTypeArtifactMigrator.cs
│ │ ├── RelatedLinksDataTypeArtifactMigrator.cs
│ │ ├── TextboxDataTypeArtifactMigrator.cs
│ │ ├── TextboxMultipleDataTypeArtifactMigrator.cs
│ │ └── TinyMCEv3DataTypeArtifactMigrator.cs
│ ├── Serialization
│ └── LegacyArtifactTypeResolver.cs
│ ├── Umbraco.Deploy.Contrib.csproj
│ └── ValueConnectors
│ ├── BlockEditorValueConnector.cs
│ ├── BlockListValueConnector.cs
│ ├── MultiUrlPickerValueConnector.cs
│ └── NestedContentValueConnector.cs
├── tests
├── .editorconfig
├── Directory.Build.props
├── Directory.Packages.props
├── Umbraco.Deploy.Contrib.Tests
│ └── Umbraco.Deploy.Contrib.Tests.csproj
└── codeanalysis.ruleset
└── version.json
/.artifactignore:
--------------------------------------------------------------------------------
1 | **/*
2 | !tests/*/bin/**
3 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Version: 1.6.2 (Using https://semver.org/)
2 | # Updated: 2020-11-02
3 | # See https://github.com/RehanSaeed/EditorConfig/releases for release notes.
4 | # See https://github.com/RehanSaeed/EditorConfig for updates to this file.
5 | # See http://EditorConfig.org for more information about .editorconfig files.
6 |
7 | ##########################################
8 | # Common Settings
9 | ##########################################
10 |
11 | # This file is the top-most EditorConfig file
12 | root = true
13 |
14 | # All Files
15 | [*]
16 | charset = utf-8
17 | indent_style = space
18 | indent_size = 4
19 | insert_final_newline = true
20 | trim_trailing_whitespace = true
21 |
22 | ##########################################
23 | # File Extension Settings
24 | ##########################################
25 |
26 | # Visual Studio Solution Files
27 | [*.sln]
28 | indent_style = tab
29 |
30 | # Visual Studio XML Project Files
31 | [*.{csproj,vbproj,vcxproj.filters,proj,projitems,shproj}]
32 | indent_size = 2
33 |
34 | # XML Configuration Files
35 | [*.{xml,config,props,targets,nuspec,resx,ruleset,vsixmanifest,vsct}]
36 | indent_size = 2
37 |
38 | # JSON Files
39 | [*.{json,json5,webmanifest}]
40 | indent_size = 2
41 |
42 | # YAML Files
43 | [*.{yml,yaml}]
44 | indent_size = 2
45 |
46 | # Markdown Files
47 | [*.md]
48 | trim_trailing_whitespace = false
49 |
50 | # Web Files
51 | [*.{htm,html,js,jsm,ts,tsx,css,sass,scss,less,svg,vue}]
52 | indent_size = 2
53 |
54 | # Batch Files
55 | [*.{cmd,bat}]
56 | end_of_line = crlf
57 |
58 | # Bash Files
59 | [*.sh]
60 | end_of_line = lf
61 |
62 | # Makefiles
63 | [Makefile]
64 | indent_style = tab
65 |
66 |
67 | [*.js]
68 | trim_trailing_whitespace = true
69 |
70 | [*.less]
71 | trim_trailing_whitespace = false
72 |
73 | ##########################################
74 | # File Header (Uncomment to support file headers)
75 | # https://docs.microsoft.com/visualstudio/ide/reference/add-file-header
76 | ##########################################
77 |
78 | # [*.{cs,csx,cake,vb,vbx}]
79 | file_header_template = Copyright (c) Umbraco.\nSee LICENSE for more details.
80 |
81 | # SA1636: File header copyright text should match
82 | # Justification: .editorconfig supports file headers. If this is changed to a value other than "none", a stylecop.json file will need to added to the project.
83 | # dotnet_diagnostic.SA1636.severity = none
84 |
85 | ##########################################
86 | # .NET Language Conventions
87 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions
88 | ##########################################
89 |
90 | # .NET Code Style Settings
91 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#net-code-style-settings
92 | [*.{cs,csx,cake,vb,vbx}]
93 | # "this." and "Me." qualifiers
94 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#this-and-me
95 | dotnet_style_qualification_for_field = false:suggestion
96 | dotnet_style_qualification_for_property = false:suggestion
97 | dotnet_style_qualification_for_method = false:suggestion
98 | dotnet_style_qualification_for_event = false:suggestion
99 | # Language keywords instead of framework type names for type references
100 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#language-keywords
101 | dotnet_style_predefined_type_for_locals_parameters_members = true:warning
102 | dotnet_style_predefined_type_for_member_access = true:warning
103 | # Modifier preferences
104 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#normalize-modifiers
105 | dotnet_style_require_accessibility_modifiers = always:warning
106 | csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:warning
107 | visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:warning
108 | dotnet_style_readonly_field = true:warning
109 | # Parentheses preferences
110 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#parentheses-preferences
111 | dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:warning
112 | dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning
113 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning
114 | dotnet_style_parentheses_in_other_operators = never_if_unnecessary:suggestion
115 | # Expression-level preferences
116 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#expression-level-preferences
117 | dotnet_style_object_initializer = true:warning
118 | dotnet_style_collection_initializer = true:warning
119 | dotnet_style_explicit_tuple_names = true:warning
120 | dotnet_style_prefer_inferred_tuple_names = true:warning
121 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning
122 | dotnet_style_prefer_auto_properties = true:warning
123 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning
124 | dotnet_style_prefer_conditional_expression_over_assignment = false:suggestion
125 | dotnet_style_prefer_conditional_expression_over_return = false:suggestion
126 | dotnet_style_prefer_compound_assignment = true:warning
127 | # Null-checking preferences
128 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#null-checking-preferences
129 | dotnet_style_coalesce_expression = true:warning
130 | dotnet_style_null_propagation = true:warning
131 | # Parameter preferences
132 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#parameter-preferences
133 | dotnet_code_quality_unused_parameters = all:warning
134 | # More style options (Undocumented)
135 | # https://github.com/MicrosoftDocs/visualstudio-docs/issues/3641
136 | dotnet_style_operator_placement_when_wrapping = end_of_line
137 | # https://github.com/dotnet/roslyn/pull/40070
138 | dotnet_style_prefer_simplified_interpolation = true:warning
139 |
140 | # C# Code Style Settings
141 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#c-code-style-settings
142 | [*.{cs,csx,cake}]
143 | # Implicit and explicit types
144 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#implicit-and-explicit-types
145 | csharp_style_var_for_built_in_types = never
146 | csharp_style_var_when_type_is_apparent = true:warning
147 | csharp_style_var_elsewhere = true:warning
148 | # Expression-bodied members
149 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#expression-bodied-members
150 | csharp_style_expression_bodied_methods = true:suggestion
151 | csharp_style_expression_bodied_constructors = true:suggestion
152 | csharp_style_expression_bodied_operators = true:suggestion
153 | csharp_style_expression_bodied_properties = true:suggestion
154 | csharp_style_expression_bodied_indexers = true:suggestion
155 | csharp_style_expression_bodied_accessors = true:suggestion
156 | csharp_style_expression_bodied_lambdas = true:suggestion
157 | csharp_style_expression_bodied_local_functions = true:suggestion
158 | # Pattern matching
159 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#pattern-matching
160 | csharp_style_pattern_matching_over_is_with_cast_check = true:warning
161 | csharp_style_pattern_matching_over_as_with_null_check = true:warning
162 | # Inlined variable declarations
163 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#inlined-variable-declarations
164 | csharp_style_inlined_variable_declaration = true:warning
165 | # Expression-level preferences
166 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#expression-level-preferences
167 | csharp_prefer_simple_default_expression = true:warning
168 | # "Null" checking preferences
169 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#c-null-checking-preferences
170 | csharp_style_throw_expression = true:warning
171 | csharp_style_conditional_delegate_call = true:warning
172 | # Code block preferences
173 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#code-block-preferences
174 | csharp_prefer_braces = true:warning
175 | # Unused value preferences
176 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#unused-value-preferences
177 | csharp_style_unused_value_expression_statement_preference = discard_variable:suggestion
178 | csharp_style_unused_value_assignment_preference = discard_variable:suggestion
179 | # Index and range preferences
180 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#index-and-range-preferences
181 | csharp_style_prefer_index_operator = true:warning
182 | csharp_style_prefer_range_operator = true:warning
183 | # Miscellaneous preferences
184 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#miscellaneous-preferences
185 | csharp_style_deconstructed_variable_declaration = true:warning
186 | csharp_style_pattern_local_over_anonymous_function = true:warning
187 | csharp_using_directive_placement = outside_namespace:warning
188 | csharp_prefer_static_local_function = true:warning
189 | csharp_prefer_simple_using_statement = true:suggestion
190 |
191 | ##########################################
192 | # .NET Formatting Conventions
193 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-code-style-settings-reference#formatting-conventions
194 | ##########################################
195 |
196 | # Organize usings
197 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#organize-using-directives
198 | dotnet_sort_system_directives_first = true
199 | # Newline options
200 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#new-line-options
201 | csharp_new_line_before_open_brace = all
202 | csharp_new_line_before_else = true
203 | csharp_new_line_before_catch = true
204 | csharp_new_line_before_finally = true
205 | csharp_new_line_before_members_in_object_initializers = true
206 | csharp_new_line_before_members_in_anonymous_types = true
207 | csharp_new_line_between_query_expression_clauses = true
208 | # Indentation options
209 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#indentation-options
210 | csharp_indent_case_contents = true
211 | csharp_indent_switch_labels = true
212 | csharp_indent_labels = no_change
213 | csharp_indent_block_contents = true
214 | csharp_indent_braces = false
215 | csharp_indent_case_contents_when_block = false
216 | # Spacing options
217 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#spacing-options
218 | csharp_space_after_cast = false
219 | csharp_space_after_keywords_in_control_flow_statements = true
220 | csharp_space_between_parentheses = false
221 | csharp_space_before_colon_in_inheritance_clause = true
222 | csharp_space_after_colon_in_inheritance_clause = true
223 | csharp_space_around_binary_operators = before_and_after
224 | csharp_space_between_method_declaration_parameter_list_parentheses = false
225 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
226 | csharp_space_between_method_declaration_name_and_open_parenthesis = false
227 | csharp_space_between_method_call_parameter_list_parentheses = false
228 | csharp_space_between_method_call_empty_parameter_list_parentheses = false
229 | csharp_space_between_method_call_name_and_opening_parenthesis = false
230 | csharp_space_after_comma = true
231 | csharp_space_before_comma = false
232 | csharp_space_after_dot = false
233 | csharp_space_before_dot = false
234 | csharp_space_after_semicolon_in_for_statement = true
235 | csharp_space_before_semicolon_in_for_statement = false
236 | csharp_space_around_declaration_statements = false
237 | csharp_space_before_open_square_brackets = false
238 | csharp_space_between_empty_square_brackets = false
239 | csharp_space_between_square_brackets = false
240 | # Wrapping options
241 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#wrap-options
242 | csharp_preserve_single_line_statements = false
243 | csharp_preserve_single_line_blocks = true
244 |
245 | ##########################################
246 | # .NET Naming Conventions
247 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-naming-conventions
248 | ##########################################
249 |
250 | [*.{cs,csx,cake,vb,vbx}]
251 | dotnet_diagnostic.CS1591.severity = suggestion
252 |
253 | ##########################################
254 | # Styles
255 | ##########################################
256 |
257 | # camel_case_style - Define the camelCase style
258 | dotnet_naming_style.camel_case_style.capitalization = camel_case
259 | # pascal_case_style - Define the PascalCase style
260 | dotnet_naming_style.pascal_case_style.capitalization = pascal_case
261 | # first_upper_style - The first character must start with an upper-case character
262 | dotnet_naming_style.first_upper_style.capitalization = first_word_upper
263 | # prefix_interface_with_i_style - Interfaces must be PascalCase and the first character of an interface must be an 'I'
264 | dotnet_naming_style.prefix_interface_with_i_style.capitalization = pascal_case
265 | dotnet_naming_style.prefix_interface_with_i_style.required_prefix = I
266 | # prefix_type_parameters_with_t_style - Generic Type Parameters must be PascalCase and the first character must be a 'T'
267 | dotnet_naming_style.prefix_type_parameters_with_t_style.capitalization = pascal_case
268 | dotnet_naming_style.prefix_type_parameters_with_t_style.required_prefix = T
269 | # disallowed_style - Anything that has this style applied is marked as disallowed
270 | dotnet_naming_style.disallowed_style.capitalization = pascal_case
271 | dotnet_naming_style.disallowed_style.required_prefix = ____RULE_VIOLATION____
272 | dotnet_naming_style.disallowed_style.required_suffix = ____RULE_VIOLATION____
273 | # internal_error_style - This style should never occur... if it does, it indicates a bug in file or in the parser using the file
274 | dotnet_naming_style.internal_error_style.capitalization = pascal_case
275 | dotnet_naming_style.internal_error_style.required_prefix = ____INTERNAL_ERROR____
276 | dotnet_naming_style.internal_error_style.required_suffix = ____INTERNAL_ERROR____
277 |
278 | ##########################################
279 | # .NET Design Guideline Field Naming Rules
280 | # Naming rules for fields follow the .NET Framework design guidelines
281 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/index
282 | ##########################################
283 |
284 | # All public/protected/protected_internal constant fields must be PascalCase
285 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/field
286 | dotnet_naming_symbols.public_protected_constant_fields_group.applicable_accessibilities = public, protected, protected_internal, internal, private
287 | dotnet_naming_symbols.public_protected_constant_fields_group.required_modifiers = const
288 | dotnet_naming_symbols.public_protected_constant_fields_group.applicable_kinds = field
289 | dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.symbols = public_protected_constant_fields_group
290 | dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.style = pascal_case_style
291 | dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.severity = warning
292 |
293 | # All public/protected/protected_internal static readonly fields must be PascalCase
294 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/field
295 | dotnet_naming_symbols.public_protected_static_readonly_fields_group.applicable_accessibilities = public, protected, protected_internal
296 | dotnet_naming_symbols.public_protected_static_readonly_fields_group.required_modifiers = static, readonly
297 | dotnet_naming_symbols.public_protected_static_readonly_fields_group.applicable_kinds = field
298 | dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.symbols = public_protected_static_readonly_fields_group
299 | dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.style = pascal_case_style
300 | dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.severity = warning
301 |
302 | # No other public/protected/protected_internal fields are allowed
303 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/field
304 | dotnet_naming_symbols.other_public_protected_fields_group.applicable_accessibilities = public, protected, protected_internal
305 | dotnet_naming_symbols.other_public_protected_fields_group.applicable_kinds = field
306 | dotnet_naming_rule.other_public_protected_fields_disallowed_rule.symbols = other_public_protected_fields_group
307 | dotnet_naming_rule.other_public_protected_fields_disallowed_rule.style = disallowed_style
308 | dotnet_naming_rule.other_public_protected_fields_disallowed_rule.severity = error
309 |
310 | # This rule should never fire. However, it's included for at least two purposes:
311 | # First, it helps to understand, reason about, and root-case certain types of issues, such as bugs in .editorconfig parsers.
312 | # Second, it helps to raise immediate awareness if a new field type is added (as occurred recently in C#).
313 | dotnet_naming_symbols.sanity_check_uncovered_field_case_group.applicable_accessibilities = *
314 | dotnet_naming_symbols.sanity_check_uncovered_field_case_group.applicable_kinds = field
315 | dotnet_naming_rule.sanity_check_uncovered_field_case_rule.symbols = sanity_check_uncovered_field_case_group
316 | dotnet_naming_rule.sanity_check_uncovered_field_case_rule.style = internal_error_style
317 | dotnet_naming_rule.sanity_check_uncovered_field_case_rule.severity = error
318 |
319 | ##########################################
320 | # Other Naming Rules
321 | ##########################################
322 |
323 | # All of the following must be PascalCase:
324 | # - Namespaces
325 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-namespaces
326 | # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1300.md
327 | # - Classes and Enumerations
328 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces
329 | # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1300.md
330 | # - Delegates
331 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces#names-of-common-types
332 | # - Constructors, Properties, Events, Methods
333 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-type-members
334 | dotnet_naming_symbols.element_group.applicable_kinds = namespace, class, enum, struct, delegate, event, method, property
335 | dotnet_naming_rule.element_rule.symbols = element_group
336 | dotnet_naming_rule.element_rule.style = pascal_case_style
337 | dotnet_naming_rule.element_rule.severity = warning
338 |
339 | # Interfaces use PascalCase and are prefixed with uppercase 'I'
340 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces
341 | dotnet_naming_symbols.interface_group.applicable_kinds = interface
342 | dotnet_naming_rule.interface_rule.symbols = interface_group
343 | dotnet_naming_rule.interface_rule.style = prefix_interface_with_i_style
344 | dotnet_naming_rule.interface_rule.severity = warning
345 |
346 | # Generics Type Parameters use PascalCase and are prefixed with uppercase 'T'
347 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces
348 | dotnet_naming_symbols.type_parameter_group.applicable_kinds = type_parameter
349 | dotnet_naming_rule.type_parameter_rule.symbols = type_parameter_group
350 | dotnet_naming_rule.type_parameter_rule.style = prefix_type_parameters_with_t_style
351 | dotnet_naming_rule.type_parameter_rule.severity = warning
352 |
353 | # Function parameters use camelCase
354 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/naming-parameters
355 | dotnet_naming_symbols.parameters_group.applicable_kinds = parameter
356 | dotnet_naming_rule.parameters_rule.symbols = parameters_group
357 | dotnet_naming_rule.parameters_rule.style = camel_case_style
358 | dotnet_naming_rule.parameters_rule.severity = warning
359 |
360 | # Instance fields use camelCase and are prefixed with '_'
361 | dotnet_naming_rule.instance_fields_should_be_camel_case.severity = warning
362 | dotnet_naming_rule.instance_fields_should_be_camel_case.symbols = instance_fields
363 | dotnet_naming_rule.instance_fields_should_be_camel_case.style = instance_field_style
364 | dotnet_naming_symbols.instance_fields.applicable_kinds = field
365 | dotnet_naming_style.instance_field_style.capitalization = camel_case
366 | dotnet_naming_style.instance_field_style.required_prefix = _
367 |
368 | ##########################################
369 | # License
370 | ##########################################
371 | # The following applies as to the .editorconfig file ONLY, and is
372 | # included below for reference, per the requirements of the license
373 | # corresponding to this .editorconfig file.
374 | # See: https://github.com/RehanSaeed/EditorConfig
375 | #
376 | # MIT License
377 | #
378 | # Copyright (c) 2017-2019 Muhammad Rehan Saeed
379 | # Copyright (c) 2019 Henry Gabryjelski
380 | #
381 | # Permission is hereby granted, free of charge, to any
382 | # person obtaining a copy of this software and associated
383 | # documentation files (the "Software"), to deal in the
384 | # Software without restriction, including without limitation
385 | # the rights to use, copy, modify, merge, publish, distribute,
386 | # sublicense, and/or sell copies of the Software, and to permit
387 | # persons to whom the Software is furnished to do so, subject
388 | # to the following conditions:
389 | #
390 | # The above copyright notice and this permission notice shall be
391 | # included in all copies or substantial portions of the Software.
392 | #
393 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
394 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
395 | # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
396 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
397 | # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
398 | # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
399 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
400 | # OTHER DEALINGS IN THE SOFTWARE.
401 | ##########################################
402 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 | *.doc diff=astextplain
3 | *.DOC diff=astextplain
4 | *.docx diff=astextplain
5 | *.DOCX diff=astextplain
6 | *.dot diff=astextplain
7 | *.DOT diff=astextplain
8 | *.pdf diff=astextplain
9 | *.PDF diff=astextplain
10 | *.rtf diff=astextplain
11 | *.RTF diff=astextplain
12 |
13 | *.jpg binary
14 | *.png binary
15 | *.gif binary
16 |
17 | *.cs text=auto diff=csharp
18 | *.vb text=auto
19 | *.c text=auto
20 | *.cpp text=auto
21 | *.cxx text=auto
22 | *.h text=auto
23 | *.hxx text=auto
24 | *.py text=auto
25 | *.rb text=auto
26 | *.java text=auto
27 | *.html text=auto
28 | *.htm text=auto
29 | *.css text=auto
30 | *.scss text=auto
31 | *.sass text=auto
32 | *.less text=auto
33 | *.js text=auto
34 | *.lisp text=auto
35 | *.clj text=auto
36 | *.sql text=auto
37 | *.php text=auto
38 | *.lua text=auto
39 | *.m text=auto
40 | *.asm text=auto
41 | *.erl text=auto
42 | *.fs text=auto
43 | *.fsx text=auto
44 | *.hs text=auto
45 | *.json text=auto
46 | *.xml text=auto
47 | *.resx text=auto
48 | *.yml text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
49 |
50 | *.csproj text=auto merge=union
51 | *.vbproj text=auto merge=union
52 | *.fsproj text=auto merge=union
53 | *.dbproj text=auto merge=union
54 | *.sln text=auto eol=crlf merge=union
55 |
56 | *.gitattributes text=auto
57 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from `dotnet new gitignore`
5 |
6 | # dotenv files
7 | .env
8 |
9 | # User-specific files
10 | *.rsuser
11 | *.suo
12 | *.user
13 | *.userosscache
14 | *.sln.docstates
15 |
16 | # User-specific files (MonoDevelop/Xamarin Studio)
17 | *.userprefs
18 |
19 | # Mono auto generated files
20 | mono_crash.*
21 |
22 | # Build results
23 | [Dd]ebug/
24 | [Dd]ebugPublic/
25 | [Rr]elease/
26 | [Rr]eleases/
27 | x64/
28 | x86/
29 | [Ww][Ii][Nn]32/
30 | [Aa][Rr][Mm]/
31 | [Aa][Rr][Mm]64/
32 | bld/
33 | [Bb]in/
34 | [Oo]bj/
35 | [Ll]og/
36 | [Ll]ogs/
37 |
38 | # Visual Studio 2015/2017 cache/options directory
39 | .vs/
40 | # Uncomment if you have tasks that create the project's static files in wwwroot
41 | #wwwroot/
42 |
43 | # Visual Studio 2017 auto generated files
44 | Generated\ Files/
45 |
46 | # MSTest test Results
47 | [Tt]est[Rr]esult*/
48 | [Bb]uild[Ll]og.*
49 |
50 | # NUnit
51 | *.VisualState.xml
52 | TestResult.xml
53 | nunit-*.xml
54 |
55 | # Build Results of an ATL Project
56 | [Dd]ebugPS/
57 | [Rr]eleasePS/
58 | dlldata.c
59 |
60 | # Benchmark Results
61 | BenchmarkDotNet.Artifacts/
62 |
63 | # .NET
64 | project.lock.json
65 | project.fragment.lock.json
66 | artifacts/
67 |
68 | # Tye
69 | .tye/
70 |
71 | # ASP.NET Scaffolding
72 | ScaffoldingReadMe.txt
73 |
74 | # StyleCop
75 | StyleCopReport.xml
76 |
77 | # Files built by Visual Studio
78 | *_i.c
79 | *_p.c
80 | *_h.h
81 | *.ilk
82 | *.meta
83 | *.obj
84 | *.iobj
85 | *.pch
86 | *.pdb
87 | *.ipdb
88 | *.pgc
89 | *.pgd
90 | *.rsp
91 | *.sbr
92 | *.tlb
93 | *.tli
94 | *.tlh
95 | *.tmp
96 | *.tmp_proj
97 | *_wpftmp.csproj
98 | *.log
99 | *.tlog
100 | *.vspscc
101 | *.vssscc
102 | .builds
103 | *.pidb
104 | *.svclog
105 | *.scc
106 |
107 | # Chutzpah Test files
108 | _Chutzpah*
109 |
110 | # Visual C++ cache files
111 | ipch/
112 | *.aps
113 | *.ncb
114 | *.opendb
115 | *.opensdf
116 | *.sdf
117 | *.cachefile
118 | *.VC.db
119 | *.VC.VC.opendb
120 |
121 | # Visual Studio profiler
122 | *.psess
123 | *.vsp
124 | *.vspx
125 | *.sap
126 |
127 | # Visual Studio Trace Files
128 | *.e2e
129 |
130 | # TFS 2012 Local Workspace
131 | $tf/
132 |
133 | # Guidance Automation Toolkit
134 | *.gpState
135 |
136 | # ReSharper is a .NET coding add-in
137 | _ReSharper*/
138 | *.[Rr]e[Ss]harper
139 | *.DotSettings.user
140 |
141 | # TeamCity is a build add-in
142 | _TeamCity*
143 |
144 | # DotCover is a Code Coverage Tool
145 | *.dotCover
146 |
147 | # AxoCover is a Code Coverage Tool
148 | .axoCover/*
149 | !.axoCover/settings.json
150 |
151 | # Coverlet is a free, cross platform Code Coverage Tool
152 | coverage*.json
153 | coverage*.xml
154 | coverage*.info
155 |
156 | # Visual Studio code coverage results
157 | *.coverage
158 | *.coveragexml
159 |
160 | # NCrunch
161 | _NCrunch_*
162 | .*crunch*.local.xml
163 | nCrunchTemp_*
164 |
165 | # MightyMoose
166 | *.mm.*
167 | AutoTest.Net/
168 |
169 | # Web workbench (sass)
170 | .sass-cache/
171 |
172 | # Installshield output folder
173 | [Ee]xpress/
174 |
175 | # DocProject is a documentation generator add-in
176 | DocProject/buildhelp/
177 | DocProject/Help/*.HxT
178 | DocProject/Help/*.HxC
179 | DocProject/Help/*.hhc
180 | DocProject/Help/*.hhk
181 | DocProject/Help/*.hhp
182 | DocProject/Help/Html2
183 | DocProject/Help/html
184 |
185 | # Click-Once directory
186 | publish/
187 |
188 | # Publish Web Output
189 | *.[Pp]ublish.xml
190 | *.azurePubxml
191 | # Note: Comment the next line if you want to checkin your web deploy settings,
192 | # but database connection strings (with potential passwords) will be unencrypted
193 | *.pubxml
194 | *.publishproj
195 |
196 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
197 | # checkin your Azure Web App publish settings, but sensitive information contained
198 | # in these scripts will be unencrypted
199 | PublishScripts/
200 |
201 | # NuGet Packages
202 | *.nupkg
203 | # NuGet Symbol Packages
204 | *.snupkg
205 | # The packages folder can be ignored because of Package Restore
206 | **/[Pp]ackages/*
207 | # except build/, which is used as an MSBuild target.
208 | !**/[Pp]ackages/build/
209 | # Uncomment if necessary however generally it will be regenerated when needed
210 | #!**/[Pp]ackages/repositories.config
211 | # NuGet v3's project.json files produces more ignorable files
212 | *.nuget.props
213 | *.nuget.targets
214 |
215 | # Microsoft Azure Build Output
216 | csx/
217 | *.build.csdef
218 |
219 | # Microsoft Azure Emulator
220 | ecf/
221 | rcf/
222 |
223 | # Windows Store app package directories and files
224 | AppPackages/
225 | BundleArtifacts/
226 | Package.StoreAssociation.xml
227 | _pkginfo.txt
228 | *.appx
229 | *.appxbundle
230 | *.appxupload
231 |
232 | # Visual Studio cache files
233 | # files ending in .cache can be ignored
234 | *.[Cc]ache
235 | # but keep track of directories ending in .cache
236 | !?*.[Cc]ache/
237 |
238 | # Others
239 | ClientBin/
240 | ~$*
241 | *~
242 | *.dbmdl
243 | *.dbproj.schemaview
244 | *.jfm
245 | *.pfx
246 | *.publishsettings
247 | orleans.codegen.cs
248 |
249 | # Including strong name files can present a security risk
250 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
251 | #*.snk
252 |
253 | # Since there are multiple workflows, uncomment next line to ignore bower_components
254 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
255 | #bower_components/
256 |
257 | # RIA/Silverlight projects
258 | Generated_Code/
259 |
260 | # Backup & report files from converting an old project file
261 | # to a newer Visual Studio version. Backup files are not needed,
262 | # because we have git ;-)
263 | _UpgradeReport_Files/
264 | Backup*/
265 | UpgradeLog*.XML
266 | UpgradeLog*.htm
267 | ServiceFabricBackup/
268 | *.rptproj.bak
269 |
270 | # SQL Server files
271 | *.mdf
272 | *.ldf
273 | *.ndf
274 |
275 | # Business Intelligence projects
276 | *.rdl.data
277 | *.bim.layout
278 | *.bim_*.settings
279 | *.rptproj.rsuser
280 | *- [Bb]ackup.rdl
281 | *- [Bb]ackup ([0-9]).rdl
282 | *- [Bb]ackup ([0-9][0-9]).rdl
283 |
284 | # Microsoft Fakes
285 | FakesAssemblies/
286 |
287 | # GhostDoc plugin setting file
288 | *.GhostDoc.xml
289 |
290 | # Node.js Tools for Visual Studio
291 | .ntvs_analysis.dat
292 | node_modules/
293 |
294 | # Visual Studio 6 build log
295 | *.plg
296 |
297 | # Visual Studio 6 workspace options file
298 | *.opt
299 |
300 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
301 | *.vbw
302 |
303 | # Visual Studio 6 auto-generated project file (contains which files were open etc.)
304 | *.vbp
305 |
306 | # Visual Studio 6 workspace and project file (working project files containing files to include in project)
307 | *.dsw
308 | *.dsp
309 |
310 | # Visual Studio 6 technical files
311 | *.ncb
312 | *.aps
313 |
314 | # Visual Studio LightSwitch build output
315 | **/*.HTMLClient/GeneratedArtifacts
316 | **/*.DesktopClient/GeneratedArtifacts
317 | **/*.DesktopClient/ModelManifest.xml
318 | **/*.Server/GeneratedArtifacts
319 | **/*.Server/ModelManifest.xml
320 | _Pvt_Extensions
321 |
322 | # Paket dependency manager
323 | .paket/paket.exe
324 | paket-files/
325 |
326 | # FAKE - F# Make
327 | .fake/
328 |
329 | # CodeRush personal settings
330 | .cr/personal
331 |
332 | # Python Tools for Visual Studio (PTVS)
333 | __pycache__/
334 | *.pyc
335 |
336 | # Cake - Uncomment if you are using it
337 | # tools/**
338 | # !tools/packages.config
339 |
340 | # Tabs Studio
341 | *.tss
342 |
343 | # Telerik's JustMock configuration file
344 | *.jmconfig
345 |
346 | # BizTalk build output
347 | *.btp.cs
348 | *.btm.cs
349 | *.odx.cs
350 | *.xsd.cs
351 |
352 | # OpenCover UI analysis results
353 | OpenCover/
354 |
355 | # Azure Stream Analytics local run output
356 | ASALocalRun/
357 |
358 | # MSBuild Binary and Structured Log
359 | *.binlog
360 |
361 | # NVidia Nsight GPU debugger configuration file
362 | *.nvuser
363 |
364 | # MFractors (Xamarin productivity tool) working folder
365 | .mfractor/
366 |
367 | # Local History for Visual Studio
368 | .localhistory/
369 |
370 | # Visual Studio History (VSHistory) files
371 | .vshistory/
372 |
373 | # BeatPulse healthcheck temp database
374 | healthchecksdb
375 |
376 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
377 | MigrationBackup/
378 |
379 | # Ionide (cross platform F# VS Code tools) working folder
380 | .ionide/
381 |
382 | # Fody - auto-generated XML schema
383 | FodyWeavers.xsd
384 |
385 | # VS Code files for those working on multiple tools
386 | .vscode/*
387 | !.vscode/settings.json
388 | !.vscode/tasks.json
389 | !.vscode/launch.json
390 | !.vscode/extensions.json
391 | *.code-workspace
392 |
393 | # Local History for Visual Studio Code
394 | .history/
395 |
396 | # Windows Installer files from build outputs
397 | *.cab
398 | *.msi
399 | *.msix
400 | *.msm
401 | *.msp
402 |
403 | # JetBrains Rider
404 | *.sln.iml
405 | .idea
406 |
407 | ##
408 | ## Visual studio for Mac
409 | ##
410 |
411 |
412 | # globs
413 | Makefile.in
414 | *.userprefs
415 | *.usertasks
416 | config.make
417 | config.status
418 | aclocal.m4
419 | install-sh
420 | autom4te.cache/
421 | *.tar.gz
422 | tarballs/
423 | test-results/
424 |
425 | # Mac bundle stuff
426 | *.dmg
427 | *.app
428 |
429 | # content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
430 | # General
431 | .DS_Store
432 | .AppleDouble
433 | .LSOverride
434 |
435 | # Icon must end with two \r
436 | Icon
437 |
438 |
439 | # Thumbnails
440 | ._*
441 |
442 | # Files that might appear in the root of a volume
443 | .DocumentRevisions-V100
444 | .fseventsd
445 | .Spotlight-V100
446 | .TemporaryItems
447 | .Trashes
448 | .VolumeIcon.icns
449 | .com.apple.timemachine.donotpresent
450 |
451 | # Directories potentially created on remote AFP share
452 | .AppleDB
453 | .AppleDesktop
454 | Network Trash Folder
455 | Temporary Items
456 | .apdisk
457 |
458 | # content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
459 | # Windows thumbnail cache files
460 | Thumbs.db
461 | ehthumbs.db
462 | ehthumbs_vista.db
463 |
464 | # Dump file
465 | *.stackdump
466 |
467 | # Folder config file
468 | [Dd]esktop.ini
469 |
470 | # Recycle Bin used on file shares
471 | $RECYCLE.BIN/
472 |
473 | # Windows Installer files
474 | *.cab
475 | *.msi
476 | *.msix
477 | *.msm
478 | *.msp
479 |
480 | # Windows shortcuts
481 | *.lnk
482 |
483 | # Vim temporary swap files
484 | *.swp
485 |
--------------------------------------------------------------------------------
/.globalconfig:
--------------------------------------------------------------------------------
1 | is_global = true
2 |
3 | ##########################################
4 | # StyleCopAnalyzers Settings
5 | ##########################################
6 |
7 | # All constant fields must be PascalCase
8 | # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1303.md
9 | dotnet_naming_symbols.stylecop_constant_fields_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected, private
10 | dotnet_naming_symbols.stylecop_constant_fields_group.required_modifiers = const
11 | dotnet_naming_symbols.stylecop_constant_fields_group.applicable_kinds = field
12 | dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.symbols = stylecop_constant_fields_group
13 | dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.style = pascal_case_style
14 |
15 | # All static readonly fields must be PascalCase
16 | # Ajusted to ignore private fields.
17 | # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1311.md
18 | dotnet_naming_symbols.stylecop_static_readonly_fields_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected
19 | dotnet_naming_symbols.stylecop_static_readonly_fields_group.required_modifiers = static, readonly
20 | dotnet_naming_symbols.stylecop_static_readonly_fields_group.applicable_kinds = field
21 | dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.symbols = stylecop_static_readonly_fields_group
22 | dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.style = pascal_case_style
23 |
24 | # No non-private instance fields are allowed
25 | # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1401.md
26 | dotnet_naming_symbols.stylecop_fields_must_be_private_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected
27 | dotnet_naming_symbols.stylecop_fields_must_be_private_group.applicable_kinds = field
28 | dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.symbols = stylecop_fields_must_be_private_group
29 | dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.style = disallowed_style
30 |
31 | # Local variables must be camelCase
32 | # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1312.md
33 | dotnet_naming_symbols.stylecop_local_fields_group.applicable_accessibilities = local
34 | dotnet_naming_symbols.stylecop_local_fields_group.applicable_kinds = local
35 | dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.symbols = stylecop_local_fields_group
36 | dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.style = camel_case_style
37 |
38 | ##########################################
39 | # StyleCopAnalyzers rule severity
40 | # https://github.com/DotNetAnalyzers/StyleCopAnalyzers
41 | ##########################################
42 |
43 | dotnet_analyzer_diagnostic.category-StyleCop.CSharp.DocumentationRules.severity = suggestion
44 | dotnet_analyzer_diagnostic.category-StyleCop.CSharp.ReadabilityRules.severity = suggestion
45 | dotnet_analyzer_diagnostic.category-StyleCop.CSharp.NamingRules.severity = suggestion
46 | dotnet_analyzer_diagnostic.category-StyleCop.CSharp.SpacingRules.severity = suggestion
47 | dotnet_analyzer_diagnostic.category-StyleCop.CSharp.OrderingRules.severity = suggestion
48 | dotnet_analyzer_diagnostic.category-StyleCop.CSharp.MaintainabilityRules.severity = suggestion
49 | dotnet_analyzer_diagnostic.category-StyleCop.CSharp.LayoutRules.severity = suggestion
50 |
51 | dotnet_diagnostic.SA1636.severity = none # SA1636: File header copyright text should match
52 | dotnet_diagnostic.SA1101.severity = none # PrefixLocalCallsWithThis - stylecop appears to be ignoring dotnet_style_qualification_for_*
53 | dotnet_diagnostic.SA1309.severity = none # FieldNamesMustNotBeginWithUnderscore
54 |
55 | dotnet_diagnostic.SA1503.severity = warning # BracesMustNotBeOmitted
56 | dotnet_diagnostic.SA1117.severity = warning # ParametersMustBeOnSameLineOrSeparateLines
57 | dotnet_diagnostic.SA1116.severity = warning # SplitParametersMustStartOnLineAfterDeclaration
58 | dotnet_diagnostic.SA1122.severity = warning # UseStringEmptyForEmptyStrings
59 | dotnet_diagnostic.SA1028.severity = warning # CodeMustNotContainTrailingWhitespace
60 | dotnet_diagnostic.SA1500.severity = warning # BracesForMultiLineStatementsMustNotShareLine
61 | dotnet_diagnostic.SA1401.severity = warning # FieldsMustBePrivate
62 | dotnet_diagnostic.SA1519.severity = warning # BracesMustNotBeOmittedFromMultiLineChildStatement
63 | dotnet_diagnostic.SA1111.severity = warning # ClosingParenthesisMustBeOnLineOfLastParameter
64 | dotnet_diagnostic.SA1520.severity = warning # UseBracesConsistently
65 | dotnet_diagnostic.SA1407.severity = warning # ArithmeticExpressionsMustDeclarePrecedence
66 | dotnet_diagnostic.SA1400.severity = warning # AccessModifierMustBeDeclared
67 | dotnet_diagnostic.SA1119.severity = warning # StatementMustNotUseUnnecessaryParenthesis
68 | dotnet_diagnostic.SA1649.severity = warning # FileNameMustMatchTypeName
69 | dotnet_diagnostic.SA1121.severity = warning # UseBuiltInTypeAlias
70 | dotnet_diagnostic.SA1132.severity = warning # DoNotCombineFields
71 | dotnet_diagnostic.SA1134.severity = warning # AttributesMustNotShareLine
72 | dotnet_diagnostic.SA1106.severity = warning # CodeMustNotContainEmptyStatements
73 | dotnet_diagnostic.SA1312.severity = warning # VariableNamesMustBeginWithLowerCaseLetter
74 | dotnet_diagnostic.SA1310.severity = warning # FieldNamesMustNotContainUnderscore
75 | dotnet_diagnostic.SA1303.severity = warning # ConstFieldNamesMustBeginWithUpperCaseLetter
76 | dotnet_diagnostic.SA1130.severity = warning # UseLambdaSyntax
77 | dotnet_diagnostic.SA1405.severity = warning # DebugAssertMustProvideMessageText
78 | dotnet_diagnostic.SA1205.severity = warning # PartialElementsMustDeclareAccess
79 | dotnet_diagnostic.SA1306.severity = warning # FieldNamesMustBeginWithLowerCaseLetter
80 | dotnet_diagnostic.SA1209.severity = warning # UsingAliasDirectivesMustBePlacedAfterOtherUsingDirectives
81 | dotnet_diagnostic.SA1216.severity = warning # UsingStaticDirectivesMustBePlacedAtTheCorrectLocation
82 | dotnet_diagnostic.SA1133.severity = warning # DoNotCombineAttributes
83 | dotnet_diagnostic.SA1135.severity = warning # UsingDirectivesMustBeQualified
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to this project
2 |
3 | Please take a moment to review this document in order to make the contribution
4 | process easy and effective for everyone involved.
5 |
6 | Following these guidelines helps to communicate that you respect the time of
7 | the developers managing and developing this open source project. In return,
8 | they should reciprocate that respect in addressing your issue or assessing
9 | patches and features.
10 |
11 |
12 | ## Using the issue tracker
13 |
14 | The issue tracker is the preferred channel for [bug reports](#bugs),
15 | [features requests](#features) and [submitting pull
16 | requests](#pull-requests), but please respect the following restrictions:
17 |
18 | * Please **do not** use the issue tracker for personal or commercial support
19 | requests (use the official Umbraco support channels).
20 |
21 | * Please **do not** derail or troll issues. Keep the discussion on topic and
22 | respect the opinions of others.
23 |
24 |
25 |
26 | ## Bug reports
27 |
28 | A bug is a _demonstrable problem_ that is caused by the code in the repository.
29 | Good bug reports are extremely helpful - thank you!
30 |
31 | Guidelines for bug reports:
32 |
33 | 1. **Use the search function** — check if the issue has already been
34 | reported.
35 |
36 | 2. **Check if the issue has been fixed** — try to reproduce it using the
37 | latest `master` or development branch in the repository.
38 |
39 | 3. **Isolate the problem** — create a reduced test
40 | case and a live example.
41 |
42 | A good bug report shouldn't leave others needing to chase you up for more
43 | information. Please try to be as detailed as possible in your report. What is
44 | your environment? What steps will reproduce the issue? What browser(s) and OS
45 | experience the problem? What would you expect to be the outcome? All these
46 | details will help people to fix any potential bugs.
47 |
48 | Example:
49 |
50 | > Short and descriptive example bug report title
51 | >
52 | > A summary of the issue and the browser/OS environment in which it occurs. If
53 | > suitable, include the steps required to reproduce the bug.
54 | >
55 | > 1. This is the first step
56 | > 2. This is the second step
57 | > 3. Further steps, etc.
58 | >
59 | > `` - a link to the reduced test case
60 | >
61 | > Any other information you want to share that is relevant to the issue being
62 | > reported. This might include the lines of code that you have identified as
63 | > causing the bug, and potential solutions (and your opinions on their
64 | > merits).
65 |
66 |
67 |
68 | ## Feature requests
69 |
70 | Feature requests are welcome. But take a moment to find out whether your idea
71 | fits with the scope and aims of the project. It's up to *you* to make a strong
72 | case to convince the project's developers of the merits of this feature. Please
73 | provide as much detail and context as possible.
74 |
75 |
76 |
77 | ## Pull requests
78 |
79 | Good pull requests - patches, improvements, new features - are a fantastic
80 | help. They should remain focused in scope and avoid containing unrelated
81 | commits.
82 |
83 | **Please ask first** before embarking on any significant pull request (e.g.
84 | implementing features, refactoring code, porting to a different language),
85 | otherwise you risk spending a lot of time working on something that the
86 | project's developers might not want to merge into the project.
87 |
88 | Please adhere to the coding conventions used throughout a project (indentation,
89 | accurate comments, etc.) and any other requirements (such as test coverage).
90 |
91 | Follow this process if you'd like your work considered for inclusion in the
92 | project:
93 |
94 | 1. [Fork](http://help.github.com/fork-a-repo/) the project, clone your fork,
95 | and configure the remotes:
96 |
97 | ```bash
98 | # Clone your fork of the repo into the current directory
99 | git clone https://github.com//
100 | # Navigate to the newly cloned directory
101 | cd
102 | # Assign the original repo to a remote called "upstream"
103 | git remote add upstream https://github.com//
104 | ```
105 |
106 | 2. If you cloned a while ago, get the latest changes from upstream:
107 |
108 | ```bash
109 | git checkout develop
110 | git pull upstream develop
111 | ```
112 |
113 | 3. Create a new topic branch (off the main project `develop` branch) to
114 | contain your feature, change, or fix:
115 |
116 | ```bash
117 | git checkout -b
118 | ```
119 |
120 | 4. Commit your changes in logical chunks. Please adhere to these [git commit
121 | message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
122 | or your code is unlikely be merged into the main project. Use Git's
123 | [interactive rebase](https://help.github.com/articles/interactive-rebase)
124 | feature to tidy up your commits before making them public.
125 |
126 | 5. Locally merge (or rebase) the upstream development branch into your topic branch:
127 |
128 | ```bash
129 | git pull [--rebase] upstream develop
130 | ```
131 |
132 | 6. Push your topic branch up to your fork:
133 |
134 | ```bash
135 | git push origin
136 | ```
137 |
138 | 7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/)
139 | with a clear title and description.
140 |
141 | **IMPORTANT**: By submitting a patch, you agree to allow the project owner to
142 | license your work under the same license as that used by the project.
143 |
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net472
5 | Umbraco HQ
6 | Umbraco
7 | Copyright © Umbraco $([System.DateTime]::Today.ToString('yyyy'))
8 | Umbraco Deploy Contrib
9 | https://github.com/umbraco/Umbraco.Deploy.Contrib
10 | https://umbraco.com/dist/nuget/logo-small.png
11 | icon.png
12 | MIT
13 | umbraco deploy contrib
14 | en-US
15 | true
16 | false
17 |
18 |
19 |
20 |
21 | true
22 | true
23 | snupkg
24 |
25 |
26 |
27 |
28 | false
29 |
30 | false
31 | 4.0.0
32 | true
33 | true
34 |
35 |
36 |
37 |
38 | $(MSBuildThisFileDirectory)
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | <_ProjectReferencesWithVersions Condition="'%(ProjectVersion)' != ''">
50 | [%(ProjectVersion), $([MSBuild]::Add($([System.Text.RegularExpressions.Regex]::Match('%(ProjectVersion)', '^\d+').Value), 1)))
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/Directory.Packages.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | true
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright © 2016 Umbraco
4 |
5 | Copyright © 2016 Our Umbraco and other contributors
6 |
7 | Copyright © 2014 Lee Kelleher, Umbrella Inc
8 |
9 | Permission is hereby granted, free of charge, to any person obtaining a copy of
10 | this software and associated documentation files (the "Software"), to deal in
11 | the Software without restriction, including without limitation the rights to
12 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
13 | of the Software, and to permit persons to whom the Software is furnished to do
14 | so, subject to the following conditions:
15 |
16 | The above copyright notice and this permission notice shall be included in all
17 | copies or substantial portions of the Software.
18 |
19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 | SOFTWARE.
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://dev.azure.com/umbraco/Umbraco%20Deploy%20Contrib/_build/latest?definitionId=185&branchName=master-v3) [](https://www.nuget.org/packages/UmbracoDeploy.Contrib)
2 |
3 | # Umbraco Deploy Contrib
4 |
5 | This project contains community contributions for Umbraco Deploy targetted for version 8 and above.
6 |
7 | Primarily this project offers connectors for the most popular Umbraco community packages - these are used by Deploy to aid with the deployment and transferring of content/property-data between environments on [Umbraco Cloud](https://umbraco.com/cloud).
8 |
9 | ## Branching
10 |
11 | The main branches corresponding to the Umbraco and Umbraco Deploy major releases are:
12 |
13 | - Umbraco 8/Deploy 4: `v4/dev`
14 | - Umbraco 9/Deploy 9: `v9/dev`
15 | - Umbraco 10/Deploy 10: `v10/dev`
16 |
17 | ## Connectors
18 |
19 | This project offers Umbraco Deploy connectors for the following community packages:
20 |
21 | - [Doc Type Grid Editor](https://our.umbraco.com/packages/backoffice-extensions/doc-type-grid-editor/)
22 |
23 | Value connectors for certain core property editors are also included:
24 |
25 | - Block List
26 | - Multi URL Picker
27 | - Nested Content
28 |
29 | ---
30 |
31 | ## Getting Started
32 |
33 | ### Installation
34 |
35 | When working with Umbraco 8, you can install the NuGet package using `Install-Package UmbracoDeploy.Contrib`.
36 |
37 | For Umbraco 9+ the package is available for install by: `Install-Package Umbraco.Deploy.Contrib`
38 |
39 | ---
40 | ## Contributing to this project
41 |
42 | Anyone who wishes to get involved with this project is more than welcome to contribute. Please take a moment to review the [guidelines for contributing](CONTRIBUTING.md), this applies for any bug reports, feature requests and pull requests.
43 |
44 | * [Bug reports](CONTRIBUTING.md#bugs)
45 | * [Feature requests](CONTRIBUTING.md#features)
46 | * [Pull requests](CONTRIBUTING.md#pull-requests)
47 |
48 |
49 | ### Issues
50 |
51 | We encourage you to report any issues you might find with these connectors, so we can have them fixed for everyone!
52 |
53 | When reporting issues with a connector it will help us a whole lot if you can reduce your report to being the absolute minimum required to encounter the error you are seeing.
54 |
55 | This means try removing anything unnecessary or unrelated to the actual issue, from your setup and also try reducing the steps to reproduce, to only cover exactly what we would need to do in order to see the error you are getting.
56 |
57 | Please use the [Umbraco Deploy Issue Tracker (for both Deploy and Deploy.Contrib)](https://github.com/umbraco/Umbraco.Deploy.Issues/issues).
58 |
59 | ## Credits
60 |
61 | Special thanks to the following community members for assisting on this project.
62 |
63 | * [Umbrella](https://github.com/UmbrellaInc) and [Lee Kelleher](https://github.com/leekelleher)
64 | * [Matt Brailsford](https://github.com/mattbrailsford)
65 |
66 | ## License
67 |
68 | Copyright © 2016 Umbraco
69 |
70 | Copyright © 2016 Our Umbraco and [other contributors](https://github.com/umbraco/Umbraco.Deploy.Contrib/graphs/contributors)
71 |
72 | Copyright © 2014 Lee Kelleher, Umbrella Inc
73 |
74 | Licensed under the [MIT License](LICENSE.md)
75 |
--------------------------------------------------------------------------------
/Umbraco.Deploy.Contrib.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.8.34330.188
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Deploy.Contrib", "src\Umbraco.Deploy.Contrib\Umbraco.Deploy.Contrib.csproj", "{42FB2213-0815-41CD-94F8-DFB0EC1D8061}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Deploy.Contrib.Tests", "tests\Umbraco.Deploy.Contrib.Tests\Umbraco.Deploy.Contrib.Tests.csproj", "{48B09241-9C44-47EF-B4DF-397B39A631DC}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7AF3C28D-DBD0-4771-9A78-D6E982094DCC}"
11 | ProjectSection(SolutionItems) = preProject
12 | .artifactignore = .artifactignore
13 | .editorconfig = .editorconfig
14 | .gitattributes = .gitattributes
15 | .gitignore = .gitignore
16 | .globalconfig = .globalconfig
17 | azure-pipelines.yml = azure-pipelines.yml
18 | CONTRIBUTING.md = CONTRIBUTING.md
19 | Directory.Build.props = Directory.Build.props
20 | Directory.Packages.props = Directory.Packages.props
21 | global.json = global.json
22 | icon.png = icon.png
23 | LICENSE.md = LICENSE.md
24 | nuget.config = nuget.config
25 | README.md = README.md
26 | version.json = version.json
27 | EndProjectSection
28 | EndProject
29 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{71D68BC9-0940-4644-8342-4806401B4ACD}"
30 | ProjectSection(SolutionItems) = preProject
31 | tests\.editorconfig = tests\.editorconfig
32 | tests\codeanalysis.ruleset = tests\codeanalysis.ruleset
33 | tests\Directory.Build.props = tests\Directory.Build.props
34 | tests\Directory.Packages.props = tests\Directory.Packages.props
35 | EndProjectSection
36 | EndProject
37 | Global
38 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
39 | Debug|Any CPU = Debug|Any CPU
40 | Release|Any CPU = Release|Any CPU
41 | EndGlobalSection
42 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
43 | {42FB2213-0815-41CD-94F8-DFB0EC1D8061}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
44 | {42FB2213-0815-41CD-94F8-DFB0EC1D8061}.Debug|Any CPU.Build.0 = Debug|Any CPU
45 | {42FB2213-0815-41CD-94F8-DFB0EC1D8061}.Release|Any CPU.ActiveCfg = Release|Any CPU
46 | {42FB2213-0815-41CD-94F8-DFB0EC1D8061}.Release|Any CPU.Build.0 = Release|Any CPU
47 | {48B09241-9C44-47EF-B4DF-397B39A631DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
48 | {48B09241-9C44-47EF-B4DF-397B39A631DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
49 | {48B09241-9C44-47EF-B4DF-397B39A631DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
50 | {48B09241-9C44-47EF-B4DF-397B39A631DC}.Release|Any CPU.Build.0 = Release|Any CPU
51 | EndGlobalSection
52 | GlobalSection(SolutionProperties) = preSolution
53 | HideSolutionNode = FALSE
54 | EndGlobalSection
55 | GlobalSection(NestedProjects) = preSolution
56 | {48B09241-9C44-47EF-B4DF-397B39A631DC} = {71D68BC9-0940-4644-8342-4806401B4ACD}
57 | EndGlobalSection
58 | GlobalSection(ExtensibilityGlobals) = postSolution
59 | SolutionGuid = {20357E31-FA18-4D77-B38B-6C878A179849}
60 | EndGlobalSection
61 | EndGlobal
62 |
--------------------------------------------------------------------------------
/azure-pipelines.yml:
--------------------------------------------------------------------------------
1 | trigger:
2 | branches:
3 | include:
4 | - 'v2/*'
5 | - 'v3/*'
6 | - 'v4/*'
7 | tags:
8 | include:
9 | - release-2.*
10 | - release-3.*
11 | - release-4.*
12 |
13 | pr:
14 | branches:
15 | include:
16 | - 'v2/*'
17 | - 'v3/*'
18 | - 'v4/*'
19 |
20 | parameters:
21 | - name: cache_nuget
22 | displayName: Cache NuGet packages
23 | type: boolean
24 | default: false # As long as we're overwriting versions on MyGet, we can't cache NuGet packages by default
25 | - name: release_myget
26 | displayName: Release to pre-release/nightly MyGet feed
27 | type: boolean
28 | default: false
29 | - name: release_myget_nightly
30 | displayName: Release to nightly MyGet feed (instead of pre-release)
31 | type: boolean
32 | default: false
33 | - name: release_nuget
34 | displayName: Release to public NuGet feed
35 | type: boolean
36 | default: false
37 |
38 | variables:
39 | solution: Umbraco.Deploy.Contrib.sln
40 | buildConfiguration: Release
41 | DOTNET_NOLOGO: true
42 | DOTNET_GENERATE_ASPNET_CERTIFICATE: false
43 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
44 | DOTNET_CLI_TELEMETRY_OPTOUT: true
45 |
46 | stages:
47 | - stage: Build
48 | variables:
49 | NUGET_PACKAGES: $(Pipeline.Workspace)/.nuget/packages
50 | jobs:
51 | - job: Build
52 | pool:
53 | vmImage: 'windows-latest' # Required for .NET Framework projects
54 | steps:
55 | # Checkout source (avoid shallow clone to calculate version height)
56 | - checkout: self
57 | fetchDepth: 0
58 |
59 | # Setup build environment
60 | - task: UseDotNet@2
61 | displayName: Use .NET SDK from global.json
62 | inputs:
63 | useGlobalJson: true
64 |
65 | # Cache and restore NuGet packages
66 | - task: Cache@2
67 | condition: ${{ parameters.cache_nuget }}
68 | displayName: Cache NuGet packages
69 | inputs:
70 | key: 'nuget | "$(Agent.OS)" | **/packages.lock.json, !**/bin/**, !**/obj/**'
71 | restoreKeys: |
72 | nuget | "$(Agent.OS)"
73 | nuget
74 | path: $(NUGET_PACKAGES)
75 |
76 | - script: dotnet restore $(solution) --locked-mode
77 | displayName: Restore NuGet packages
78 |
79 | # Build
80 | - script: dotnet build $(solution) --configuration $(buildConfiguration) --no-restore -p:ContinuousIntegrationBuild=true
81 | displayName: Run dotnet build
82 | name: build
83 |
84 | # Pack
85 | - script: dotnet pack $(solution) --configuration $(buildConfiguration) --no-build --output $(Build.ArtifactStagingDirectory)/nupkg
86 | displayName: Run dotnet pack
87 |
88 | # Publish
89 | - task: PublishPipelineArtifact@1
90 | displayName: Publish NuGet packages
91 | inputs:
92 | targetPath: $(Build.ArtifactStagingDirectory)/nupkg
93 | artifactName: nupkg
94 |
95 | - task: PublishPipelineArtifact@1
96 | displayName: Publish build output
97 | inputs:
98 | targetPath: $(Build.SourcesDirectory)
99 | artifactName: build_output
100 |
101 | - stage: Test
102 | dependsOn: Build
103 | jobs:
104 | - job: UnitTests
105 | displayName: Unit Tests
106 | pool:
107 | vmImage: 'windows-latest'
108 | steps:
109 | # Setup test environment
110 | - task: DownloadPipelineArtifact@2
111 | displayName: Download build artifacts
112 | inputs:
113 | artifact: build_output
114 | path: $(Build.SourcesDirectory)
115 |
116 | - task: UseDotNet@2
117 | displayName: Use .NET SDK from global.json
118 | inputs:
119 | useGlobalJson: true
120 |
121 | # Test
122 | - script: dotnet test $(solution) --configuration $(buildConfiguration) --no-build --logger trx --results-directory $(Build.ArtifactStagingDirectory)/tests
123 | displayName: Run dotnet test
124 |
125 | # Publish
126 | - task: PublishTestResults@2
127 | displayName: Publish test results
128 | condition: succeededOrFailed()
129 | inputs:
130 | testResultsFormat: VSTest
131 | testResultsFiles: '*.trx'
132 | searchFolder: $(Build.ArtifactStagingDirectory)/tests
133 | testRunTitle: Unit Tests
134 | configuration: $(buildConfiguration)
135 |
136 | - stage: ReleaseMyGet
137 | displayName: MyGet release
138 | dependsOn: Test
139 | condition: and(succeeded(), or(eq(dependencies.Build.outputs['Build.build.NBGV_PublicRelease'], 'True'), ${{ parameters.release_myget }}))
140 | jobs:
141 | - job:
142 | displayName: Release to pre-release/nightly MyGet feed
143 | steps:
144 | - checkout: none
145 | - task: DownloadPipelineArtifact@2
146 | displayName: Download nupkg
147 | inputs:
148 | artifact: nupkg
149 | path: $(Build.ArtifactStagingDirectory)/nupkg
150 | - task: NuGetCommand@2
151 | displayName: NuGet push
152 | inputs:
153 | command: 'push'
154 | packagesToPush: $(Build.ArtifactStagingDirectory)/nupkg/*.nupkg
155 | nuGetFeedType: 'external'
156 | ${{ if eq(parameters.release_myget_nightly, true) }}:
157 | publishFeedCredentials: 'MyGet - Nightly'
158 | ${{ else }}:
159 | publishFeedCredentials: 'MyGet - Pre-releases'
160 |
161 | - stage: ReleaseNuGet
162 | displayName: NuGet release
163 | dependsOn: ReleaseMyGet
164 | condition: and(succeeded(), or(eq(dependencies.Build.outputs['Build.build.NBGV_PublicRelease'], 'True'), ${{ parameters.release_nuget }}))
165 | jobs:
166 | - job:
167 | displayName: Release to public NuGet feed
168 | steps:
169 | - checkout: none
170 | - task: DownloadPipelineArtifact@2
171 | displayName: Download nupkg
172 | inputs:
173 | artifact: nupkg
174 | path: $(Build.ArtifactStagingDirectory)/nupkg
175 | - task: NuGetCommand@2
176 | displayName: NuGet push
177 | inputs:
178 | command: 'push'
179 | packagesToPush: $(Build.ArtifactStagingDirectory)/nupkg/*.nupkg
180 | nuGetFeedType: 'external'
181 | publishFeedCredentials: 'NuGet'
182 |
--------------------------------------------------------------------------------
/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "sdk": {
3 | "version": "8.0.100",
4 | "rollForward": "latestFeature"
5 | }
6 | }
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umbraco/Umbraco.Deploy.Contrib/6c27f514aca2300704315178bfe5e9ca772c0c3c/icon.png
--------------------------------------------------------------------------------
/nuget.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/DataTypeConfigurationConnectors/DocTypeGridEditorDataTypeConfigurationConnector.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text.RegularExpressions;
5 | using Newtonsoft.Json;
6 | using Newtonsoft.Json.Linq;
7 | using Umbraco.Core;
8 | using Umbraco.Core.Configuration.Grid;
9 | using Umbraco.Core.Deploy;
10 | using Umbraco.Core.Models;
11 | using Umbraco.Core.Services;
12 | using Umbraco.Deploy.Connectors.DataTypeConfigurationConnectors;
13 | using Umbraco.Deploy.Core;
14 | using Umbraco.Web.PropertyEditors;
15 |
16 | namespace Umbraco.Deploy.Contrib.DataTypeConfigurationConnectors
17 | {
18 | ///
19 | /// Implements a Grid layout data type configuration connector supporting DocTypeGridEditor.
20 | ///
21 | public class DocTypeGridEditorDataTypeConfigurationConnector : DataTypeConfigurationConnectorBase2
22 | {
23 | private readonly IGridConfig _gridConfig;
24 | private readonly IContentTypeService _contentTypeService;
25 |
26 | ///
27 | public override IEnumerable PropertyEditorAliases { get; } = new[]
28 | {
29 | Constants.PropertyEditors.Aliases.Grid
30 | };
31 |
32 | ///
33 | /// Initializes a new instance of the class.
34 | ///
35 | /// The grid configuration.
36 | /// The content type service.
37 | public DocTypeGridEditorDataTypeConfigurationConnector(IGridConfig gridConfig, IContentTypeService contentTypeService)
38 | {
39 | _gridConfig = gridConfig;
40 | _contentTypeService = contentTypeService;
41 | }
42 |
43 | ///
44 | public override string ToArtifact(IDataType dataType, ICollection dependencies, IContextCache contextCache)
45 | {
46 | if (dataType.ConfigurationAs() is GridConfiguration gridConfiguration &&
47 | gridConfiguration.Items?.ToObject() is GridConfigurationItems gridConfigurationItems)
48 | {
49 | // Get all element types (when needed)
50 | var allElementTypes = new Lazy>(() => _contentTypeService.GetAll().Where(x => x.IsElement).ToList());
51 |
52 | // Process DTGE editors
53 | foreach (var gridEditor in GetGridEditors(gridConfigurationItems).Where(IsDocTypeGridEditor))
54 | {
55 | if (gridEditor.Config.TryGetValue("allowedDocTypes", out var allowedDocTypesConfig) &&
56 | allowedDocTypesConfig is JArray allowedDocTypes &&
57 | allowedDocTypes.Count > 0)
58 | {
59 | string[] docTypes = allowedDocTypes.Values().WhereNotNull().ToArray();
60 |
61 | // Use regex matching
62 | AddDependencies(dependencies, allElementTypes.Value.Where(x => docTypes.Any(y => Regex.IsMatch(x.Alias, y))));
63 | }
64 | else
65 | {
66 | // Add all element types as dependencies and stop processing
67 | AddDependencies(dependencies, allElementTypes.Value);
68 | break;
69 | }
70 | }
71 | }
72 |
73 | return base.ToArtifact(dataType, dependencies, contextCache);
74 | }
75 |
76 | private static void AddDependencies(ICollection dependencies, IEnumerable contentTypes)
77 | {
78 | foreach (var contentType in contentTypes)
79 | {
80 | dependencies.Add(new ArtifactDependency(contentType.GetUdi(), true, ArtifactDependencyMode.Exist));
81 | }
82 | }
83 |
84 | ///
85 | /// Gets the grid editors used within the grid configuration.
86 | ///
87 | /// The grid configuration items.
88 | ///
89 | /// The used grid editors (returns all editors if any of the areas allows all editors).
90 | ///
91 | protected virtual IEnumerable GetGridEditors(GridConfigurationItems gridConfigurationItems)
92 | {
93 | foreach (var gridEditor in _gridConfig.EditorsConfig.Editors)
94 | {
95 | if (IsAllowedGridEditor(gridConfigurationItems, gridEditor.Alias))
96 | {
97 | yield return gridEditor;
98 | }
99 | }
100 | }
101 |
102 | ///
103 | /// Determines whether the grid editor alias is allowed in the specified grid configuration.
104 | ///
105 | /// The grid configuration items.
106 | /// The alias.
107 | ///
108 | /// true if the grid editor alias is allowed in the specified grid configuration; otherwise, false.
109 | ///
110 | protected static bool IsAllowedGridEditor(GridConfigurationItems gridConfigurationItems, string alias)
111 | => gridConfigurationItems.Layouts.Any(x => x.Areas.Any(y => y.AllowAll || y.Allowed.Contains(alias)));
112 |
113 | ///
114 | /// Determines whether the grid editor is the DTGE.
115 | ///
116 | /// The grid editor.
117 | ///
118 | /// true if the grid editor is the DTGE; otherwise, false.
119 | ///
120 | protected static bool IsDocTypeGridEditor(IGridEditorConfig gridEditor)
121 | => !string.IsNullOrEmpty(gridEditor.View) && gridEditor.View.Contains("doctypegrideditor");
122 |
123 | ///
124 | /// The grid configuration items.
125 | ///
126 | protected sealed class GridConfigurationItems
127 | {
128 | ///
129 | /// Gets or sets the row configurations.
130 | ///
131 | ///
132 | /// The row configurations.
133 | ///
134 | [JsonProperty("layouts")]
135 | public GridConfigurationLayout[] Layouts { get; set; } = Array.Empty();
136 | }
137 |
138 | ///
139 | /// The grid row configuration.
140 | ///
141 | protected sealed class GridConfigurationLayout
142 | {
143 | ///
144 | /// Gets or sets the areas.
145 | ///
146 | ///
147 | /// The areas.
148 | ///
149 | [JsonProperty("areas")]
150 | public GridConfigurationLayoutArea[] Areas { get; set; } = Array.Empty();
151 | }
152 |
153 | ///
154 | /// The grid row configuration area.
155 | ///
156 | protected sealed class GridConfigurationLayoutArea
157 | {
158 | ///
159 | /// Gets or sets a value indicating whether all grid editors are allowed.
160 | ///
161 | ///
162 | /// true if all grid editors are allowed; otherwise, false.
163 | ///
164 | ///
165 | /// Defaults to true.
166 | ///
167 | [JsonProperty("allowAll")]
168 | public bool AllowAll { get; set; } = true;
169 |
170 | ///
171 | /// Gets or sets the allowed grid editor aliases.
172 | ///
173 | ///
174 | /// The allowed grid editor aliases.
175 | ///
176 | [JsonProperty("allowed")]
177 | public string[] Allowed { get; set; } = Array.Empty();
178 | }
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Extensions/ArtifactMigratorCollectionBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | using Umbraco.Deploy.Contrib.Migrators.Legacy;
2 | using Umbraco.Deploy.Migrators;
3 |
4 | namespace Umbraco.Extensions
5 | {
6 | public static class ArtifactMigratorCollectionBuilderExtensions
7 | {
8 | ///
9 | /// Adds the legacy artifact migrators to allow importing from Umbraco 7.
10 | ///
11 | /// The artifact migrator collection builder.
12 | ///
13 | /// The artifact migrator collection builder.
14 | ///
15 | public static ArtifactMigratorCollectionBuilder AddLegacyMigrators(this ArtifactMigratorCollectionBuilder artifactMigratorCollectionBuilder)
16 | => artifactMigratorCollectionBuilder
17 | // Pre-values to configuration
18 | .Append()
19 | // Release/expire dates to schedule
20 | .Append()
21 | // Allowed at root and child content types to permissions
22 | .Append()
23 | // Data types
24 | .Append()
25 | .Append()
26 | .Append()
27 | .Append()
28 | .Append()
29 | .Append()
30 | .Append()
31 | .Append()
32 | .Append()
33 | .Append()
34 | .Append()
35 | .Append()
36 | .Append()
37 | .Append()
38 | .Append()
39 | .Append()
40 | .Append()
41 | .Append()
42 | .Append()
43 | .Append()
44 | .Append()
45 | .Append()
46 | .Append()
47 | // Property values
48 | .Append()
49 | .Append()
50 | .Append();
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Extensions/ArtifactTypeResolverCollectionBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | using Umbraco.Deploy.Contrib.Connectors.Serialization;
2 | using Umbraco.Deploy.Serialization;
3 |
4 | namespace Umbraco.Extensions
5 | {
6 | public static class ArtifactTypeResolverCollectionBuilderExtensions
7 | {
8 | ///
9 | /// Adds the legacy artifact type resolver to allow importing from Umbraco 7.
10 | ///
11 | /// The artifact type resolver collection builder.
12 | ///
13 | /// The artifact type resolver collection builder.
14 | ///
15 | public static ArtifactTypeResolverCollectionBuilder AddLegacyTypeResolver(this ArtifactTypeResolverCollectionBuilder artifactTypeResolverCollectionBuilder)
16 | => artifactTypeResolverCollectionBuilder.Append();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/GridCellValueConnectors/DocTypeGridEditorCellValueConnector.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Newtonsoft.Json;
4 | using Newtonsoft.Json.Linq;
5 | using Umbraco.Core;
6 | using Umbraco.Core.Composing;
7 | using Umbraco.Core.Deploy;
8 | using Umbraco.Core.Logging;
9 | using Umbraco.Core.Models;
10 | using Umbraco.Core.Services;
11 | using Umbraco.Deploy.Connectors;
12 | using Umbraco.Deploy.Connectors.GridCellValueConnectors;
13 | using Umbraco.Deploy.Connectors.ValueConnectors.Services;
14 | using Umbraco.Deploy.Core;
15 | using Umbraco.Deploy.Extensions;
16 |
17 | namespace Umbraco.Deploy.Contrib.Connectors.GridCellValueConnectors
18 | {
19 | public class DocTypeGridEditorCellValueConnector : GridCellValueConnectorBase2
20 | {
21 | private readonly ILogger _logger;
22 | private readonly IContentTypeService _contentTypeService;
23 | private readonly Lazy _valueConnectorsLazy;
24 |
25 | private ValueConnectorCollection ValueConnectors => _valueConnectorsLazy.Value;
26 |
27 | [Obsolete("Please use the constructor taking all parameters. This constructor will be removed in a future version.")]
28 | public DocTypeGridEditorCellValueConnector(ILogger logger, IContentTypeService contentTypeService, Lazy valueConnectors)
29 | : this(
30 | Current.Factory.GetInstance(),
31 | Current.Factory.GetInstance(),
32 | logger,
33 | contentTypeService,
34 | valueConnectors)
35 | { }
36 |
37 | public DocTypeGridEditorCellValueConnector(IEntityService entityService, ILocalLinkParser localLinkParser, ILogger logger, IContentTypeService contentTypeService, Lazy valueConnectors)
38 | : base(entityService, localLinkParser)
39 | {
40 | _logger = logger ?? throw new ArgumentNullException(nameof(logger));
41 | _contentTypeService = contentTypeService ?? throw new ArgumentNullException(nameof(contentTypeService));
42 | _valueConnectorsLazy = valueConnectors ?? throw new ArgumentNullException(nameof(valueConnectors));
43 | }
44 |
45 | public sealed override bool IsConnector(string view)
46 | => !string.IsNullOrWhiteSpace(view) && view.Contains("doctypegrideditor");
47 |
48 | public sealed override string GetValue(GridValue.GridControl gridControl, ICollection dependencies, IContextCache contextCache)
49 | {
50 | // cancel if there's no values
51 | if (gridControl.Value == null || gridControl.Value.HasValues == false)
52 | {
53 | return null;
54 | }
55 |
56 | _logger.Debug($"GetValue - Grid Values: {gridControl.Value}");
57 |
58 | var docTypeGridEditorContent = JsonConvert.DeserializeObject(gridControl.Value.ToString());
59 |
60 | // if an 'empty' dtge item has been added - it has no ContentTypeAlias set .. just return and don't throw.
61 | if (docTypeGridEditorContent == null || string.IsNullOrWhiteSpace(docTypeGridEditorContent.ContentTypeAlias))
62 | {
63 | _logger.Debug("GetValue - DTGE Empty without ContentTypeAlias");
64 | return null;
65 | }
66 |
67 | _logger.Debug($"GetValue - ContentTypeAlias - {docTypeGridEditorContent.ContentTypeAlias}");
68 |
69 | // check if the doc type exist - else abort packaging
70 | var contentType = contextCache.GetContentTypeByAlias(_contentTypeService, docTypeGridEditorContent.ContentTypeAlias);
71 | if (contentType == null)
72 | {
73 | _logger.Debug("GetValue - Missing ContentType");
74 | throw new InvalidOperationException($"Could not resolve the Content Type for the Doc Type Grid Editor property: {docTypeGridEditorContent.ContentTypeAlias}");
75 | }
76 |
77 | // add content type as a dependency
78 | dependencies.Add(new ArtifactDependency(contentType.GetUdi(), false, ArtifactDependencyMode.Match));
79 |
80 | // find all properties
81 | var propertyTypes = contentType.CompositionPropertyTypes;
82 |
83 | foreach (var propertyType in propertyTypes)
84 | {
85 | _logger.Debug($"GetValue - PropertyTypeAlias - {propertyType.Alias}");
86 |
87 | // test if there's a value for the given property
88 | if (!TryGetValue(docTypeGridEditorContent, propertyType, out var value))
89 | {
90 | continue;
91 | }
92 |
93 | // if the value is an Udi then add it as a dependency
94 | if (AddUdiDependency(dependencies, value))
95 | {
96 | continue;
97 | }
98 |
99 | // throws if not found - no need for a null check
100 | var propValueConnector = ValueConnectors.Get(propertyType);
101 |
102 | _logger.Debug($"GetValue - PropertyValueConnectorAlias - {string.Join(", ", propValueConnector.PropertyEditorAliases)}");
103 | _logger.Debug($"GetValue - propertyTypeValue - {value}");
104 |
105 | //properties like MUP / Nested Content are JSON, we need to convert to string for the conversion to artifact
106 | string parsedValue = propValueConnector.ToArtifact(value != null && value.ToString().TryParseJson(out JToken _) ? value.ToString() : value, propertyType, dependencies, contextCache);
107 |
108 | _logger.Debug($"GetValue - ParsedValue - {parsedValue}");
109 |
110 | docTypeGridEditorContent.Value[propertyType.Alias] = parsedValue;
111 | }
112 |
113 | var resolvedValue = JsonConvert.SerializeObject(docTypeGridEditorContent, Formatting.None);
114 |
115 | _logger.Debug($"GetValue - ResolvedValue - {resolvedValue}");
116 |
117 | return resolvedValue;
118 | }
119 |
120 | public sealed override void SetValue(GridValue.GridControl gridControl, IContextCache contextCache)
121 | {
122 | // cancel if there's no values
123 | if (string.IsNullOrWhiteSpace(gridControl.Value.ToString()))
124 | {
125 | return;
126 | }
127 |
128 | // For some reason the control value isn't properly parsed so we need this extra step to parse it into a JToken
129 | gridControl.Value = JToken.Parse(gridControl.Value.ToString());
130 |
131 | _logger.Debug($"SetValue - GridControlValue - {gridControl.Value}");
132 |
133 | var docTypeGridEditorContent = JsonConvert.DeserializeObject(gridControl.Value.ToString());
134 | if (docTypeGridEditorContent == null)
135 | {
136 | return;
137 | }
138 |
139 | _logger.Debug($"SetValue - ContentTypeAlias - {docTypeGridEditorContent.ContentTypeAlias}");
140 |
141 | // check if the doc type exist - else abort packaging
142 | var contentType = contextCache.GetContentTypeByAlias(_contentTypeService, docTypeGridEditorContent.ContentTypeAlias)
143 | ?? throw new InvalidOperationException($"Could not resolve the Content Type for the Doc Type Grid Editor property: {docTypeGridEditorContent.ContentTypeAlias}");
144 |
145 | _logger.Debug($"SetValue - ContentType - {contentType}");
146 |
147 | // find all properties
148 | var propertyTypes = contentType.CompositionPropertyTypes;
149 |
150 | foreach (var propertyType in propertyTypes)
151 | {
152 | _logger.Debug($"SetValue - PropertyEditorAlias -- {propertyType.PropertyEditorAlias}");
153 |
154 | if (!docTypeGridEditorContent.Value.TryGetValue(propertyType.Alias, out object value) || value == null)
155 | {
156 | _logger.Debug("SetValue - Value Is Null");
157 | continue;
158 | }
159 |
160 | // throws if not found - no need for a null check
161 | var propValueConnector = ValueConnectors.Get(propertyType);
162 | var convertedValue = propValueConnector.FromArtifact(value.ToString(), propertyType, string.Empty, contextCache);
163 |
164 | // test if the value is a json object (thus could be a nested complex editor)
165 | // if that's the case we'll need to add it as a json object instead of string to avoid it being escaped
166 | if (convertedValue != null && convertedValue.ToString().TryParseJson(out JToken jtokenValue))
167 | {
168 | _logger.Debug($"SetValue - jtokenValue - {jtokenValue}");
169 | docTypeGridEditorContent.Value[propertyType.Alias] = jtokenValue;
170 | }
171 | else
172 | {
173 | _logger.Debug($"SetValue - convertedValue - {convertedValue}");
174 | docTypeGridEditorContent.Value[propertyType.Alias] = convertedValue;
175 | }
176 | }
177 |
178 | var jtokenObj = JToken.FromObject(docTypeGridEditorContent);
179 | _logger.Debug($"SetValue - jtokenObject - {jtokenObj}");
180 | gridControl.Value = jtokenObj;
181 | }
182 |
183 | private bool AddUdiDependency(ICollection dependencies, object value)
184 | {
185 | if (Udi.TryParse(value.ToString(), out var udi))
186 | {
187 | _logger.Debug($"GetValue - Udi Dependency - {udi}");
188 | dependencies.Add(new ArtifactDependency(udi, false, ArtifactDependencyMode.Match));
189 | return true;
190 | }
191 |
192 | return false;
193 | }
194 |
195 | private bool TryGetValue(DocTypeGridEditorValue docTypeGridEditorContent, PropertyType propertyType, out object objVal)
196 | {
197 | if (!docTypeGridEditorContent.Value.TryGetValue(propertyType.Alias, out objVal) || objVal == null)
198 | {
199 | _logger.Debug("GetValue - Value is null");
200 | return false;
201 | }
202 |
203 | return true;
204 | }
205 |
206 | private class DocTypeGridEditorValue
207 | {
208 | [JsonProperty("id")]
209 | public Guid Id { get; set; }
210 |
211 | [JsonProperty("dtgeContentTypeAlias")]
212 | public string ContentTypeAlias { get; set; }
213 |
214 | [JsonProperty("value")]
215 | public Dictionary Value { get; set; }
216 | }
217 | }
218 | }
219 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/Content/CheckBoxListPropertyValueArtifactMigrator.cs:
--------------------------------------------------------------------------------
1 | using Umbraco.Core;
2 | using Umbraco.Core.Services;
3 | using Umbraco.Deploy.Artifacts.Content;
4 | using Umbraco.Deploy.Connectors.ServiceConnectors.Wrappers;
5 |
6 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
7 | {
8 | ///
9 | /// Migrates the using the editor from the containing prevalues (seperated by ) from Umbraco 7 to a JSON array.
10 | ///
11 | public class CheckBoxListPropertyValueArtifactMigrator : PrevaluePropertyValueArtifactMigratorBase
12 | {
13 | ///
14 | protected override bool Multiple => true;
15 |
16 | ///
17 | /// Initializes a new instance of the class.
18 | ///
19 | /// The content type service.
20 | /// The media type service.
21 | /// The member type service.
22 | public CheckBoxListPropertyValueArtifactMigrator(IContentTypeService contentTypeService, IMediaTypeService mediaTypeService, IMemberTypeService memberTypeService)
23 | : base(Constants.PropertyEditors.Aliases.CheckBoxList, contentTypeService, mediaTypeService, memberTypeService)
24 | { }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/Content/DocumentArtifactJsonMigrator.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json.Linq;
2 | using Semver;
3 | using Umbraco.Core.Models;
4 | using Umbraco.Deploy.Artifacts.Content;
5 | using Umbraco.Deploy.Migrators;
6 |
7 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
8 | {
9 | ///
10 | /// Migrates the JSON from Umbraco 7 release/expire date to schedule.
11 | ///
12 | public class DocumentArtifactJsonMigrator : ArtifactJsonMigratorBase
13 | {
14 | ///
15 | /// Initializes a new instance of the class.
16 | ///
17 | public DocumentArtifactJsonMigrator()
18 | => MaxVersion = new SemVersion(3, 0, 0);
19 |
20 | ///
21 | public override JToken Migrate(JToken artifactJson)
22 | {
23 | var schedule = new JArray();
24 |
25 | if (artifactJson["ReleaseDate"] is JValue releaseDate &&
26 | releaseDate.Value != null)
27 | {
28 | schedule.Add(new JObject()
29 | {
30 | ["Date"] = releaseDate.Value(),
31 | ["Culture"] = string.Empty,
32 | ["Action"] = nameof(ContentScheduleAction.Release)
33 | });
34 | }
35 |
36 | if (artifactJson["ExpireDate"] is JValue expireDate &&
37 | expireDate.Value != null)
38 | {
39 | schedule.Add(new JObject()
40 | {
41 | ["Date"] = expireDate,
42 | ["Culture"] = string.Empty,
43 | ["Action"] = nameof(ContentScheduleAction.Expire)
44 | });
45 | }
46 |
47 | artifactJson["Schedule"] = schedule;
48 |
49 | return artifactJson;
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/Content/DropDownListFlexiblePropertyValueArtifactMigrator.cs:
--------------------------------------------------------------------------------
1 | using Umbraco.Core;
2 | using Umbraco.Core.Services;
3 | using Umbraco.Deploy.Artifacts.Content;
4 | using Umbraco.Deploy.Connectors.ServiceConnectors.Wrappers;
5 |
6 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
7 | {
8 | ///
9 | /// Migrates the using the editor from the containing prevalues (seperated by ) from Umbraco 7 to a JSON array.
10 | ///
11 | public class DropDownListFlexiblePropertyValueArtifactMigrator : PrevaluePropertyValueArtifactMigratorBase
12 | {
13 | ///
14 | protected override bool Multiple => true;
15 |
16 | ///
17 | /// Initializes a new instance of the class.
18 | ///
19 | /// The content type service.
20 | /// The media type service.
21 | /// The member type service.
22 | public DropDownListFlexiblePropertyValueArtifactMigrator(IContentTypeService contentTypeService, IMediaTypeService mediaTypeService, IMemberTypeService memberTypeService)
23 | : base(Constants.PropertyEditors.Aliases.DropDownListFlexible, contentTypeService, mediaTypeService, memberTypeService)
24 | { }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/Content/PrevaluePropertyValueArtifactMigratorBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Newtonsoft.Json;
3 | using Semver;
4 | using Umbraco.Core.Services;
5 | using Umbraco.Deploy.Artifacts.Content;
6 | using Umbraco.Deploy.Connectors.ServiceConnectors.Wrappers;
7 | using Umbraco.Deploy.Migrators;
8 |
9 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
10 | {
11 | ///
12 | /// Migrates the using the specified editor alias from the containing prevalues (seperated by ) from Umbraco 7 to a single value or JSON array.
13 | ///
14 | public abstract class PrevaluePropertyValueArtifactMigratorBase : PropertyValueArtifactMigratorBase
15 | {
16 | private const string Delimiter = ";;";
17 |
18 | ///
19 | /// Gets a value indicating whether the property stored multiple prevalues as a JSON array or single value.
20 | ///
21 | ///
22 | /// true if multiple prevalues are stored as a JSON array; otherwise, false.
23 | ///
24 | protected abstract bool Multiple { get; }
25 |
26 | ///
27 | /// Initializes a new instance of the class.
28 | ///
29 | /// The editor alias.
30 | /// The content type service.
31 | /// The media type service.
32 | /// The member type service.
33 | public PrevaluePropertyValueArtifactMigratorBase(string editorAlias, IContentTypeService contentTypeService, IMediaTypeService mediaTypeService, IMemberTypeService memberTypeService)
34 | : base(editorAlias, contentTypeService, mediaTypeService, memberTypeService)
35 | => MaxVersion = new SemVersion(3, 0, 0);
36 |
37 | ///
38 | protected override string Migrate(string value)
39 | {
40 | var values = value?.Split(new[] { Delimiter }, StringSplitOptions.RemoveEmptyEntries);
41 | if (values == null || values.Length == 0)
42 | {
43 | return null;
44 | }
45 |
46 | return Multiple
47 | ? JsonConvert.SerializeObject(values)
48 | : values[0];
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/Content/RadioButtonListPropertyValueArtifactMigrator.cs:
--------------------------------------------------------------------------------
1 | using Umbraco.Core;
2 | using Umbraco.Core.Services;
3 | using Umbraco.Deploy.Artifacts.Content;
4 | using Umbraco.Deploy.Connectors.ServiceConnectors.Wrappers;
5 |
6 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
7 | {
8 | ///
9 | /// Migrates the using the editor from the containing prevalues (seperated by ) from Umbraco 7 to a JSON array.
10 | ///
11 | public class RadioButtonListPropertyValueArtifactMigrator : PrevaluePropertyValueArtifactMigratorBase
12 | {
13 | ///
14 | protected override bool Multiple => false;
15 |
16 | ///
17 | /// Initializes a new instance of the class.
18 | ///
19 | /// The content type service.
20 | /// The media type service.
21 | /// The member type service.
22 | public RadioButtonListPropertyValueArtifactMigrator(IContentTypeService contentTypeService, IMediaTypeService mediaTypeService, IMemberTypeService memberTypeService)
23 | : base(Constants.PropertyEditors.Aliases.RadioButtonList, contentTypeService, mediaTypeService, memberTypeService)
24 | { }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/ContentType/ContentTypeArtifactJsonMigrator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Newtonsoft.Json.Linq;
3 | using Semver;
4 | using Umbraco.Core;
5 | using Umbraco.Deploy.Artifacts.ContentType;
6 | using Umbraco.Deploy.Migrators;
7 |
8 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
9 | {
10 | ///
11 | /// Migrates the JSON from Umbraco 7 allowed at root and child content types to permissions.
12 | ///
13 | public class ContentTypeArtifactJsonMigrator : ArtifactJsonMigratorBase
14 | {
15 | ///
16 | /// Initializes a new instance of the class.
17 | ///
18 | public ContentTypeArtifactJsonMigrator()
19 | => MaxVersion = new SemVersion(3, 0, 0);
20 |
21 | protected override bool CanMigrateType(Type type)
22 | => type.Inherits();
23 |
24 | ///
25 | public override JToken Migrate(JToken artifactJson)
26 | {
27 | var permissions = new JObject();
28 |
29 | if (artifactJson["AllowedAtRoot"] is JValue allowedAtRootValue &&
30 | allowedAtRootValue.Value != null)
31 | {
32 | permissions["AllowedAtRoot"] = allowedAtRootValue;
33 | }
34 |
35 | if (artifactJson["AllowedChildContentTypes"] is JArray allowedChildContentTypesToken)
36 | {
37 | permissions["AllowedChildContentTypes"] = allowedChildContentTypesToken;
38 | }
39 |
40 | artifactJson["Permissions"] = permissions;
41 |
42 | return artifactJson;
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/ContentType/ElementTypeArtifactMigratorBase.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using Semver;
3 | using Umbraco.Deploy.Artifacts.ContentType;
4 | using Umbraco.Deploy.Migrators;
5 |
6 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
7 | {
8 | ///
9 | /// Migrates the from Umbraco 7 to an element type.
10 | ///
11 | public abstract class ElementTypeArtifactMigratorBase : ArtifactMigratorBase
12 | {
13 | private readonly string[] _elementTypeAliases;
14 |
15 | ///
16 | /// Initializes a new instance of the class.
17 | ///
18 | /// The element type aliases.
19 | protected ElementTypeArtifactMigratorBase(params string[] elementTypeAliases)
20 | {
21 | _elementTypeAliases = elementTypeAliases;
22 |
23 | MaxVersion = new SemVersion(3, 0, 0);
24 | }
25 |
26 | ///
27 | protected override DocumentTypeArtifact Migrate(DocumentTypeArtifact artifact)
28 | {
29 | if (_elementTypeAliases.Contains(artifact.Alias))
30 | {
31 | artifact.Permissions.IsElementType = true;
32 | }
33 |
34 | return artifact;
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/CheckBoxListDataTypeArtifactMigrator.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Semver;
3 | using Umbraco.Core;
4 | using Umbraco.Core.PropertyEditors;
5 | using Umbraco.Deploy.Artifacts;
6 | using Umbraco.Deploy.Migrators;
7 |
8 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
9 | {
10 | ///
11 | /// Migrates the to replace the editor configuration from Umbraco 7 to .
12 | ///
13 | public class CheckBoxListDataTypeArtifactMigrator : DataTypeConfigurationArtifactMigratorBase
14 | {
15 | ///
16 | /// Initializes a new instance of the class.
17 | ///
18 | public CheckBoxListDataTypeArtifactMigrator()
19 | : base(Constants.PropertyEditors.Aliases.CheckBoxList)
20 | => MaxVersion = new SemVersion(3, 0, 0);
21 |
22 | ///
23 | protected override ValueListConfiguration MigrateConfiguration(IDictionary fromConfiguration)
24 | {
25 | var toConfiguration = new ValueListConfiguration();
26 |
27 | foreach (var (key, value) in fromConfiguration)
28 | {
29 | if (int.TryParse(key, out var id) && value != null)
30 | {
31 | toConfiguration.Items.Add(new ValueListConfiguration.ValueListItem()
32 | {
33 | Id = id,
34 | Value = value.ToString()
35 | });
36 | }
37 | }
38 |
39 | return toConfiguration;
40 | }
41 |
42 | ///
43 | protected override ValueListConfiguration GetDefaultConfiguration()
44 | => new ValueListConfiguration();
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/ColorPickerAliasDataTypeArtifactMigrator.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Semver;
3 | using Umbraco.Core;
4 | using Umbraco.Core.PropertyEditors;
5 | using Umbraco.Deploy.Artifacts;
6 | using Umbraco.Deploy.Migrators;
7 |
8 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
9 | {
10 | ///
11 | /// Migrates the to replace the editor with and the configuration from Umbraco 7 to .
12 | ///
13 | public class ColorPickerAliasDataTypeArtifactMigrator : ReplaceDataTypeArtifactMigratorBase
14 | {
15 | private const string FromEditorAlias = "Umbraco.ColorPickerAlias";
16 | private const string TrueValue = "1";
17 |
18 | ///
19 | /// Initializes a new instance of the class.
20 | ///
21 | /// The property editors.
22 | public ColorPickerAliasDataTypeArtifactMigrator(PropertyEditorCollection propertyEditors)
23 | : base(FromEditorAlias, Constants.PropertyEditors.Aliases.ColorPicker, propertyEditors)
24 | => MaxVersion = new SemVersion(3, 0, 0);
25 |
26 | ///
27 | protected override ColorPickerConfiguration MigrateConfiguration(IDictionary fromConfiguration)
28 | {
29 | var toConfiguration = new ColorPickerConfiguration();
30 |
31 | foreach (var (key, value) in fromConfiguration)
32 | {
33 | if (key == "useLabel")
34 | {
35 | toConfiguration.UseLabel = TrueValue.Equals(value);
36 | }
37 | else if (int.TryParse(key, out var id) && value != null)
38 | {
39 | toConfiguration.Items.Add(new ValueListConfiguration.ValueListItem()
40 | {
41 | Id = id,
42 | Value = value.ToString()
43 | });
44 | }
45 | }
46 |
47 | return toConfiguration;
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/ContentPicker2DataTypeArtifactMigrator.cs:
--------------------------------------------------------------------------------
1 | using Umbraco.Core;
2 | using Umbraco.Core.PropertyEditors;
3 | using Umbraco.Deploy.Artifacts;
4 | using Umbraco.Web.PropertyEditors;
5 |
6 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
7 | {
8 | ///
9 | /// Migrates the to replace the editor with and the configuration from Umbraco 7 to .
10 | ///
11 | public class ContentPicker2DataTypeArtifactMigrator : ContentPickerReplaceDataTypeArtifactMigratorBase
12 | {
13 | private const string FromEditorAlias = "Umbraco.ContentPicker2";
14 |
15 | ///
16 | /// Initializes a new instance of the class.
17 | ///
18 | /// The property editors.
19 | public ContentPicker2DataTypeArtifactMigrator(PropertyEditorCollection propertyEditors)
20 | : base(FromEditorAlias, propertyEditors)
21 | { }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/ContentPickerAliasDataTypeArtifactMigrator.cs:
--------------------------------------------------------------------------------
1 | using Umbraco.Core;
2 | using Umbraco.Core.PropertyEditors;
3 | using Umbraco.Deploy.Artifacts;
4 | using Umbraco.Web.PropertyEditors;
5 |
6 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
7 | {
8 | ///
9 | /// Migrates the to replace the editor with and the configuration from Umbraco 7 to .
10 | ///
11 | public class ContentPickerAliasDataTypeArtifactMigrator : ContentPickerReplaceDataTypeArtifactMigratorBase
12 | {
13 | private const string FromEditorAlias = "Umbraco.ContentPickerAlias";
14 |
15 | ///
16 | /// Initializes a new instance of the class.
17 | ///
18 | /// The property editors.
19 | public ContentPickerAliasDataTypeArtifactMigrator(PropertyEditorCollection propertyEditors)
20 | : base(FromEditorAlias, propertyEditors)
21 | { }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/ContentPickerReplaceDataTypeArtifactMigratorBase.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Semver;
3 | using Umbraco.Core;
4 | using Umbraco.Core.PropertyEditors;
5 | using Umbraco.Deploy.Artifacts;
6 | using Umbraco.Deploy.Migrators;
7 |
8 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
9 | {
10 | ///
11 | /// Migrates the to replace the editor alias with and update the configuration.
12 | ///
13 | public abstract class ContentPickerReplaceDataTypeArtifactMigratorBase : ReplaceDataTypeArtifactMigratorBase
14 | {
15 | ///
16 | /// Initializes a new instance of the class.
17 | ///
18 | /// The editor alias to migrate from.
19 | /// The property editors.
20 | protected ContentPickerReplaceDataTypeArtifactMigratorBase(string fromEditorAlias, PropertyEditorCollection propertyEditors)
21 | : base(fromEditorAlias, Constants.PropertyEditors.Aliases.ContentPicker, propertyEditors)
22 | => MaxVersion = new SemVersion(3, 0, 0);
23 |
24 | ///
25 | protected override IDictionary MigrateConfiguration(IDictionary configuration)
26 | {
27 | if (configuration.TryGetValue("startNodeId", out var startNodeIdValue) &&
28 | (!(startNodeIdValue?.ToString() is string startNodeIdString) || !Udi.TryParse(startNodeIdString, out _)))
29 | {
30 | // Remove invalid start node id
31 | configuration.Remove("startNodeId");
32 | }
33 |
34 | return base.MigrateConfiguration(configuration);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/DateDataTypeArtifactMigrator.cs:
--------------------------------------------------------------------------------
1 | using Semver;
2 | using Umbraco.Core;
3 | using Umbraco.Core.PropertyEditors;
4 | using Umbraco.Deploy.Artifacts;
5 | using Umbraco.Deploy.Migrators;
6 |
7 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
8 | {
9 | ///
10 | /// Migrates the to replace the editor with .
11 | ///
12 | public class DateDataTypeArtifactMigrator : ReplaceDataTypeArtifactMigratorBase
13 | {
14 | private const string FromEditorAlias = "Umbraco.Date";
15 |
16 | ///
17 | /// Initializes a new instance of the class.
18 | ///
19 | /// The property editors.
20 | public DateDataTypeArtifactMigrator(PropertyEditorCollection propertyEditors)
21 | : base(FromEditorAlias, Constants.PropertyEditors.Aliases.DateTime, propertyEditors)
22 | => MaxVersion = new SemVersion(3, 0, 0);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/DropDownDataTypeArtifactMigrator.cs:
--------------------------------------------------------------------------------
1 | using Umbraco.Core;
2 | using Umbraco.Core.PropertyEditors;
3 | using Umbraco.Deploy.Artifacts;
4 |
5 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
6 | {
7 | ///
8 | /// Migrates the to replace the editor with and the configuration from Umbraco 7 to .
9 | ///
10 | public class DropDownDataTypeArtifactMigrator : DropDownReplaceDataTypeArtifactMigratorBase
11 | {
12 | private const string FromEditorAlias = "Umbraco.DropDown";
13 |
14 | ///
15 | protected override bool Multiple => false;
16 |
17 | ///
18 | /// Initializes a new instance of the class.
19 | ///
20 | /// The property editors.
21 | public DropDownDataTypeArtifactMigrator(PropertyEditorCollection propertyEditors)
22 | : base(FromEditorAlias, propertyEditors)
23 | { }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/DropDownFlexibleDataTypeArtifactMigrator.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Semver;
3 | using Umbraco.Core;
4 | using Umbraco.Core.PropertyEditors;
5 | using Umbraco.Deploy.Artifacts;
6 | using Umbraco.Deploy.Migrators;
7 |
8 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
9 | {
10 | ///
11 | /// Migrates the to replace the configuration of the editor from Umbraco 7 to .
12 | ///
13 | public class DropDownFlexibleDataTypeArtifactMigrator : DataTypeConfigurationArtifactMigratorBase
14 | {
15 | private const string TrueValue = "1";
16 |
17 | ///
18 | /// Initializes a new instance of the class.
19 | ///
20 | public DropDownFlexibleDataTypeArtifactMigrator()
21 | : base(Constants.PropertyEditors.Aliases.DropDownListFlexible)
22 | => MaxVersion = new SemVersion(3, 0, 0);
23 |
24 | ///
25 | protected override DropDownFlexibleConfiguration MigrateConfiguration(IDictionary fromConfiguration)
26 | {
27 | var toConfiguration = new DropDownFlexibleConfiguration()
28 | {
29 | Multiple = true
30 | };
31 |
32 | foreach (var (key, value) in fromConfiguration)
33 | {
34 | if (key == "multiple")
35 | {
36 | toConfiguration.Multiple = TrueValue.Equals(value);
37 | }
38 | else if (int.TryParse(key, out var id) && value != null)
39 | {
40 | toConfiguration.Items.Add(new ValueListConfiguration.ValueListItem()
41 | {
42 | Id = id,
43 | Value = value.ToString()
44 | });
45 | }
46 | }
47 |
48 | return toConfiguration;
49 | }
50 |
51 | ///
52 | protected override DropDownFlexibleConfiguration GetDefaultConfiguration()
53 | => new DropDownFlexibleConfiguration()
54 | {
55 | Multiple = true
56 | };
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/DropDownMultipleDataTypeArtifactMigrator.cs:
--------------------------------------------------------------------------------
1 | using Umbraco.Core;
2 | using Umbraco.Core.PropertyEditors;
3 | using Umbraco.Deploy.Artifacts;
4 |
5 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
6 | {
7 | ///
8 | /// Migrates the to replace the editor with and the configuration from Umbraco 7 to .
9 | ///
10 | public class DropDownMultipleDataTypeArtifactMigrator : DropDownReplaceDataTypeArtifactMigratorBase
11 | {
12 | private const string FromEditorAlias = "Umbraco.DropDownMultiple";
13 |
14 | ///
15 | protected override bool Multiple => true;
16 |
17 | ///
18 | /// Initializes a new instance of the class.
19 | ///
20 | /// The property editors.
21 | public DropDownMultipleDataTypeArtifactMigrator(PropertyEditorCollection propertyEditors)
22 | : base(FromEditorAlias, propertyEditors)
23 | { }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/DropDownReplaceDataTypeArtifactMigratorBase.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Semver;
3 | using Umbraco.Core;
4 | using Umbraco.Core.PropertyEditors;
5 | using Umbraco.Deploy.Artifacts;
6 | using Umbraco.Deploy.Migrators;
7 |
8 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
9 | {
10 | ///
11 | /// Migrates the to replace the editor alias with and the configuration from Umbraco 7 to .
12 | ///
13 | public abstract class DropDownReplaceDataTypeArtifactMigratorBase : ReplaceDataTypeArtifactMigratorBase
14 | {
15 | private const string TrueValue = "1";
16 |
17 | ///
18 | /// Gets a value indicating whether the configuration allows multiple items to be selected.
19 | ///
20 | ///
21 | /// true if multiple items can be selected; otherwise, false.
22 | ///
23 | protected abstract bool Multiple { get; }
24 |
25 | ///
26 | /// Initializes a new instance of the class.
27 | ///
28 | /// The editor alias to migrate from.
29 | /// The property editors.
30 | protected DropDownReplaceDataTypeArtifactMigratorBase(string fromEditorAlias, PropertyEditorCollection propertyEditors)
31 | : base(fromEditorAlias, Constants.PropertyEditors.Aliases.DropDownListFlexible, propertyEditors)
32 | => MaxVersion = new SemVersion(3, 0, 0);
33 |
34 | ///
35 | protected override DropDownFlexibleConfiguration MigrateConfiguration(IDictionary fromConfiguration)
36 | {
37 | var toConfiguration = new DropDownFlexibleConfiguration()
38 | {
39 | Multiple = Multiple
40 | };
41 |
42 | foreach (var (key, value) in fromConfiguration)
43 | {
44 | if (key == "multiple")
45 | {
46 | toConfiguration.Multiple = TrueValue.Equals(value);
47 | }
48 | else if (int.TryParse(key, out var id) && value != null)
49 | {
50 | toConfiguration.Items.Add(new ValueListConfiguration.ValueListItem()
51 | {
52 | Id = id,
53 | Value = value.ToString()
54 | });
55 | }
56 | }
57 |
58 | return toConfiguration;
59 | }
60 |
61 | ///
62 | protected override DropDownFlexibleConfiguration GetDefaultConfiguration(IConfigurationEditor toConfigurationEditor)
63 | {
64 | var configuration = base.GetDefaultConfiguration(toConfigurationEditor);
65 | if (configuration != null)
66 | {
67 | configuration.Multiple = Multiple;
68 | }
69 |
70 | return configuration;
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/DropdownlistMultiplePublishKeysDataTypeArtifactMigrator.cs:
--------------------------------------------------------------------------------
1 | using Umbraco.Core;
2 | using Umbraco.Core.PropertyEditors;
3 | using Umbraco.Deploy.Artifacts;
4 |
5 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
6 | {
7 | ///
8 | /// Migrates the to replace the editor with and the configuration from Umbraco 7 to .
9 | ///
10 | public class DropdownlistMultiplePublishKeysDataTypeArtifactMigrator : DropDownReplaceDataTypeArtifactMigratorBase
11 | {
12 | private const string FromEditorAlias = "Umbraco.DropdownlistMultiplePublishKeys";
13 |
14 | ///
15 | protected override bool Multiple => true;
16 |
17 | ///
18 | /// Initializes a new instance of the class.
19 | ///
20 | /// The property editors.
21 | public DropdownlistMultiplePublishKeysDataTypeArtifactMigrator(PropertyEditorCollection propertyEditors)
22 | : base(FromEditorAlias, propertyEditors)
23 | { }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/DropdownlistPublishingKeysDataTypeArtifactMigrator.cs:
--------------------------------------------------------------------------------
1 | using Umbraco.Core;
2 | using Umbraco.Core.PropertyEditors;
3 | using Umbraco.Deploy.Artifacts;
4 |
5 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
6 | {
7 | ///
8 | /// Migrates the to replace the editor with and the configuration from Umbraco 7 to .
9 | ///
10 | public class DropdownlistPublishingKeysDataTypeArtifactMigrator : DropDownReplaceDataTypeArtifactMigratorBase
11 | {
12 | private const string FromEditorAlias = "Umbraco.DropdownlistPublishingKeys";
13 |
14 | ///
15 | protected override bool Multiple => false;
16 |
17 | ///
18 | /// Initializes a new instance of the class.
19 | ///
20 | /// The property editors.
21 | public DropdownlistPublishingKeysDataTypeArtifactMigrator(PropertyEditorCollection propertyEditors)
22 | : base(FromEditorAlias, propertyEditors)
23 | { }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/MediaPicker2DataTypeArtifactMigrator.cs:
--------------------------------------------------------------------------------
1 | using Umbraco.Core;
2 | using Umbraco.Core.PropertyEditors;
3 | using Umbraco.Deploy.Artifacts;
4 | using Umbraco.Web.PropertyEditors;
5 |
6 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
7 | {
8 | ///
9 | /// Migrates the to replace the editor with and the configuration from Umbraco 7 to .
10 | ///
11 | public class MediaPicker2DataTypeArtifactMigrator : MediaPickerReplaceDataTypeArtifactMigratorBase
12 | {
13 | private const string FromEditorAlias = "Umbraco.MediaPicker2";
14 |
15 | ///
16 | protected override bool Multiple => false;
17 |
18 | ///
19 | /// Initializes a new instance of the class.
20 | ///
21 | /// The property editors.
22 | public MediaPicker2DataTypeArtifactMigrator(PropertyEditorCollection propertyEditors)
23 | : base(FromEditorAlias, propertyEditors)
24 | { }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/MediaPickerDataTypeArtifactMigrator.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Semver;
3 | using Umbraco.Core;
4 | using Umbraco.Deploy.Artifacts;
5 | using Umbraco.Deploy.Migrators;
6 |
7 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
8 | {
9 | ///
10 | /// Migrates the to update the editor configuration.
11 | ///
12 | public class MediaPickerDataTypeArtifactMigrator : DataTypeConfigurationArtifactMigratorBase
13 | {
14 | ///
15 | /// Initializes a new instance of the class.
16 | ///
17 | public MediaPickerDataTypeArtifactMigrator()
18 | : base(Constants.PropertyEditors.Aliases.MediaPicker)
19 | => MaxVersion = new SemVersion(3, 0, 0);
20 |
21 | ///
22 | protected override IDictionary MigrateConfiguration(IDictionary fromConfiguration)
23 | {
24 | if (fromConfiguration.TryGetValue("startNodeId", out var startNodeIdValue) &&
25 | (!(startNodeIdValue?.ToString() is string startNodeId) || !Udi.TryParse(startNodeId, out _)))
26 | {
27 | // Remove invalid start node ID
28 | fromConfiguration.Remove("startNodeId");
29 | }
30 |
31 | return fromConfiguration;
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/MediaPickerReplaceDataTypeArtifactMigratorBase.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Semver;
3 | using Umbraco.Core;
4 | using Umbraco.Core.PropertyEditors;
5 | using Umbraco.Deploy.Artifacts;
6 | using Umbraco.Deploy.Migrators;
7 |
8 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
9 | {
10 | ///
11 | /// Migrates the to replace the editor alias with and update the configuration.
12 | ///
13 | public abstract class MediaPickerReplaceDataTypeArtifactMigratorBase : ReplaceDataTypeArtifactMigratorBase
14 | {
15 | ///
16 | /// Gets a value indicating whether the configuration allows multiple items to be picked.
17 | ///
18 | ///
19 | /// true if multiple items can be picked; otherwise, false.
20 | ///
21 | protected abstract bool Multiple { get; }
22 |
23 | ///
24 | /// Initializes a new instance of the class.
25 | ///
26 | /// From editor alias.
27 | /// The property editors.
28 | protected MediaPickerReplaceDataTypeArtifactMigratorBase(string fromEditorAlias, PropertyEditorCollection propertyEditors)
29 | : base(fromEditorAlias, Constants.PropertyEditors.Aliases.MediaPicker, propertyEditors)
30 | => MaxVersion = new SemVersion(3, 0, 0);
31 |
32 | ///
33 | protected override IDictionary MigrateConfiguration(IDictionary configuration)
34 | {
35 | if (!configuration.ContainsKey("multiPicker"))
36 | {
37 | configuration["multiPicker"] = Multiple;
38 | }
39 |
40 | if (configuration.TryGetValue("startNodeId", out var startNodeIdValue) &&
41 | (!(startNodeIdValue?.ToString() is string startNodeId) || !Udi.TryParse(startNodeId, out _)))
42 | {
43 | // Remove invalid start node ID
44 | configuration.Remove("startNodeId");
45 | }
46 |
47 | return configuration;
48 | }
49 |
50 | ///
51 | protected override IDictionary GetDefaultConfiguration(IConfigurationEditor toConfigurationEditor)
52 | {
53 | var configuration = base.GetDefaultConfiguration(toConfigurationEditor);
54 | if (configuration != null)
55 | {
56 | configuration["multiPicker"] = Multiple;
57 | }
58 |
59 | return configuration;
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/MemberPicker2DataTypeArtifactMigrator.cs:
--------------------------------------------------------------------------------
1 | using Semver;
2 | using Umbraco.Core;
3 | using Umbraco.Core.PropertyEditors;
4 | using Umbraco.Deploy.Artifacts;
5 | using Umbraco.Deploy.Migrators;
6 |
7 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
8 | {
9 | ///
10 | /// Migrates the to replace the editor with .
11 | ///
12 | public class MemberPicker2DataTypeArtifactMigrator : ReplaceDataTypeArtifactMigratorBase
13 | {
14 | private const string FromEditorAlias = "Umbraco.MemberPicker2";
15 |
16 | ///
17 | /// Initializes a new instance of the class.
18 | ///
19 | /// The property editors.
20 | public MemberPicker2DataTypeArtifactMigrator(PropertyEditorCollection propertyEditors)
21 | : base(FromEditorAlias, Constants.PropertyEditors.Aliases.MemberPicker, propertyEditors)
22 | => MaxVersion = new SemVersion(3, 0, 0);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/MultiNodeTreePicker2DataTypeArtifactMigrator.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Newtonsoft.Json.Linq;
3 | using Semver;
4 | using Umbraco.Core;
5 | using Umbraco.Core.PropertyEditors;
6 | using Umbraco.Deploy.Artifacts;
7 | using Umbraco.Deploy.Migrators;
8 |
9 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
10 | {
11 | ///
12 | /// Migrates the to replace the editor with and update the configuration.
13 | ///
14 | public class MultiNodeTreePicker2DataTypeArtifactMigrator : ReplaceDataTypeArtifactMigratorBase
15 | {
16 | private const string FromEditorAlias = "Umbraco.MultiNodeTreePicker2";
17 |
18 | ///
19 | /// Initializes a new instance of the class.
20 | ///
21 | /// The property editors.
22 | public MultiNodeTreePicker2DataTypeArtifactMigrator(PropertyEditorCollection propertyEditors)
23 | : base(FromEditorAlias, Constants.PropertyEditors.Aliases.MultiNodeTreePicker, propertyEditors)
24 | => MaxVersion = new SemVersion(3, 0, 0);
25 |
26 | ///
27 | protected override IDictionary MigrateConfiguration(IDictionary configuration)
28 | {
29 | if (configuration.TryGetValue("startNode", out var startNodeValue) &&
30 | startNodeValue is JObject startNode &&
31 | startNode["id"] is JValue idValue &&
32 | (!(idValue.Value?.ToString() is string id) || !Udi.TryParse(id, out _)))
33 | {
34 | // Remove invalid start node ID
35 | startNode.Remove("id");
36 | }
37 |
38 | return configuration;
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/MultiNodeTreePickerDataTypeArtifactMigrator.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Newtonsoft.Json.Linq;
3 | using Semver;
4 | using Umbraco.Core;
5 | using Umbraco.Deploy.Artifacts;
6 | using Umbraco.Deploy.Migrators;
7 |
8 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
9 | {
10 | ///
11 | /// Migrates the to update the editor configuration.
12 | ///
13 | public class MultiNodeTreePickerDataTypeArtifactMigrator : DataTypeConfigurationArtifactMigratorBase
14 | {
15 | ///
16 | /// Initializes a new instance of the class.
17 | ///
18 | public MultiNodeTreePickerDataTypeArtifactMigrator()
19 | : base(Constants.PropertyEditors.Aliases.MultiNodeTreePicker)
20 | => MaxVersion = new SemVersion(3, 0, 0);
21 |
22 | ///
23 | protected override IDictionary MigrateConfiguration(IDictionary fromConfiguration)
24 | {
25 | if (fromConfiguration.TryGetValue("startNode", out var startNodeValue) &&
26 | startNodeValue is JObject startNode &&
27 | startNode["id"] is JValue idValue &&
28 | (!(idValue.Value?.ToString() is string id) || !Udi.TryParse(id, out _)))
29 | {
30 | // Remove invalid start node ID
31 | startNode.Remove("id");
32 | }
33 |
34 | return fromConfiguration;
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/MultiUrlPickerReplaceDataTypeArtifactMigratorBase.cs:
--------------------------------------------------------------------------------
1 | using Semver;
2 | using Umbraco.Core;
3 | using Umbraco.Core.PropertyEditors;
4 | using Umbraco.Deploy.Artifacts;
5 | using Umbraco.Deploy.Migrators;
6 |
7 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
8 | {
9 | ///
10 | /// Migrates the to replace the editor alias with .
11 | ///
12 | public abstract class MultiUrlPickerReplaceDataTypeArtifactMigratorBase : ReplaceDataTypeArtifactMigratorBase
13 | {
14 | ///
15 | /// Initializes a new instance of the class.
16 | ///
17 | /// The editor alias to migrate from.
18 | /// The property editors.
19 | protected MultiUrlPickerReplaceDataTypeArtifactMigratorBase(string fromEditorAlias, PropertyEditorCollection propertyEditors)
20 | : base(fromEditorAlias, Constants.PropertyEditors.Aliases.MultiUrlPicker, propertyEditors)
21 | => MaxVersion = new SemVersion(3, 0, 0);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/MultipleMediaPickerDataTypeArtifactMigrator.cs:
--------------------------------------------------------------------------------
1 | using Umbraco.Core;
2 | using Umbraco.Core.PropertyEditors;
3 | using Umbraco.Deploy.Artifacts;
4 |
5 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
6 | {
7 | ///
8 | /// Migrates the to replace the editor with and update the configuration.
9 | ///
10 | public class MultipleMediaPickerDataTypeArtifactMigrator : MediaPickerReplaceDataTypeArtifactMigratorBase
11 | {
12 | private const string FromEditorAlias = "Umbraco.MultipleMediaPicker";
13 |
14 | ///
15 | protected override bool Multiple => true;
16 |
17 | ///
18 | /// Initializes a new instance of the class.
19 | ///
20 | /// The property editors.
21 | public MultipleMediaPickerDataTypeArtifactMigrator(PropertyEditorCollection propertyEditors)
22 | : base(FromEditorAlias, propertyEditors)
23 | { }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/NoEditDataTypeArtifactMigrator.cs:
--------------------------------------------------------------------------------
1 | using Semver;
2 | using Umbraco.Core;
3 | using Umbraco.Core.PropertyEditors;
4 | using Umbraco.Deploy.Artifacts;
5 | using Umbraco.Deploy.Migrators;
6 |
7 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
8 | {
9 | ///
10 | /// Migrates the to replace the editor with .
11 | ///
12 | public class NoEditDataTypeArtifactMigrator : ReplaceDataTypeArtifactMigratorBase
13 | {
14 | private const string FromEditorAlias = "Umbraco.NoEdit";
15 |
16 | ///
17 | /// Initializes a new instance of the class.
18 | ///
19 | /// The property editors.
20 | public NoEditDataTypeArtifactMigrator(PropertyEditorCollection propertyEditors)
21 | : base(FromEditorAlias, Constants.PropertyEditors.Aliases.Label, propertyEditors)
22 | => MaxVersion = new SemVersion(3, 0, 0);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/PreValuesDataTypeArtifactJsonMigrator.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using Newtonsoft.Json.Linq;
3 | using Semver;
4 | using Umbraco.Core;
5 | using Umbraco.Deploy.Artifacts;
6 | using Umbraco.Deploy.Migrators;
7 |
8 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
9 | {
10 | ///
11 | /// Migrates the JSON from Umbraco 7 pre-values to configuration objects/arrays.
12 | ///
13 | public class PreValuesDataTypeArtifactJsonMigrator : ArtifactJsonMigratorBase
14 | {
15 | ///
16 | /// Initializes a new instance of the class.
17 | ///
18 | public PreValuesDataTypeArtifactJsonMigrator()
19 | => MaxVersion = new SemVersion(3, 0, 0);
20 |
21 | ///
22 | public override JToken Migrate(JToken artifactJson)
23 | {
24 | if (artifactJson["PreValues"] is JObject preValues)
25 | {
26 | var configuration = new JObject();
27 |
28 | foreach (var property in preValues.Properties())
29 | {
30 | var propertyValue = property.Value;
31 |
32 | // Convert pre-value serialized JSON to actual JSON objects/arrays
33 | if (propertyValue.Type == JTokenType.String &&
34 | propertyValue.Value() is string value)
35 | {
36 | if (string.IsNullOrEmpty(value))
37 | {
38 | // Skip empty value
39 | continue;
40 | }
41 | else if (value.DetectIsJson())
42 | {
43 | propertyValue = JToken.Parse(value);
44 | }
45 | }
46 |
47 | configuration.Add(property.Name, propertyValue);
48 | }
49 |
50 | artifactJson["Configuration"] = configuration;
51 | }
52 |
53 | return artifactJson;
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/RadioButtonListDataTypeArtifactMigrator.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Semver;
3 | using Umbraco.Core;
4 | using Umbraco.Core.Models;
5 | using Umbraco.Core.PropertyEditors;
6 | using Umbraco.Deploy.Artifacts;
7 | using Umbraco.Deploy.Migrators;
8 |
9 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
10 | {
11 | ///
12 | /// Migrates the to replace the configuration of the editor from Umbraco 7 to .
13 | ///
14 | public class RadioButtonListDataTypeArtifactMigrator : DataTypeConfigurationArtifactMigratorBase
15 | {
16 | ///
17 | /// Initializes a new instance of the class.
18 | ///
19 | public RadioButtonListDataTypeArtifactMigrator()
20 | : base(Constants.PropertyEditors.Aliases.RadioButtonList)
21 | => MaxVersion = new SemVersion(3, 0, 0);
22 |
23 | ///
24 | protected override DataTypeArtifact Migrate(DataTypeArtifact artifact)
25 | {
26 | artifact.DatabaseType = ValueStorageType.Nvarchar;
27 |
28 | return base.Migrate(artifact);
29 | }
30 |
31 | ///
32 | protected override ValueListConfiguration MigrateConfiguration(IDictionary fromConfiguration)
33 | {
34 | var toConfiguration = new ValueListConfiguration();
35 |
36 | foreach (var (key, value) in fromConfiguration)
37 | {
38 | if (int.TryParse(key, out var id) && value != null)
39 | {
40 | toConfiguration.Items.Add(new ValueListConfiguration.ValueListItem()
41 | {
42 | Id = id,
43 | Value = value.ToString()
44 | });
45 | }
46 | }
47 |
48 | return toConfiguration;
49 | }
50 |
51 | ///
52 | protected override ValueListConfiguration GetDefaultConfiguration()
53 | => new ValueListConfiguration();
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/RelatedLinks2DataTypeArtifactMigrator.cs:
--------------------------------------------------------------------------------
1 | using Umbraco.Core;
2 | using Umbraco.Core.PropertyEditors;
3 | using Umbraco.Deploy.Artifacts;
4 | using Umbraco.Web.PropertyEditors;
5 |
6 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
7 | {
8 | ///
9 | /// Migrates the to replace the editor with and the configuration from Umbraco 7 to .
10 | ///
11 | public class RelatedLinks2DataTypeArtifactMigrator : MultiUrlPickerReplaceDataTypeArtifactMigratorBase
12 | {
13 | private const string FromEditorAlias = "Umbraco.RelatedLinks2";
14 |
15 | ///
16 | /// Initializes a new instance of the class.
17 | ///
18 | /// The property editors.
19 | public RelatedLinks2DataTypeArtifactMigrator(PropertyEditorCollection propertyEditors)
20 | : base(FromEditorAlias, propertyEditors)
21 | { }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/RelatedLinksDataTypeArtifactMigrator.cs:
--------------------------------------------------------------------------------
1 | using Umbraco.Core;
2 | using Umbraco.Core.PropertyEditors;
3 | using Umbraco.Deploy.Artifacts;
4 | using Umbraco.Web.PropertyEditors;
5 |
6 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
7 | {
8 | ///
9 | /// Migrates the to replace the editor with and the configuration from Umbraco 7 to .
10 | ///
11 | public class RelatedLinksDataTypeArtifactMigrator : MultiUrlPickerReplaceDataTypeArtifactMigratorBase
12 | {
13 | private const string FromEditorAlias = "Umbraco.RelatedLinks";
14 |
15 | ///
16 | /// Initializes a new instance of the class.
17 | ///
18 | /// The property editors.
19 | public RelatedLinksDataTypeArtifactMigrator(PropertyEditorCollection propertyEditors)
20 | : base(FromEditorAlias, propertyEditors)
21 | { }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/TextboxDataTypeArtifactMigrator.cs:
--------------------------------------------------------------------------------
1 | using Semver;
2 | using Umbraco.Core;
3 | using Umbraco.Core.PropertyEditors;
4 | using Umbraco.Deploy.Artifacts;
5 | using Umbraco.Deploy.Migrators;
6 |
7 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
8 | {
9 | ///
10 | /// Migrates the to replace the editor with .
11 | ///
12 | public class TextboxDataTypeArtifactMigrator : ReplaceDataTypeArtifactMigratorBase
13 | {
14 | private const string FromEditorAlias = "Umbraco.Textbox";
15 |
16 | ///
17 | /// Initializes a new instance of the class.
18 | ///
19 | /// The property editors.
20 | public TextboxDataTypeArtifactMigrator(PropertyEditorCollection propertyEditors)
21 | : base(FromEditorAlias, Constants.PropertyEditors.Aliases.TextBox, propertyEditors)
22 | => MaxVersion = new SemVersion(3, 0, 0);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/TextboxMultipleDataTypeArtifactMigrator.cs:
--------------------------------------------------------------------------------
1 | using Semver;
2 | using Umbraco.Core;
3 | using Umbraco.Core.PropertyEditors;
4 | using Umbraco.Deploy.Artifacts;
5 | using Umbraco.Deploy.Migrators;
6 |
7 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
8 | {
9 | ///
10 | /// Migrates the to replace the editor with .
11 | ///
12 | public class TextboxMultipleDataTypeArtifactMigrator : ReplaceDataTypeArtifactMigratorBase
13 | {
14 | private const string FromEditorAlias = "Umbraco.TextboxMultiple";
15 |
16 | ///
17 | /// Initializes a new instance of the class.
18 | ///
19 | /// The property editors.
20 | public TextboxMultipleDataTypeArtifactMigrator(PropertyEditorCollection propertyEditors)
21 | : base(FromEditorAlias, Constants.PropertyEditors.Aliases.TextArea, propertyEditors)
22 | => MaxVersion = new SemVersion(3, 0, 0);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Migrators/Legacy/DataType/TinyMCEv3DataTypeArtifactMigrator.cs:
--------------------------------------------------------------------------------
1 | using Semver;
2 | using Umbraco.Core;
3 | using Umbraco.Core.PropertyEditors;
4 | using Umbraco.Deploy.Artifacts;
5 | using Umbraco.Deploy.Migrators;
6 |
7 | namespace Umbraco.Deploy.Contrib.Migrators.Legacy
8 | {
9 | ///
10 | /// Migrates the to replace the editor with .
11 | ///
12 | public class TinyMCEv3DataTypeArtifactMigrator : ReplaceDataTypeArtifactMigratorBase
13 | {
14 | private const string FromEditorAlias = "Umbraco.TinyMCEv3";
15 |
16 | ///
17 | /// Initializes a new instance of the class.
18 | ///
19 | /// The property editors.
20 | public TinyMCEv3DataTypeArtifactMigrator(PropertyEditorCollection propertyEditors)
21 | : base(FromEditorAlias, Constants.PropertyEditors.Aliases.TinyMce, propertyEditors)
22 | => MaxVersion = new SemVersion(3, 0, 0);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Serialization/LegacyArtifactTypeResolver.cs:
--------------------------------------------------------------------------------
1 | using Semver;
2 | using Umbraco.Deploy.Serialization;
3 |
4 | namespace Umbraco.Deploy.Contrib.Connectors.Serialization
5 | {
6 | ///
7 | /// Resolves legacy artifact type names from Umbraco 7.
8 | ///
9 | public sealed class LegacyArtifactTypeResolver : ArtifactTypeResolverBase
10 | {
11 | ///
12 | /// Initializes a new instance of the class.
13 | ///
14 | public LegacyArtifactTypeResolver()
15 | => MaxVersion = new SemVersion(3, 0, 0);
16 |
17 | ///
18 | protected override string ResolveTypeName(string typeName)
19 | {
20 | // v2 to v4
21 | switch (typeName)
22 | {
23 | // Content
24 | case "Umbraco.Deploy.Artifacts.DocumentArtifact":
25 | typeName = "Umbraco.Deploy.Artifacts.Content.DocumentArtifact";
26 | break;
27 | case "Umbraco.Deploy.Artifacts.MediaArtifact":
28 | typeName = "Umbraco.Deploy.Artifacts.Content.MediaArtifact";
29 | break;
30 | case "Umbraco.Deploy.Artifacts.MemberArtifact":
31 | typeName = "Umbraco.Deploy.Artifacts.Content.MemberArtifact";
32 | break;
33 | // Content types
34 | case "Umbraco.Deploy.Artifacts.DocumentTypeArtifact":
35 | typeName = "Umbraco.Deploy.Artifacts.ContentType.DocumentTypeArtifact";
36 | break;
37 | case "Umbraco.Deploy.Artifacts.MediaTypeArtifact":
38 | typeName = "Umbraco.Deploy.Artifacts.ContentType.MediaTypeArtifact";
39 | break;
40 | case "Umbraco.Deploy.Artifacts.MemberTypeArtifact":
41 | typeName = "Umbraco.Deploy.Artifacts.ContentType.MemberTypeArtifact";
42 | break;
43 | case "Umbraco.Deploy.Artifacts.RelationTypeArtifact":
44 | typeName = "Umbraco.Deploy.Artifacts.ContentType.RelationTypeArtifact";
45 | break;
46 | }
47 |
48 | return typeName;
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/Umbraco.Deploy.Contrib.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | UmbracoDeploy.Contrib
4 | Umbraco Deploy - Contrib
5 | This project contains community contributions for the Umbraco deployment engine, Umbraco Deploy. Primarily this project offers ValueConnectors for the most popular Umbraco community packages - these are used by Umbraco Deploy (and Umbraco Cloud) to aid with the deployment and transferring of content/property-data to a target environment.
6 | Umbraco.Deploy.Contrib.Connectors
7 | Umbraco.Deploy.Contrib
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/ValueConnectors/BlockEditorValueConnector.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using Newtonsoft.Json;
5 | using Newtonsoft.Json.Linq;
6 | using Umbraco.Core;
7 | using Umbraco.Core.Deploy;
8 | using Umbraco.Core.Logging;
9 | using Umbraco.Core.Models;
10 | using Umbraco.Core.Services;
11 | using Umbraco.Deploy.Connectors;
12 | using Umbraco.Deploy.Connectors.ValueConnectors;
13 | using Umbraco.Deploy.Connectors.ValueConnectors.Services;
14 | using Umbraco.Deploy.Core;
15 | using Umbraco.Deploy.Extensions;
16 |
17 | namespace Umbraco.Deploy.Contrib.Connectors.ValueConnectors
18 | {
19 | ///
20 | /// A Deploy connector for BlockEditor based property editors (ie. BlockList)
21 | ///
22 | [Obsolete("Use Umbraco.Deploy.Connectors.ValueConnectors.BlockValueConnectorBase instead to support recursive migrators. This class will be removed in a future version.")]
23 | public abstract class BlockEditorValueConnector : ValueConnectorBase
24 | {
25 | private readonly IContentTypeService _contentTypeService;
26 | private readonly Lazy _valueConnectorsLazy;
27 | private readonly ILogger _logger;
28 |
29 | ///
30 | public override IEnumerable PropertyEditorAliases { get; } = Enumerable.Empty();
31 |
32 | // cannot inject ValueConnectorCollection directly as it would cause a circular (recursive) dependency,
33 | // so we have to inject it lazily and use the lazy value when actually needing it
34 | private ValueConnectorCollection ValueConnectors => _valueConnectorsLazy.Value;
35 |
36 | public BlockEditorValueConnector(IContentTypeService contentTypeService, Lazy valueConnectors, ILogger logger)
37 | {
38 | _contentTypeService = contentTypeService ?? throw new ArgumentNullException(nameof(contentTypeService));
39 | _valueConnectorsLazy = valueConnectors ?? throw new ArgumentNullException(nameof(valueConnectors));
40 | _logger = logger ?? throw new ArgumentNullException(nameof(logger));
41 | }
42 |
43 | public override string ToArtifact(object value, PropertyType propertyType, ICollection dependencies, IContextCache contextCache)
44 | {
45 | _logger.Debug("Converting {PropertyType} to artifact.", propertyType.Alias);
46 | var valueAsString = value as string;
47 |
48 | // nested values will arrive here as JObject - convert to string to enable reuse of same code as when non-nested.
49 | if (value is JObject)
50 | {
51 | _logger.Debug("Value is a JObject - converting to string.");
52 | valueAsString = value.ToString();
53 | }
54 |
55 | if (string.IsNullOrWhiteSpace(valueAsString))
56 | {
57 | _logger.Debug($"Value is null or whitespace. Skipping conversion to artifact.");
58 | return null;
59 | }
60 |
61 | if (!valueAsString.TryParseJson(out BlockEditorValue blockEditorValue))
62 | {
63 | _logger.Warn("Value '{Value}' is not a JSON string. Skipping conversion to artifact.", valueAsString);
64 | return null;
65 | }
66 |
67 | if (blockEditorValue == null)
68 | {
69 | _logger.Warn("Deserialized value is null. Skipping conversion to artifact.");
70 | return null;
71 | }
72 |
73 | var allBlocks = blockEditorValue.Content.Concat(blockEditorValue.Settings ?? Enumerable.Empty()).ToList();
74 |
75 | // get all the content types used in block editor items
76 | var allContentTypes = allBlocks.Select(x => x.ContentTypeKey)
77 | .Distinct()
78 | .ToDictionary(a => a, a =>
79 | {
80 | if (!Guid.TryParse(a, out var keyAsGuid))
81 | {
82 | throw new InvalidOperationException($"Could not parse ContentTypeKey as GUID {keyAsGuid}.");
83 | }
84 |
85 | return contextCache.GetContentTypeByKey(_contentTypeService, keyAsGuid);
86 | });
87 |
88 | //Ensure all of these content types are found
89 | if (allContentTypes.Values.Any(contentType => contentType == null))
90 | {
91 | throw new InvalidOperationException($"Could not resolve these content types for the Block Editor property: {string.Join(",", allContentTypes.Where(x => x.Value == null).Select(x => x.Key))}");
92 | }
93 |
94 | //Ensure that these content types have dependencies added
95 | foreach (var contentType in allContentTypes.Values)
96 | {
97 | _logger.Debug("Adding dependency for content type {ContentType}.", contentType.Alias);
98 | dependencies.Add(new ArtifactDependency(contentType.GetUdi(), false, ArtifactDependencyMode.Match));
99 | }
100 |
101 | foreach (var block in allBlocks)
102 | {
103 | var contentType = allContentTypes[block.ContentTypeKey];
104 |
105 | if (block.PropertyValues != null)
106 | {
107 | foreach (var key in block.PropertyValues.Keys.ToArray())
108 | {
109 | var innerPropertyType = contentType.CompositionPropertyTypes.FirstOrDefault(x => x.Alias == key);
110 |
111 | if (innerPropertyType == null)
112 | {
113 | _logger.Warn("No property type found with alias {PropertyType} on content type {ContentType}.", key, contentType.Alias);
114 | continue;
115 | }
116 |
117 | // fetch the right value connector from the collection of connectors, intended for use with this property type.
118 | // throws if not found - no need for a null check
119 | var propertyValueConnector = ValueConnectors.Get(innerPropertyType);
120 |
121 | // pass the value, property type and the dependencies collection to the connector to get a "artifact" value
122 | var innerValue = block.PropertyValues[key];
123 | object parsedValue = propertyValueConnector.ToArtifact(innerValue, innerPropertyType, dependencies, contextCache);
124 |
125 | _logger.Debug("Mapped {Key} value '{PropertyValue}' to '{ParsedValue}' using {PropertyValueConnectorType} for {PropertyType}.", key, block.PropertyValues[key], parsedValue, propertyValueConnector.GetType(), innerPropertyType.Alias);
126 |
127 | parsedValue = parsedValue?.ToString();
128 |
129 | block.PropertyValues[key] = parsedValue;
130 | }
131 | }
132 | }
133 |
134 | value = JsonConvert.SerializeObject(blockEditorValue);
135 | _logger.Debug("Finished converting {PropertyType} to artifact.", propertyType.Alias);
136 | return (string)value;
137 | }
138 |
139 | public override object FromArtifact(string value, PropertyType propertyType, object currentValue, IContextCache contextCache)
140 | {
141 | _logger.Debug("Converting {PropertyType} from artifact.", propertyType.Alias);
142 | if (string.IsNullOrWhiteSpace(value))
143 | {
144 | return value;
145 | }
146 |
147 | if (!value.TryParseJson(out BlockEditorValue blockEditorValue))
148 | {
149 | return value;
150 | }
151 |
152 | if (blockEditorValue == null)
153 | {
154 | return value;
155 | }
156 |
157 | var allBlocks = blockEditorValue.Content.Concat(blockEditorValue.Settings ?? Enumerable.Empty()).ToList();
158 |
159 | var allContentTypes = allBlocks.Select(x => x.ContentTypeKey)
160 | .Distinct()
161 | .ToDictionary(a => a, a =>
162 | {
163 | if (!Guid.TryParse(a, out var keyAsGuid))
164 | {
165 | throw new InvalidOperationException($"Could not parse ContentTypeKey as GUID {keyAsGuid}.");
166 | }
167 |
168 | return contextCache.GetContentTypeByKey(_contentTypeService, keyAsGuid);
169 | });
170 |
171 | //Ensure all of these content types are found
172 | if (allContentTypes.Values.Any(contentType => contentType == null))
173 | {
174 | throw new InvalidOperationException($"Could not resolve these content types for the Block Editor property: {string.Join(",", allContentTypes.Where(x => x.Value == null).Select(x => x.Key))}");
175 | }
176 |
177 | foreach (var block in allBlocks)
178 | {
179 | var contentType = allContentTypes[block.ContentTypeKey];
180 |
181 | if (block.PropertyValues != null)
182 | {
183 | foreach (var key in block.PropertyValues.Keys.ToArray())
184 | {
185 | var innerPropertyType = contentType.CompositionPropertyTypes.FirstOrDefault(x => x.Alias == key);
186 |
187 | if (innerPropertyType == null)
188 | {
189 | _logger.Warn("No property type found with alias {Key} on content type {ContentType}.", key, contentType.Alias);
190 | continue;
191 | }
192 |
193 | // fetch the right value connector from the collection of connectors, intended for use with this property type.
194 | // throws if not found - no need for a null check
195 | var propertyValueConnector = ValueConnectors.Get(innerPropertyType);
196 |
197 | var innerValue = block.PropertyValues[key];
198 |
199 | if (innerValue != null)
200 | {
201 | // pass the artifact value and property type to the connector to get a real value from the artifact
202 | var convertedValue = propertyValueConnector.FromArtifact(innerValue.ToString(), innerPropertyType, null, contextCache);
203 |
204 | if (convertedValue == null)
205 | {
206 | block.PropertyValues[key] = null;
207 | }
208 | else
209 | {
210 | block.PropertyValues[key] = convertedValue;
211 | }
212 | _logger.Debug("Mapped {Key} value '{PropertyValue}' to '{ConvertedValue}' using {PropertyValueConnectorType} for {PropertyType}.", key, innerValue, convertedValue, propertyValueConnector.GetType(), innerPropertyType.Alias);
213 | }
214 | else
215 | {
216 | block.PropertyValues[key] = innerValue;
217 | _logger.Debug("{Key} value was null. Setting value as null without conversion.", key);
218 | }
219 | }
220 | }
221 | }
222 |
223 | _logger.Debug("Finished converting {PropertyType} from artifact.", propertyType.Alias);
224 |
225 | return JObject.FromObject(blockEditorValue);
226 | }
227 |
228 | ///
229 | /// Strongly typed representation of the stored value for a block editor value
230 | ///
231 | ///
232 | /// Example JSON:
233 | ///
267 | ///
268 | public class BlockEditorValue
269 | {
270 | ///
271 | /// We do not have to actually handle anything in the layout since it should only contain references to items existing as data.
272 | /// JObject is fine for transferring this over.
273 | ///
274 | [JsonProperty("layout")]
275 | public JObject Layout { get; set; }
276 |
277 | ///
278 | /// This contains all the blocks created in the block editor.
279 | ///
280 | [JsonProperty("contentData")]
281 | public IEnumerable Content { get; set; }
282 |
283 | ///
284 | /// This contains the settings associated with the block editor.
285 | ///
286 | [JsonProperty("settingsData")]
287 | public IEnumerable Settings { get; set; }
288 | }
289 |
290 | public class Block
291 | {
292 | [JsonProperty("contentTypeKey")]
293 | public string ContentTypeKey { get; set; }
294 |
295 | [JsonProperty("udi")]
296 | public string Udi { get; set; }
297 |
298 | ///
299 | /// This is the property values defined on the block.
300 | /// These can be anything so we have to use a dictionary to represent them and JsonExtensionData attribute ensures all otherwise unmapped properties are stored here.
301 | ///
302 | [JsonExtensionData]
303 | public IDictionary PropertyValues { get; set; }
304 | }
305 | }
306 | }
307 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/ValueConnectors/BlockListValueConnector.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Umbraco.Core.Logging;
4 | using Umbraco.Core.Services;
5 | using Umbraco.Deploy.Connectors.ValueConnectors.Services;
6 |
7 | namespace Umbraco.Deploy.Contrib.Connectors.ValueConnectors
8 | {
9 | ///
10 | /// A Deploy connector for the BlockList property editor
11 | ///
12 | [Obsolete("Deploy 4.9.0 adds an explicit binding to use Umbraco.Deploy.Connectors.ValueConnectors.BlockEditorValueConnector instead to support recursive migrators. This class will be removed in a future version.")]
13 | public class BlockListValueConnector : BlockEditorValueConnector
14 | {
15 | public override IEnumerable PropertyEditorAliases { get; } = new[]
16 | {
17 | "Umbraco.BlockList"
18 | };
19 |
20 | public BlockListValueConnector(IContentTypeService contentTypeService, Lazy valueConnectors, ILogger logger)
21 | : base(contentTypeService, valueConnectors, logger)
22 | { }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/ValueConnectors/MultiUrlPickerValueConnector.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text.RegularExpressions;
4 | using Newtonsoft.Json;
5 | using Newtonsoft.Json.Linq;
6 | using Umbraco.Core;
7 | using Umbraco.Core.Deploy;
8 | using Umbraco.Core.Logging;
9 | using Umbraco.Core.Models;
10 | using Umbraco.Core.Services;
11 | using Umbraco.Deploy.Connectors.ValueConnectors;
12 | using Umbraco.Deploy.Core;
13 |
14 | namespace Umbraco.Deploy.Contrib.Connectors.ValueConnectors
15 | {
16 | [Obsolete("Deploy 4.9.0 adds an explicit binding to use Umbraco.Deploy.Connectors.ValueConnectors.MultiUrlPickerValueConnector instead to support recursive migrators. This class will be removed in a future version.")]
17 | public class MultiUrlPickerValueConnector : ValueConnectorBase
18 | {
19 | private readonly IEntityService _entityService;
20 | private readonly IMediaService _mediaService;
21 | private readonly ILogger _logger;
22 |
23 | // Used to fetch the udi from a umb://-based url
24 | private static readonly Regex MediaUdiSrcRegex = new Regex(@"(?umb://media/[A-z0-9]+)", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
25 |
26 | ///
27 | public override IEnumerable PropertyEditorAliases { get; } = new[]
28 | {
29 | "Umbraco.MultiUrlPicker"
30 | };
31 |
32 | ///
33 | /// Initializes a new instance of the class.
34 | /// Source found here: https://github.com/rasmusjp/umbraco-multi-url-picker
35 | /// MultiUrlPicker can have a list of links, these can be document links, links to files in the
36 | /// media library, or just a text string with a link to whatever. We need to resolve if its a link
37 | /// to a document or a file in the media library, and transfer it as an artifact to the target environment.
38 | /// The object value is stored as json, and is an array of Links, defined with the following properties
39 | /// Link = {
40 | /// id,
41 | /// name,
42 | /// url,
43 | /// target,
44 | /// isMedia,
45 | /// icon
46 | /// }
47 | /// https://github.com/rasmusjp/umbraco-multi-url-picker/blob/master/src/RJP.MultiUrlPicker/App_Plugins/RJP.MultiUrlPicker/MultiUrlPicker.js#L120
48 | ///
49 | /// An implementation.
50 | ///
51 | ///
52 | public MultiUrlPickerValueConnector(IEntityService entityService, IMediaService mediaService, ILogger logger)
53 | {
54 | _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService));
55 | _mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService));
56 | _logger = logger ?? throw new ArgumentNullException(nameof(logger));
57 | }
58 |
59 | public sealed override string ToArtifact(object value, PropertyType propertyType, ICollection dependencies, IContextCache contextCache)
60 | {
61 | var svalue = value as string;
62 | if (string.IsNullOrWhiteSpace(svalue))
63 | {
64 | return null;
65 | }
66 |
67 | var valueAsJToken = JToken.Parse(svalue);
68 | if (valueAsJToken is JArray)
69 | {
70 | // Multiple links, parse as JArray
71 | var links = JsonConvert.DeserializeObject(svalue);
72 | if (links == null)
73 | {
74 | return null;
75 | }
76 |
77 | foreach (var link in links)
78 | {
79 | var isMedia = link["isMedia"] != null;
80 |
81 | // Only do processing if the Id is set on the element. OR if the url is set and its a media item
82 | if (TryParseJTokenAttr(link, "id", out int intId))
83 | {
84 | // Checks weather we are resolving a media item or a document
85 | var objectTypeId = isMedia
86 | ? UmbracoObjectTypes.Media
87 | : UmbracoObjectTypes.Document;
88 | var entityType = isMedia ? Constants.UdiEntityType.Media : Constants.UdiEntityType.Document;
89 |
90 | var guidAttempt = contextCache.GetEntityKeyById(_entityService, intId, objectTypeId);
91 | if (guidAttempt.Success == false)
92 | {
93 | continue;
94 | }
95 |
96 | var udi = new GuidUdi(entityType, guidAttempt.Result);
97 |
98 | // Add the artifact dependency
99 | dependencies.Add(new ArtifactDependency(udi, false, ArtifactDependencyMode.Exist));
100 |
101 | // Set the Id attribute to the udi
102 | link["id"] = udi.ToString();
103 | }
104 | else if (TryParseJTokenAttr(link, "udi", out GuidUdi guidUdi))
105 | {
106 | var entityExists = contextCache.EntityExists(_entityService, guidUdi.Guid);
107 | if (!entityExists)
108 | {
109 | continue;
110 | }
111 |
112 | // Add the artifact dependency
113 | dependencies.Add(new ArtifactDependency(guidUdi, false, ArtifactDependencyMode.Exist));
114 | }
115 | else if (isMedia && TryParseJTokenAttr(link, "url", out string url))
116 | {
117 | // This state can happen due to an issue in RJP.MultiUrlPicker(or our linkPicker in RTE which it relies on),
118 | // where you edit a media link, and just hit "Select".
119 | // That will set the id to null, but the url will still be filled. We try to get the media item, and if so add it as
120 | // a dependency to the package. If we can't find it, we abort(aka continue)
121 | var entry = _mediaService.GetMediaByPath(url);
122 | if (entry == null)
123 | {
124 | continue;
125 | }
126 |
127 | // Add the artifact dependency
128 | var udi = entry.GetUdi();
129 | dependencies.Add(new ArtifactDependency(udi, false, ArtifactDependencyMode.Exist));
130 |
131 | // Update the url on the item to the udi aka umb://media/fileguid
132 | link["url"] = udi.ToString();
133 | }
134 | }
135 |
136 | return JsonConvert.SerializeObject(links);
137 | }
138 |
139 | if (valueAsJToken is JObject)
140 | {
141 | // Single link, parse as JToken
142 | var link = JsonConvert.DeserializeObject(svalue);
143 | if (link == null)
144 | {
145 | return string.Empty;
146 | }
147 |
148 | var isMedia = link["isMedia"] != null;
149 |
150 | // Only do processing if the Id is set on the element. OR if the url is set and its a media item
151 | if (TryParseJTokenAttr(link, "id", out int intId))
152 | {
153 | // Checks weather we are resolving a media item or a document
154 | var objectTypeId = isMedia
155 | ? UmbracoObjectTypes.Media
156 | : UmbracoObjectTypes.Document;
157 | var entityType = isMedia ? Constants.UdiEntityType.Media : Constants.UdiEntityType.Document;
158 |
159 | var guidAttempt = contextCache.GetEntityKeyById(_entityService, intId, objectTypeId);
160 | if (guidAttempt.Success)
161 | {
162 | var udi = new GuidUdi(entityType, guidAttempt.Result);
163 |
164 | // Add the artifact dependency
165 | dependencies.Add(new ArtifactDependency(udi, false, ArtifactDependencyMode.Exist));
166 |
167 | // Set the Id attribute to the udi
168 | link["id"] = udi.ToString();
169 | }
170 | }
171 | else if (TryParseJTokenAttr(link, "udi", out GuidUdi guidUdi))
172 | {
173 | if (contextCache.EntityExists(_entityService, guidUdi.Guid))
174 | {
175 | // Add the artifact dependency
176 | dependencies.Add(new ArtifactDependency(guidUdi, false, ArtifactDependencyMode.Exist));
177 | }
178 | }
179 | else if (isMedia && TryParseJTokenAttr(link, "url", out string url))
180 | {
181 | // This state can happen due to an issue in RJP.MultiUrlPicker(or our linkPicker in RTE which it relies on),
182 | // where you edit a media link, and just hits "Select".
183 | // That will set the id to null, but the url will still be filled. We try to get the media item, and if so add it as
184 | // a dependency to the package. If we can't find it, we abort(aka continue)
185 | var entry = _mediaService.GetMediaByPath(url);
186 | if (entry != null)
187 | {
188 | // Add the artifact dependency
189 | var udi = entry.GetUdi();
190 | dependencies.Add(new ArtifactDependency(udi, false, ArtifactDependencyMode.Exist));
191 |
192 | // Update the url on the item to the udi aka umb://media/fileguid
193 | link["url"] = udi.ToString();
194 | }
195 | }
196 |
197 | return JsonConvert.SerializeObject(link);
198 | }
199 |
200 | // If none of the above...
201 | return string.Empty;
202 | }
203 |
204 | public sealed override object FromArtifact(string value, PropertyType propertyType, object currentValue, IContextCache contextCache)
205 | {
206 | if (string.IsNullOrWhiteSpace(value))
207 | {
208 | return value;
209 | }
210 |
211 | var valueAsJToken = JToken.Parse(value);
212 | if (valueAsJToken is JArray)
213 | {
214 | // Multiple links, parse as JArray
215 | var links = JsonConvert.DeserializeObject(value);
216 | if (links != null)
217 | {
218 | foreach (var link in links)
219 | {
220 | // Only do processing on an item if the Id or the url is set
221 | if (TryParseJTokenAttr(link, "id", out GuidUdi udi))
222 | {
223 | // Check the type of the link
224 | var nodeObjectType = link["isMedia"] != null
225 | ? UmbracoObjectTypes.Media
226 | : UmbracoObjectTypes.Document;
227 |
228 | // Get the Id corresponding to the Guid
229 | // it *should* succeed when deploying, due to dependencies management
230 | // nevertheless, assume it can fail, and then create an invalid localLink
231 | var idAttempt = contextCache.GetEntityIdByKey(_entityService, udi.Guid, nodeObjectType);
232 | if (idAttempt)
233 | {
234 | link["id"] = idAttempt.Success ? idAttempt.Result : 0;
235 | }
236 | }
237 | else if (TryParseJTokenAttr(link, "url", out string url))
238 | {
239 | // Check whether the url attribute of the link contains a udi, if so, replace it with the
240 | // path to the file, i.e. the regex replaces with /path/to/file
241 | var newUrl = MediaUdiSrcRegex.Replace(url, match =>
242 | {
243 | var udiString = match.Groups["udi"].ToString();
244 | if (GuidUdi.TryParse(udiString, out var foundUdi) &&
245 | foundUdi.EntityType == Constants.UdiEntityType.Media)
246 | {
247 | // (take care of nulls)
248 | var media = _mediaService.GetById(foundUdi.Guid);
249 | if (media != null)
250 | {
251 | return media.GetUrl("umbracoFile", _logger);
252 | }
253 | }
254 |
255 | return string.Empty;
256 | });
257 |
258 | link["url"] = newUrl;
259 | }
260 | }
261 |
262 | value = JsonConvert.SerializeObject(links);
263 | }
264 | }
265 | else if (valueAsJToken is JObject)
266 | {
267 | // Single link, parse as JToken
268 | var link = JsonConvert.DeserializeObject(value);
269 |
270 | // Only do processing on an item if the Id or the url is set
271 | if (TryParseJTokenAttr(link, "id", out GuidUdi udi))
272 | {
273 | // Check the type of the link
274 | var nodeObjectType = link["isMedia"] != null
275 | ? UmbracoObjectTypes.Media
276 | : UmbracoObjectTypes.Document;
277 |
278 | // Get the Id corresponding to the Guid
279 | // it *should* succeed when deploying, due to dependencies management
280 | // nevertheless, assume it can fail, and then create an invalid localLink
281 | var idAttempt = contextCache.GetEntityIdByKey(_entityService, udi.Guid, nodeObjectType);
282 | if (idAttempt)
283 | {
284 | link["id"] = idAttempt.Success ? idAttempt.Result : 0;
285 | }
286 | }
287 | else if (TryParseJTokenAttr(link, "url", out string url))
288 | {
289 | // Check whether the url attribute of the link contains a udi, if so, replace it with the
290 | // path to the file, i.e. the regex replaces with /path/to/file
291 | var newUrl = MediaUdiSrcRegex.Replace(url, match =>
292 | {
293 | var udiString = match.Groups["udi"].ToString();
294 | if (GuidUdi.TryParse(udiString, out var foundUdi) &&
295 | foundUdi.EntityType == Constants.UdiEntityType.Media)
296 | {
297 | // (take care of nulls)
298 | var media = _mediaService.GetById(foundUdi.Guid);
299 | if (media != null)
300 | {
301 | return media.GetUrl("umbracoFile", _logger);
302 | }
303 | }
304 |
305 | return string.Empty;
306 | });
307 |
308 | link["url"] = newUrl;
309 | }
310 |
311 | value = JsonConvert.SerializeObject(link);
312 | }
313 |
314 | return value;
315 | }
316 |
317 | private bool TryParseJTokenAttr(JToken link, string attrName, out int attrValue)
318 | {
319 | if (link[attrName] != null)
320 | {
321 | var val = link[attrName].ToString();
322 | return int.TryParse(val, out attrValue);
323 | }
324 |
325 | attrValue = 0;
326 | return false;
327 | }
328 |
329 | private bool TryParseJTokenAttr(JToken link, string attrName, out GuidUdi attrValue)
330 | {
331 | if (link[attrName] != null)
332 | {
333 | var val = link[attrName].ToString();
334 | return GuidUdi.TryParse(val, out attrValue);
335 | }
336 |
337 | attrValue = null;
338 | return false;
339 | }
340 |
341 | private bool TryParseJTokenAttr(JToken link, string attrName, out string strAttr)
342 | {
343 | if (link[attrName] != null)
344 | {
345 | var val = link[attrName].ToString();
346 | if (string.IsNullOrEmpty(val) == false)
347 | {
348 | strAttr = val;
349 | return true;
350 | }
351 | }
352 |
353 | strAttr = string.Empty;
354 | return false;
355 | }
356 | }
357 | }
358 |
--------------------------------------------------------------------------------
/src/Umbraco.Deploy.Contrib/ValueConnectors/NestedContentValueConnector.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using Newtonsoft.Json;
5 | using Newtonsoft.Json.Linq;
6 | using Umbraco.Core;
7 | using Umbraco.Core.Deploy;
8 | using Umbraco.Core.Logging;
9 | using Umbraco.Core.Models;
10 | using Umbraco.Core.Services;
11 | using Umbraco.Deploy.Connectors;
12 | using Umbraco.Deploy.Connectors.ValueConnectors;
13 | using Umbraco.Deploy.Connectors.ValueConnectors.Services;
14 | using Umbraco.Deploy.Core;
15 | using Umbraco.Deploy.Extensions;
16 |
17 | namespace Umbraco.Deploy.Contrib.Connectors.ValueConnectors
18 | {
19 | ///
20 | /// A Deploy connector for the NestedContent property editor
21 | ///
22 | [Obsolete("Deploy 4.9.0 adds an explicit binding to use Umbraco.Deploy.Connectors.ValueConnectors.NestedContentValueConnector instead to support recursive migrators. This class will be removed in a future version.")]
23 | public class NestedContentValueConnector : ValueConnectorBase
24 | {
25 | private readonly IContentTypeService _contentTypeService;
26 | private readonly Lazy _valueConnectorsLazy;
27 | private readonly ILogger _logger;
28 |
29 | ///
30 | ///
31 | /// Our.Umbraco.NestedContent is the original NestedContent package
32 | /// Umbraco.NestedContent is Core NestedContent (introduced in v7.7)
33 | ///
34 | public override IEnumerable PropertyEditorAliases { get; } = new[]
35 | {
36 | "Umbraco.NestedContent"
37 | };
38 |
39 | // cannot inject ValueConnectorCollection as it creates a circular (recursive) dependency,
40 | // so we have to inject it lazily and use the lazy value when actually needing it
41 | private ValueConnectorCollection ValueConnectors => _valueConnectorsLazy.Value;
42 |
43 | public NestedContentValueConnector(IContentTypeService contentTypeService, Lazy valueConnectors, ILogger logger)
44 | {
45 | _contentTypeService = contentTypeService ?? throw new ArgumentNullException(nameof(contentTypeService));
46 | _valueConnectorsLazy = valueConnectors ?? throw new ArgumentNullException(nameof(valueConnectors));
47 | _logger = logger ?? throw new ArgumentNullException(nameof(logger));
48 | }
49 |
50 | public sealed override string ToArtifact(object value, PropertyType propertyType, ICollection dependencies, IContextCache contextCache)
51 | {
52 | _logger.Debug("Converting {PropertyType} to artifact.", propertyType.Alias);
53 | var valueAsString = value as string;
54 |
55 | if (string.IsNullOrWhiteSpace(valueAsString))
56 | {
57 | _logger.Debug($"Value is null or whitespace. Skipping conversion to artifact.");
58 | return null;
59 | }
60 |
61 | var nestedContent = new List();
62 | if (valueAsString.Trim().StartsWith("{"))
63 | {
64 | if (valueAsString.TryParseJson(out NestedContentValue nestedContentObjectValue))
65 | {
66 | nestedContent.Add(nestedContentObjectValue);
67 | }
68 | else
69 | {
70 | _logger.Warn("Value '{Value}' is not a JSON string. Skipping conversion to artifact.", valueAsString);
71 | return null;
72 | }
73 | }
74 | else
75 | {
76 | if (valueAsString.TryParseJson(out NestedContentValue[] nestedContentCollectionValue))
77 | {
78 | nestedContent.AddRange(nestedContentCollectionValue);
79 | }
80 | else
81 | {
82 | _logger.Warn("Value '{Value}' is not a JSON string. Skipping conversion to artifact.", valueAsString);
83 | return null;
84 | }
85 | }
86 |
87 | if (nestedContent.All(x => x == null))
88 | {
89 | _logger.Warn("Value contained no elements. Skipping conversion to artifact.");
90 | return null;
91 | }
92 |
93 | var allContentTypes = nestedContent.Select(x => x.ContentTypeAlias)
94 | .Distinct()
95 | .ToDictionary(a => a, a => contextCache.GetContentTypeByAlias(_contentTypeService, a));
96 |
97 | //Ensure all of these content types are found
98 | if (allContentTypes.Values.Any(contentType => contentType == null))
99 | {
100 | throw new InvalidOperationException($"Could not resolve these content types for the Nested Content property: {string.Join(",", allContentTypes.Where(x => x.Value == null).Select(x => x.Key))}.");
101 | }
102 |
103 | //Ensure that these content types have dependencies added
104 | foreach (var contentType in allContentTypes.Values)
105 | {
106 | _logger.Debug("Adding dependency for content type {ContentType}.", contentType.Alias);
107 | dependencies.Add(new ArtifactDependency(contentType.GetUdi(), false, ArtifactDependencyMode.Match));
108 | }
109 |
110 | foreach (var row in nestedContent)
111 | {
112 | var contentType = allContentTypes[row.ContentTypeAlias];
113 |
114 | foreach (var key in row.PropertyValues.Keys.ToArray())
115 | {
116 | // key is a system property that is added by NestedContent in Core v7.7
117 | // see note in NestedContentValue - leave it unchanged
118 | if (key == "key")
119 | {
120 | continue;
121 | }
122 |
123 | var innerPropertyType = contentType.CompositionPropertyTypes.FirstOrDefault(x => x.Alias == key);
124 |
125 | if (innerPropertyType == null)
126 | {
127 | _logger.Warn("No property type found with alias {PropertyType} on content type {ContentType}.", key, propertyType.Alias);
128 | continue;
129 | }
130 |
131 | // fetch the right value connector from the collection of connectors, intended for use with this property type.
132 | // throws if not found - no need for a null check
133 | var propertyValueConnector = ValueConnectors.Get(innerPropertyType);
134 |
135 | // pass the value, property type and the dependencies collection to the connector to get a "artifact" value
136 | var innerValue = row.PropertyValues[key];
137 |
138 | // connectors are expecting strings, not JTokens
139 | object preparedValue = innerValue is JToken
140 | ? innerValue?.ToString()
141 | : innerValue;
142 | object parsedValue = propertyValueConnector.ToArtifact(preparedValue, innerPropertyType, dependencies, contextCache);
143 |
144 | // getting Map image value umb://media/43e7401fb3cd48ceaa421df511ec703c to (nothing) - why?!
145 | _logger.Debug("Mapped {Key} value '{PropertyValue}' to '{ParsedValue}' using {PropertyValueConnectorType} for {PropertyType}.", key, row.PropertyValues[key], parsedValue, propertyValueConnector.GetType(), innerPropertyType.Alias);
146 |
147 | parsedValue = parsedValue?.ToString();
148 |
149 | row.PropertyValues[key] = parsedValue;
150 | }
151 | }
152 |
153 | value = JsonConvert.SerializeObject(nestedContent);
154 | _logger.Debug("Finished converting {PropertyType} to artifact.", propertyType.Alias);
155 | return (string)value;
156 | }
157 |
158 | public sealed override object FromArtifact(string value, PropertyType propertyType, object currentValue, IContextCache contextCache)
159 | {
160 | _logger.Debug("Converting {PropertyType} from artifact.", propertyType.Alias);
161 | if (string.IsNullOrWhiteSpace(value))
162 | {
163 | _logger.Debug($"Value is null or whitespace. Skipping conversion from artifact.");
164 | return value;
165 | }
166 |
167 | if (!value.TryParseJson(out NestedContentValue[] nestedContent))
168 | {
169 | _logger.Warn("Value '{Value}' is not a json string. Skipping conversion from artifact.", value);
170 | return value;
171 | }
172 |
173 | if (nestedContent == null || nestedContent.All(x => x == null))
174 | {
175 | _logger.Warn("Value contained no elements. Skipping conversion from artifact.");
176 | return value;
177 | }
178 |
179 | var allContentTypes = nestedContent.Select(x => x.ContentTypeAlias)
180 | .Distinct()
181 | .ToDictionary(a => a, a => contextCache.GetContentTypeByAlias(_contentTypeService, a));
182 |
183 | //Ensure all of these content types are found
184 | if (allContentTypes.Values.Any(contentType => contentType == null))
185 | {
186 | throw new InvalidOperationException($"Could not resolve these content types for the Nested Content property: {string.Join(",", allContentTypes.Where(x => x.Value == null).Select(x => x.Key))}.");
187 | }
188 |
189 | foreach (var row in nestedContent)
190 | {
191 | var contentType = allContentTypes[row.ContentTypeAlias];
192 |
193 | foreach (var key in row.PropertyValues.Keys.ToArray())
194 | {
195 | // key is a system property that is added by NestedContent in Core v7.7
196 | // see note in NestedContentValue - leave it unchanged
197 | if (key == "key")
198 | {
199 | continue;
200 | }
201 |
202 | var innerPropertyType = contentType.CompositionPropertyTypes.FirstOrDefault(x => x.Alias == key);
203 |
204 | if (innerPropertyType == null)
205 | {
206 | _logger.Warn("No property type found with alias {PropertyType} on content type {ContentType}.", key, contentType.Alias);
207 | continue;
208 | }
209 |
210 | // fetch the right value connector from the collection of connectors, intended for use with this property type.
211 | // throws if not found - no need for a null check
212 | var propertyValueConnector = ValueConnectors.Get(innerPropertyType);
213 |
214 | var innerValue = row.PropertyValues[key];
215 |
216 | if (innerValue != null)
217 | {
218 | // pass the artifact value and property type to the connector to get a real value from the artifact
219 | var convertedValue = propertyValueConnector.FromArtifact(innerValue.ToString(), innerPropertyType, null, contextCache);
220 |
221 | if (convertedValue == null)
222 | {
223 | row.PropertyValues[key] = null;
224 | }
225 | // integers needs to be converted into strings
226 | else if (convertedValue is int)
227 | {
228 | row.PropertyValues[key] = convertedValue.ToString();
229 | }
230 | // json strings need to be converted into JTokens
231 | else if (convertedValue is string convertedStringValue && convertedStringValue.TryParseJson(out JToken valueAsJToken))
232 | {
233 | row.PropertyValues[key] = valueAsJToken;
234 | }
235 | else
236 | {
237 | row.PropertyValues[key] = convertedValue;
238 | }
239 | _logger.Debug("Mapped {Key} value '{PropertyValue}' to '{ConvertedValue}' using {PropertyValueConnectorType} for {PropertyType}.", key, innerValue, convertedValue, propertyValueConnector.GetType(), innerPropertyType.Alias);
240 | }
241 | else
242 | {
243 | row.PropertyValues[key] = innerValue;
244 | _logger.Debug("{Key} value was null. Setting value as null without conversion.", key);
245 | }
246 | }
247 | }
248 |
249 | // Note: NestedContent does not use formatting when serializing JSON values.
250 | value = JArray.FromObject(nestedContent).ToString(Formatting.None);
251 |
252 | _logger.Debug("Finished converting {PropertyType} from artifact.", propertyType.Alias);
253 |
254 | return value;
255 | }
256 |
257 | ///
258 | /// The typed value stored for Nested Content
259 | ///
260 | ///
261 | /// An example of the JSON stored for NestedContent is:
262 | /// asdfasdfasdfasdf
\nasdf
\n
\nasdf
"},
265 | /// {"name":"Content","ncContentTypeAlias":"nC1","text":"This is ","multiText":"pretty cool","rTE":""}
266 | /// ]
267 | /// ]]>
268 | ///
269 | public class NestedContentValue
270 | {
271 | [JsonProperty("name")]
272 | public string Name { get; set; }
273 |
274 | [JsonProperty("ncContentTypeAlias")]
275 | public string ContentTypeAlias { get; set; }
276 |
277 | ///
278 | /// The remaining properties will be serialized to a dictionary
279 | ///
280 | ///
281 | /// The JsonExtensionDataAttribute is used to put the non-typed properties into a bucket
282 | /// http://www.newtonsoft.com/json/help/html/DeserializeExtensionData.htm
283 | /// NestedContent serializes to string, int, whatever eg
284 | /// "stringValue":"Some String","numericValue":125,"otherNumeric":null
285 | ///
286 | [JsonExtensionData]
287 | public IDictionary PropertyValues { get; set; }
288 | }
289 | }
290 | }
291 |
--------------------------------------------------------------------------------
/tests/.editorconfig:
--------------------------------------------------------------------------------
1 | root = false
2 |
3 | [*.cs]
4 | csharp_style_var_when_type_is_apparent = true:none
5 | csharp_style_var_elsewhere = true:none
--------------------------------------------------------------------------------
/tests/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | false
9 | $(EnablePackageValidation)
10 | false
11 |
12 |
13 |
14 |
15 | $(MSBuildThisFileDirectory)codeanalysis.ruleset
16 |
17 |
18 |
--------------------------------------------------------------------------------
/tests/Directory.Packages.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/tests/Umbraco.Deploy.Contrib.Tests/Umbraco.Deploy.Contrib.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/tests/codeanalysis.ruleset:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/version.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json",
3 | "version": "4.5.0-alpha",
4 | "assemblyVersion": {
5 | "precision": "build"
6 | },
7 | "gitCommitIdShortFixedLength": 7,
8 | "nuGetPackageVersion": {
9 | "semVer": 2.0
10 | },
11 | "publicReleaseRefSpec": [
12 | "^refs/heads/main$",
13 | "^refs/tags/release-"
14 | ],
15 | "cloudBuild": {
16 | "setAllVariables": true,
17 | "buildNumber": {
18 | "enabled": true
19 | }
20 | },
21 | "release": {
22 | "tagName": "release-{version}",
23 | "branchName": "release/{version}"
24 | }
25 | }
--------------------------------------------------------------------------------