Compare commits

...
224 Commits
Author SHA1 Message Date
Andy Butland c6ab394947 Merge branch 'release/10.8.11' into v10/dev
# Conflicts:
#	version.json
2025-07-02 06:32:18 +02:00
Kenn JacobsenandGitHub d8f68d2c40 Merge commit from fork 2025-06-24 08:39:17 +02:00
Andy Butland ff88617db0 Bumped version to 10.8.11. 2025-06-05 07:49:09 +02:00
Andy Butland 9f912aea0e Merge branch 'release/10.8.10' into v10/dev
# Conflicts:
#	version.json
2025-05-06 07:15:10 +02:00
Andy Butland ba95c12f09 Resolved failures in unit tests. 2025-05-06 05:37:30 +02:00
Andy ButlandandGitHub 14fbd20665 Merge commit from fork
* Backport user enumeration fix.

* Supress warning on use of .NET 6 with TimeProvider dependency.

* Replace TimeProvider with Stopwatch, as the former isn't tested against .NET 6.0 and generates warnings.

* Remove full path details from exception when requesting a path outside of the physical file system's root.

* Added randomness to login duration.

* Ensured against negative duration.
2025-05-06 05:11:03 +02:00
mole 2d8b5e8786 Use windows agent for nuget push 2025-04-28 10:48:26 +02:00
Andy Butland 747e095178 Bump version to 10.8.10. 2025-04-22 10:06:27 +02:00
Andy Butland 1cfa5a225e Merge branch 'release/10.8.9' into v10/dev
# Conflicts:
#	version.json
2025-03-11 09:20:51 +01:00
7888b9a4ce Merge commit from fork
* Bumped version to 10.8.9.

* Fixed parsing of node if in content and media permission querystring handlers to retrieve expected value when multiple are provided in the querystring.

# Conflicts:
#	tests/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Authorization/ContentPermissionsQueryStringHandlerTests.cs
#	tests/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Authorization/MediaPermissionsQueryStringHandlerTests.cs

* Add HttpPost attributes to backoffice endpoints that should only accept post requests.

* Narrow PermissionQueryString parsing to the releveant UmbracoObjectType

* Add missed update from v10

---------

Co-authored-by: Sven Geusens <sge@umbraco.dk>
2025-03-11 05:11:08 +01:00
Andy Butland e31582b297 Backport bumped imagesharp to prevent CVE-2025-27598 #18602 2025-03-09 08:58:25 +01:00
Nikolaj Geisle 75cc017a18 Merge branch 'release/10.8.8' into v10/dev
# Conflicts:
#	version.json
2025-01-23 11:08:09 +01:00
d60137e6da Merge commit from fork
* Ensure preview can only be requested with a valid culture code.

* Update src/Umbraco.Web.BackOffice/Controllers/PreviewController.cs

Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>

* Restricted to predefined culture codes.

---------

Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>
2025-01-20 14:14:28 +01:00
Andy Butland 9f9c88781a Bumped version to 10.8.8. 2025-01-07 10:08:01 +01:00
c7014e159b Sort manifest file paths alphabetically (#14466)
* Sort manifest file paths alphabetically

* Update src/Umbraco.Infrastructure/Manifest/ManifestParser.cs

Co-authored-by: Ronald Barendse <ronald@barend.se>

---------

Co-authored-by: Ronald Barendse <ronald@barend.se>
2024-11-21 16:19:48 +01:00
Zeegaan 31e1acce67 Merge remote-tracking branch 'origin/release/10.8.7' into v10/dev
# Conflicts:
#	version.json
2024-10-23 08:48:08 +02:00
Sven GeusensandNikolaj Geisle 35c51a029a Prevents XSS when viewing an uploaded SVG
from the media-info and image-preview components.
2024-10-21 12:42:06 +02:00
ElitsaandNikolaj Geisle 8c1128c85b Update the HttpContext's user with the authenticated user's principal 2024-10-21 12:41:42 +02:00
ElitsaandNikolaj Geisle c9021ab2d2 Reduce the time when getRemainingTimeoutSeconds request is made from 30s to 20s, so fewer calls are made 2024-10-21 12:41:18 +02:00
ElitsaandNikolaj Geisle 67a71f8f82 Make sure that the client shows the login screen as close to the server's timout time as possible 2024-10-21 12:41:17 +02:00
Andreas ZerbstandAndreas Zerbst edd0a4a4a9 Updated message pack (#17320)
(cherry picked from commit 11270eaaf5)
2024-10-21 11:46:43 +02:00
Andreas ZerbstandGitHub 11270eaaf5 Updated message pack (#17320) 2024-10-21 11:00:47 +02:00
Bjarke BergandGitHub 2d71b5a63b Updated image sharp to a non vulnerable version (#17290) 2024-10-16 12:16:38 +02:00
Nikolaj Geisle 9bab74d30e Bump version.json 2024-10-07 11:55:34 +02:00
Bjarke Berg 0ee0db8071 Merge remote-tracking branch 'refs/remotes/origin/release/10.8' into v10/dev
# Conflicts:
#	version.json
2024-05-21 08:44:27 +02:00
Bjarke BergandGitHub c17d4e1a60 Merge pull request from GHSA-j74q-mv2c-rxmp 2024-05-17 08:37:51 +02:00
Bjarke Berg fee222daff Bump version 2024-05-03 09:29:37 +02:00
119fde2033 V10: Fix for fallback file upload (#14892) (#15868)
* Fix for fallback file upload (#14892)

* Added check for file type

* Removed unneeded null checks and fixed tabs

* Cleaning

* Cleanups, cleanups, and removal of unneeded null checks

* Reverted removal of relationshipservice

* Revert null check removals (too risky)

---------

Co-authored-by: Ambert van Unen <AvanUnen@ilionx.com>
Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>

(cherry picked from commit 0b5d1f8aa6)

* Fix up formatting

---------

Co-authored-by: Ambert van Unen <ambertvu@gmail.com>
2024-04-24 13:44:20 +02:00
Andy ButlandandGitHub 52c21b0fca Updates JSON schema for Umbraco 10 with latest references for Forms and Deploy (#15918) 2024-03-20 13:20:40 +01:00
Bjarke Berg 99d5a7e609 Merge remote-tracking branch 'origin/release/10.8' into v10/dev 2024-03-19 08:43:59 +01:00
JeyandBjarke Berg 7e1d1a1968 Merge pull request from GHSA-552f-97wf-pmpq
Co-authored-by: jey <jey@umbraco.dk>
(cherry picked from commit b743f6a2df)
2024-03-18 08:28:25 +01:00
b743f6a2df Merge pull request from GHSA-552f-97wf-pmpq
Co-authored-by: jey <jey@umbraco.dk>
2024-03-18 08:27:41 +01:00
Bjarke Berg a2511ff09b Fixing locking issues for document type saves. (#15854)
* Added  ExecuteNonQuery(DbCommand command) on database to ensure we call OnExecutingCommand and OnExecutedCommand when executing DbCommands

* Added Cache Instructions lock, to avoid deadlocks

* Optimized read locks for nucache when only one content type is rebuilt

* Optimized the SqlServer locks, so only one command is executed (and thereby roundtrip) per lock instead of two

* Avoid breaking changes

* Cosmetic changes

* Take locks if everything is rebuild

* Use same lock in scopes, to avoid potential deadlocks between the two

* Use eager locks in PublishedSnapshotService.cs

* Added timeouts to some of the application locks

* Revert "Use eager locks in PublishedSnapshotService.cs"

This reverts commit 01873aae97.

* Revert "Added Cache Instructions lock, to avoid deadlocks"

This reverts commit e3fca7c12a.

* Use single readlock call to lock many

* Use eager locks for reads

* Eager write locks

* Ignore test of lazy locks

* Unique timeout exception messages

---------

Co-authored-by: kjac <kja@umbraco.dk>
(cherry picked from commit 2c23e67c65)
2024-03-15 14:55:20 +01:00
2c23e67c65 Fixing locking issues for document type saves. (#15854)
* Added  ExecuteNonQuery(DbCommand command) on database to ensure we call OnExecutingCommand and OnExecutedCommand when executing DbCommands

* Added Cache Instructions lock, to avoid deadlocks

* Optimized read locks for nucache when only one content type is rebuilt

* Optimized the SqlServer locks, so only one command is executed (and thereby roundtrip) per lock instead of two

* Avoid breaking changes

* Cosmetic changes

* Take locks if everything is rebuild

* Use same lock in scopes, to avoid potential deadlocks between the two

* Use eager locks in PublishedSnapshotService.cs

* Added timeouts to some of the application locks

* Revert "Use eager locks in PublishedSnapshotService.cs"

This reverts commit 01873aae97.

* Revert "Added Cache Instructions lock, to avoid deadlocks"

This reverts commit e3fca7c12a.

* Use single readlock call to lock many

* Use eager locks for reads

* Eager write locks

* Ignore test of lazy locks

* Unique timeout exception messages

---------

Co-authored-by: kjac <kja@umbraco.dk>
2024-03-15 10:56:02 +01:00
Bjarke Berg 8e837d387d Merge remote-tracking branch 'origin/v10/dev' into release/10.8
# Conflicts:
#	version.json
2024-03-14 14:53:42 +01:00
Bjarke Berg 801fb5f885 Bump version 2024-03-14 14:48:09 +01:00
Bjarke BergandGitHub ed517ecd86 Update Imagesharp (#15885) 2024-03-14 14:31:30 +01:00
Bjarke Berg b5e46ba880 Merge remote-tracking branch 'origin/release/10.8' into v10/dev 2024-02-06 11:07:16 +01:00
Nikolaj GeisleandGitHub cbf9f9bcd1 Merge pull request from GHSA-gvpc-3pj6-4m9w
* Add MarkDownPropertyValueEditor with html sanitizer

* Implement IMarkdownSanitizer.
2024-02-06 09:53:40 +01:00
Bjarke Berg 2735f17ed8 Merge remote-tracking branch 'origin/release/10.8' into v10/dev
# Conflicts:
#	version.json
2024-02-01 11:09:47 +01:00
Ronald BarendseandBjarke Berg e37cf30690 Skip cache refresher operations for content blueprints (#15633)
* Skip cache refresher operations for content blueprints

* Fix JsonPayload deserialization error by adding a default constructor and property initializers

* Obsolete JsonPayload constructor and update usages

(cherry picked from commit 3e28e10cdf)
2024-02-01 10:00:42 +01:00
Bjarke BergandGitHub 118ac8e230 V10+ version of https://github.com/umbraco/Umbraco-CMS/pull/15638 (#15664) 2024-02-01 09:58:42 +01:00
Ronald BarendseandGitHub 3e28e10cdf Skip cache refresher operations for content blueprints (#15633)
* Skip cache refresher operations for content blueprints

* Fix JsonPayload deserialization error by adding a default constructor and property initializers

* Obsolete JsonPayload constructor and update usages
2024-02-01 09:55:09 +01:00
AleksanderandBjarke Berg b18b6cc5e7 Pass cache level to properties when creating published content in nucache
(cherry picked from commit d9d2b66e85)

# Conflicts:
#	src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs
(cherry picked from commit 040495f359)
2024-01-31 10:52:01 +01:00
Elitsa MarinovskaandBjarke Berg 7a04baf9ef V10: Pass in variation context to published cache (#15563)
* Make sure that we always have variation context

* Fix references

(cherry picked from commit 57b3a196bf)
2024-01-30 15:57:33 +01:00
Sven GeusensandBjarke Berg bc1ddaed8c Run the same cleanup with scaffolding content as when copying. (#15541)
* Run the same cleanup with scaffolding content as when copying.

- Added a new ContentScaffoldedNotification
- Published the notification when a new scaffold has been created from a blueprint (content template)
- Linked up the ComplextPEContent handler to do the same cleanup for the new notification as when copying.
- registered handlers to the event for blocklist, blockgrid and nested content

* PR pattern matching suggestion

Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>

---------

Co-authored-by: Sven Geusens <sge@umbraco.dk>
Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>
(cherry picked from commit dff90c6ec0)
2024-01-30 15:54:33 +01:00
Bjarke Berg 860afb35f2 Bump version 2024-01-30 15:53:21 +01:00
Ronald BarendseandGitHub 9799c550f4 Create shadow file systems in configured LocalTempPath (#15637) 2024-01-29 08:48:45 +01:00
Ronald BarendseandGitHub b7e43a8def Get references from macro parameters using IDataValueReferenceFactory (#15625) 2024-01-23 16:08:17 +01:00
Ronald BarendseandGitHub cdbbd6a921 Optimize relation tracking for adding new and keeping existing relations (#15596)
* Include automatic relation type aliases from factory and fix SQL parameter overflow (#15141)

* Include automatic relation type aliases from factory

* Remove unnessecary distinct and fix SQL parameter overflow issue

* Fixed assertions and test distinct aliases

* Simplified collection assertions

* Improve logging of invalid reference relations (#15160)

* Include automatic relation type aliases from factory

* Remove unnessecary distinct and fix SQL parameter overflow issue

* Fixed assertions and test distinct aliases

* Simplified collection assertions

* Improve logging of invalid reference relations

* Always get all automatic relation type aliases

* Do not set relation type alias for unknown entity types

* Get references from recursive (nested/block) properties

* Optimize relation tracking for adding new and keeping existing relations

* Optimize getting references by grouping by property editor alias and avoiding duplicate parsing of the same value
2024-01-22 14:53:20 +01:00
Ronald BarendseandGitHub 5198e7c52d Backport relation tracking fixes and get references from recursive (nested/block) properties (#15593)
* Include automatic relation type aliases from factory and fix SQL parameter overflow (#15141)

* Include automatic relation type aliases from factory

* Remove unnessecary distinct and fix SQL parameter overflow issue

* Fixed assertions and test distinct aliases

* Simplified collection assertions

* Improve logging of invalid reference relations (#15160)

* Include automatic relation type aliases from factory

* Remove unnessecary distinct and fix SQL parameter overflow issue

* Fixed assertions and test distinct aliases

* Simplified collection assertions

* Improve logging of invalid reference relations

* Always get all automatic relation type aliases

* Do not set relation type alias for unknown entity types

* Get references from recursive (nested/block) properties
2024-01-19 20:02:57 +01:00
Andy ButlandandGitHub 49f5d2e2d4 Updates JSON schema for Umbraco 10 to include details of additional configuration introduced in Forms and Deploy. (#15566) 2024-01-12 13:13:20 +01:00
Elitsa MarinovskaandGitHub 57b3a196bf V10: Pass in variation context to published cache (#15563)
* Make sure that we always have variation context

* Fix references
2024-01-11 12:46:31 +01:00
dff90c6ec0 Run the same cleanup with scaffolding content as when copying. (#15541)
* Run the same cleanup with scaffolding content as when copying.

- Added a new ContentScaffoldedNotification
- Published the notification when a new scaffold has been created from a blueprint (content template)
- Linked up the ComplextPEContent handler to do the same cleanup for the new notification as when copying.
- registered handlers to the event for blocklist, blockgrid and nested content

* PR pattern matching suggestion

Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>

---------

Co-authored-by: Sven Geusens <sge@umbraco.dk>
Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>
2024-01-10 12:22:36 +01:00
AleksanderandSebastiaan Janssen 040495f359 Pass cache level to properties when creating published content in nucache
(cherry picked from commit d9d2b66e85)

# Conflicts:
#	src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs
2024-01-08 14:42:17 +01:00
Bjarke Berg a2ad95d965 Change content 2023-12-22 13:49:57 +01:00
Bjarke Berg 64f2447c0e Added script to update default version 2023-12-22 13:15:13 +01:00
Bjarke Berg b648126d19 Use wildcard as default valid 2023-12-22 12:59:13 +01:00
812b414d96 Batched more update calls to avoid Sql paramater count error (#15487)
Co-authored-by: Sven Geusens <sge@umbraco.dk>
2023-12-21 09:43:37 +01:00
Bjarke Berg ec91c47158 Merge remote-tracking branch 'origin/release/10.8' into v10/dev
# Conflicts:
#	version.json
2023-12-20 09:51:14 +01:00
Kenn JacobsenandGitHub e04a41be45 Add policies for content template handling (#15482) 2023-12-19 14:18:48 +01:00
Chris Fitz-AvonandBjarke Berg d5156aced2 Remove content section access policy from GetAllLanguages endpoint. #15435 (#15450)
(cherry picked from commit cedfdcc9b2)
2023-12-18 08:25:00 +01:00
Bjarke Berg fa9b0e4718 Bump version 2023-12-18 08:23:34 +01:00
Bjarke Berg 8915064780 Merge remote-tracking branch 'origin/release/10.8' into v10/dev
# Conflicts:
#	version.json
2023-12-13 09:28:19 +01:00
ZeegaanandBjarke Berg 677ff59d04 Loosen up policies so editors can get what they need 2023-12-12 15:46:46 +01:00
Bjarke Berg 1fe2ec08be bump version 2023-12-12 15:35:15 +01:00
Bjarke Berg 5dfa76600a Post fix 2023-12-11 16:32:38 +01:00
Bjarke Berg 83bcd37250 Merge remote-tracking branch 'origin/release/10.8' into v10/dev 2023-12-11 14:37:10 +01:00
Kenn JacobsenandGitHub 4a7ad4a562 Merge pull request from GHSA-v98m-398x-269r 2023-12-11 14:00:23 +01:00
cdd4d2a000 Merge pull request from GHSA-cfr5-7p54-4qg8
* Bump version

* Apply authorization policies to controllers

* Return bad request if we urltracking is disabled

* Apply authorization policies to controllers

* Return bad request if we urltracking is disabled

---------

Co-authored-by: Bjarke Berg <mail@bergmania.dk>
Co-authored-by: Zeegaan <nge@umbraco.dk>
2023-12-11 13:59:59 +01:00
be5a740c96 Merge pull request from GHSA-8qp8-9rpw-j46c
* Added Exception handling and replicated error and info message

* Update auth.resource.js

Fixed the message

* Changed Delay introduction to early phase to avoid repeating code.

---------

Co-authored-by: jey <jey@umbraco.dk>
Co-authored-by: Jey <cyaqublu@gmail.com>
2023-12-11 13:59:35 +01:00
13cc320f19 Merge pull request from GHSA-6324-52pr-h4p5
* Bump version

* Fix https://github.com/umbraco/Umbraco-CMS/security/advisories/GHSA-6324-52pr-h4p5

* Fix https://github.com/umbraco/Umbraco-CMS/security/advisories/GHSA-6324-52pr-h4p5

---------

Co-authored-by: Bjarke Berg <mail@bergmania.dk>
Co-authored-by: Zeegaan <nge@umbraco.dk>
2023-12-11 13:59:03 +01:00
ZeegaanandBjarke Berg b5544aa520 Suppress flow when queueing background threads 2023-12-11 12:43:25 +01:00
Bjarke Berg 9e3f8c7d0c Merge remote-tracking branch 'origin/release/10.8' into v10/dev
# Conflicts:
#	version.json
2023-12-08 13:12:33 +01:00
Bjarke Berg cb76554455 Bugfix: Count existing media correct (#15206)
* https://github.com/umbraco/Umbraco-CMS/issues/15205
Count media correct

* Fix content should be document

(cherry picked from commit d2ff2ea46e)
2023-12-07 09:21:25 +01:00
Jacob Overgaard 37e4d80ce8 Update nightly build (#15359)
* cherry-pick templateParameters from v14/dev

* add isNightly parameter

* remove v9

* add parameter check for myget isNightly
2023-12-05 12:45:23 +01:00
Bjarke Berg d5d4edbe92 Bump Version 2023-11-30 21:51:54 +01:00
Bjarke Berg 8d9343b564 Merge branch 'release/10.8' into v10/dev
# Conflicts:
#	version.json
2023-11-27 18:10:40 +01:00
Bjarke Berg 1ee891c8d5 Merge remote-tracking branch 'origin/release/10.8' into release/10.8 2023-11-27 18:09:41 +01:00
Bjarke Berg bf1a5b9b28 Bump version 2023-11-27 18:09:30 +01:00
Bjarke Berg 696b74cdb6 Merge branch 'release/10.8' into v10/dev 2023-11-27 18:08:30 +01:00
Bjarke BergandGitHub bf8af4588e Centralised NuGet packages (#15293)
* Moved to centralized nuget packages

* Handle JsonSchema

* Change PackageReference to PackageVersion

* Opt out of central package management for mangement api (at least for versions less than 14) and the UI project

* ManagePackageVersionsCentrally = false

* Change folder acceptance tests are build, to avoid reading the test Directory.Packages.props

* Change folder acceptance tests are build, to avoid reading the test Directory.Packages.props

* change working directory

* workingDirectory

* Force the template to use local nuget packages

* Force the template to use local nuget packages

* clean up

* added wait on

* added wait on
2023-11-27 15:18:00 +01:00
Kenn JacobsenandBjarke Berg 4781fb1d8b Ensure content types are updated in ContentStore when a data type changes (#15239) 2023-11-17 10:37:23 +01:00
Bjarke Berg d714741bee Fixed build 2023-11-15 09:53:28 +01:00
Bjarke Berg ea33b73daa Added scope.complete in edge cases. (#15207)
(cherry picked from commit 28e8ac11f0)
2023-11-15 09:46:24 +01:00
Bjarke Berg ba64b46824 Merge remote-tracking branch 'origin/release/10.8' into release/10.8 2023-11-15 09:45:30 +01:00
Bjarke Berg 04e59e9a9d Fixed a couple of occurrences where scopes was auto-completed while modified db state (#14947)
* Fixed a couple of occurrences where scopes was auto-complated while actually modified the state of the database.

* Added temp ctor to fix boot issue

(cherry picked from commit 41f8f03c2c)
2023-11-15 09:45:23 +01:00
Jacob OvergaardandGitHub be39b9c19a V10: Update @umbraco-ui/uui, jQuery, ace-editor, nouislider, spectrum-colorpicker2 (#15197)
* V13: Add support for Node.js 20 (#15022)

* update versionSpec to nodejs 20 and avoid specifying minor and patch versions to improve Azure Pipelines stability

* update engines and package lock files

* update helpful displayNames for npm builds

* add retry to counter nodejs.org timeouts

add retryCountOnTaskFailure as suggested on https://developercommunity.visualstudio.com/t/NodeTool0-task-to-install-nodejs-fails/10455454

* update lockfile

* bump nvm support to latest node.js 20.9 LTS

* build(deps): bump @umbraco-ui/uui from 1.3.0 to 1.5.0

* build(deps): bump public dependencies to latest

* build(deps-dev): bump build dependencies to latest

* build(deps-dev): bump test tools to latest

* build: add script to lint and run --fix

* revert login merge from v13
2023-11-14 13:08:29 +01:00
Bjarke Berg 9a143c0850 Merge remote-tracking branch 'origin/release/10.8' into release/10.8 2023-11-14 11:46:26 +01:00
Bjarke Berg df4cd63962 https://github.com/umbraco/Umbraco-CMS/issues/15195 Fixed issue with media not cached correct (#15196) 2023-11-14 10:59:30 +01:00
Bjarke Berg a17e398f28 Merge remote-tracking branch 'origin/release/10.8' into v10/dev 2023-11-14 09:29:36 +01:00
Bjarke Berg 9af9dd2c02 Merge remote-tracking branch 'origin/release/10.8' into v10/dev 2023-11-14 09:29:09 +01:00
Bjarke BergandGitHub 2266a98fc6 https://github.com/umbraco/Umbraco-CMS/issues/15195 Fixed issue with media not cached correct (#15196) 2023-11-14 09:14:01 +01:00
151fccee97 Performance optimisations related to blocks (and multi url picker) (#15184)
* Added content types to property index value factory, because the deep cloning is too expensive to execute often

* Do not use entityservice in ToEditor, as it goes to the database. We need to use something that is cached.

* Small performance optimization for nested content too

* A little formatting and an obsoletion message

---------

Co-authored-by: kjac <kja@umbraco.dk>
2023-11-14 08:12:05 +01:00
Bjarke Berg abfa07367f Bump version 2023-11-13 18:06:41 +01:00
Bjarke BergandGitHub e5de8bf56b Updated nuget packages (#15192) 2023-11-13 14:59:52 +01:00
Bjarke Berg 00bb5170a0 Merge remote-tracking branch 'origin/v10/dev' into release/10.8
# Conflicts:
#	version.json
2023-11-09 13:53:46 +01:00
919138c299 #14835 Update link on permissionsreport.html (#14872)
* #14835 Update link on permissionsreport.html

Updated link to permissions page to point to 10-LTS documentation

* retrigger checks

---------

Co-authored-by: Rasmus Berntsen <rasmus.berntsen@isobar.com>
2023-11-09 13:53:18 +01:00
Ronald BarendseandGitHub ed65645a33 Add global.json and cleanup UI project file (#14900)
* Add global.json with minimum .NET 6.0.5 SDK version and roll forward policy

* Clean up UI project file
2023-11-09 13:52:21 +01:00
Ronald BarendseandGitHub d0be4ab263 Publish ContentTreeChangeNotification after saving/deleting blueprints (#14898) 2023-11-09 13:51:05 +01:00
Bjarke Berg ddb26632f9 Bump to rc 2023-11-09 13:38:34 +01:00
Bjarke Berg d5b1f5875b Bump version 2023-11-09 13:38:13 +01:00
Bjarke Berg f8c1a560ff Bump version 2023-11-09 13:36:57 +01:00
9e5ff305c8 Batched bulk WhereIn query to avoid To mana paramaters error (#15004)
Co-authored-by: Sven Geusens <sge@umbraco.dk>
2023-11-07 10:49:46 +01:00
Elitsa MarinovskaandGitHub ffaa77eb25 Update correct action (#15142) 2023-11-06 17:54:16 +01:00
Kenn JacobsenandGitHub 6777145079 Ensure that missing access rules do not break the site (#15081) 2023-11-02 08:45:27 +01:00
Elitsa MarinovskaandGitHub 92af8ac881 Check content permissions before performing action (#15043)
* Setting actionContext.Result when authz wasn't successful

* Taking into account permissions when it is a new node

* Cleanup

* Passing nodeId as path when new item
2023-11-01 11:30:32 +01:00
Lucas Bach BisgaardandSebastiaan Janssen bde88caf14 Fixes #14351 - Using Fallback to default langauge on a specific item changes the whole VariationContext (#14620)
(cherry picked from commit 738749b705)
2023-10-26 11:47:44 +02:00
Bjarke BergandGitHub f4ac6cdded Added "pr: none" to nightly trigger (#15044) 2023-10-26 09:01:25 +02:00
Elitsa MarinovskaandGitHub 132935c2d7 Handle corrupted index (#14889) 2023-10-09 10:19:36 +02:00
Kenn JacobsenandGitHub 04b05714e5 Add notification state to "final" published notification when publishing with descendants (#14922)
* Revert "V10/bugfix/14543 publish descendants (#14763)"

This reverts commit f750bca453.

* Add notification state to "final" published notification when publishing with descendants
2023-10-05 14:39:00 +02:00
Kenn JacobsenandGitHub 7be1852827 Make sure to sign out external users if an error occurs during sign-in (#14867) 2023-09-28 13:25:11 +02:00
Andreas ZerbstandGitHub 158cef1692 V10 fixed up failing acceptance test (#14829)
* Updated playwright, our builders, and our helpers

* Updated the use of our testhelper methods, we removed the need for sending umbracoApi through the methods as a parameter since it was unnecessary

* Added a timeout

* Updated successNotifications and added a locator

* Removed timeout from successNotification

* Added additional timeouts and updated old locators which were failing

* Updated locator so it only finds one element

* Removed timeouts and added a waitForTimeout

* Removed timeouts

* Removed timeouts

* Added timeouts

* Updated locator

* Added a timeout

* Updated locators for clicking button

* Changed locator for adding the image, sometimes the old locator would find 2 locators
2023-09-20 12:15:24 +02:00
Bjarke Berg 1a4f3981eb Merge remote-tracking branch 'origin/v10/dev' into v10/dev 2023-09-20 09:42:28 +02:00
Bjarke Berg 7765f98ee1 Added random delay in forgot password to lessen the risk the response times can be use to determine whether the mail exist or not. 2023-09-20 09:02:32 +02:00
6b72880c0b fix: ensured that allowed user name characters are supported in backoffice users as well (#14810) (#14825)
Co-authored-by: Arkadiusz Biel <bielu@bielu.com.pl>
2023-09-19 09:01:35 +02:00
Andy ButlandandGitHub d9f3936a43 Updated dependencies to Forms and Deploy for JSON schema generation. (#14826) 2023-09-19 08:54:41 +02:00
bf09c87f87 Mention MultiUrlPickerValueConverter instead (#14818)
Co-authored-by: Zeegaan <nge@umbraco.dk>
2023-09-18 13:48:11 +02:00
Sven GeusensandGitHub ec2134dea0 Disabled nighly build branch trigger (#14807) 2023-09-15 10:02:29 +02:00
Nikolaj GeisleandGitHub 8ccc2faee0 Add UsePagedSqlQuery setting to NucacheSettings (#14806)
* imlement UsePagedSqlQuery

* Remove unneccesary spacing
2023-09-14 20:11:08 +02:00
Jacob Overgaard 0a4cc27a5d V12: Property editors should only contain layout when in preview mode (#14796)
* Revert "Make sure the property editor layout is contained within its container (prevent Z-index bleed-through) (#13583)"

This reverts commit 8463d906a7.

* remove seemingly unused attribute readonly

* contain everything with contain:layout

this is set if the property editor is in preview mode to make sure all overlays work

* Revert "remove seemingly unused attribute readonly"

This reverts commit 7a2743e8f6.
2023-09-14 13:19:36 +02:00
c8e054baa2 V10/feature/pipeline test filters (#14766)
* Add configuration/code to not run certain tests based on variables/release builds

* Applied longrunning testAttribute to the worst offenders (>200ms on my machine)

* Fix yaml notation

* split up windows/non windows test runs

* Added supression for moved tests

* Fix yaml validation issues

* Change yaml string parameter null value to empty string

* Convert empty strings to whitespace strings

* Rename and cleanup some paramater to better reflect why we use them

* Nightly build test

* Change nightly build authentication type

* template paramater fix

* Update nightly pipeline name

---------

Co-authored-by: Sven Geusens <sge@umbraco.dk>
2023-09-12 14:16:27 +02:00
Bjarke Berg 95ffdae475 Merge remote-tracking branch 'origin/v10/dev' into v10/dev 2023-09-12 09:43:52 +02:00
Andreas ZerbstandJacob Overgaard ca8ac21f4b Added test for checking if settings model contains default value (#14513)
* Added test for checking if a settings model contains default value.
Fixed tests

* Bumped version

* Moved createSliderWithDefaultValue function to our testHelpers. Removed the use of count in test since there was only one
2023-09-11 15:13:08 +02:00
Jacob Overgaard f85a0d1715 Render all tabs in the background to ensure they register their initial state on any $scope.model in the stack. (#14493)
Sometimes a tab, e.g. a "block list settings model" might register some default values, but if the user never clicks on the tab then they are not registered due to how AngularJS renders views with "ng-if".
2023-09-11 15:12:48 +02:00
Andreas ZerbstandGitHub 2fc29e638c Limbo models builder changes the content to element when using Compositions (#14776) 2023-09-07 17:18:57 +02:00
Andreas ZerbstandGitHub 56486b1ace V10 Cherrypicked issuu RTE embed (#14777)
* Added a UserAgent to header

* Added the use of iframe. This allows us to see the issuu embed in the RTE
2023-09-07 16:28:11 +02:00
Bjarke Berg fd043f6ecf Merge remote-tracking branch 'origin/v10/dev' into release/10.7 2023-09-05 10:19:13 +02:00
Bjarke Berg 39a102ed8a rollback version 2023-09-05 10:14:21 +02:00
f750bca453 V10/bugfix/14543 publish descendants (#14763)
* WIP: Fix publish descendants and related notifications

* Removed related entitities from publish notification

* Fixed root not being saved when publishingWithDescendants

* Updated integrationtests to reflect the update view on when to save the root when its part of a branch

* PR formatting fix

Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>

* PR Cleanup

Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>

* Spicing up the codebase with some PR pattern matching

Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>

---------

Co-authored-by: Sven Geusens <sge@umbraco.dk>
Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>
2023-09-05 10:14:06 +02:00
Bjarke Berg 7e36203f60 Merge remote-tracking branch 'origin/release/10.7' into v10/dev
# Conflicts:
#	version.json
2023-09-04 10:24:22 +02:00
Bjarke Berg 334dff8645 bump version number 2023-09-04 10:23:44 +02:00
Bjarke Berg 9fd140f81d Merge remote-tracking branch 'origin/release/10.7' into v10/dev 2023-08-28 11:35:41 +02:00
Bjarke BergandGitHub 1198c76d67 Remove parsing of short into integer (#14721) 2023-08-25 13:07:42 +02:00
Nikolaj 869b480dae Bump version 2023-08-24 10:49:50 +02:00
Nikolaj 12704b112e Merge branch 'release/10.7' into v10/dev 2023-08-24 10:49:11 +02:00
Ronald BarendseandNikolaj 3c37653012 Fix exceptions in Slider and Tags property value converters (#13782)
* Fix IndexOutOfRangeException when converting single value to range in SliderValueConverter

* Fix NullReferenceException while deserializing empty value in TagsValueConverter

* Use invariant decimal parsing

* Handle converting from slider to single value

* Fix parsing range as single value

* Make Handle methods autonomous

---------

Co-authored-by: nikolajlauridsen <nikolajlauridsen@protonmail.ch>
2023-08-23 10:50:25 +02:00
e5a8d01004 Fix exceptions in Slider and Tags property value converters (#13782)
* Fix IndexOutOfRangeException when converting single value to range in SliderValueConverter

* Fix NullReferenceException while deserializing empty value in TagsValueConverter

* Use invariant decimal parsing

* Handle converting from slider to single value

* Fix parsing range as single value

* Make Handle methods autonomous

---------

Co-authored-by: nikolajlauridsen <nikolajlauridsen@protonmail.ch>
2023-08-23 10:09:43 +02:00
Andy ButlandandBjarke Berg 9fd0b1986c Updated JSON schema reference for Umbraco Forms. (#14701) 2023-08-22 13:30:26 +02:00
Andy ButlandandGitHub 80ea5174c6 Updated JSON schema reference for Umbraco Forms. (#14701) 2023-08-22 13:28:01 +02:00
Niels Lyngsøandkjac e1b4aebb0f directly render labels without angularJS template code (#14700) 2023-08-22 11:35:38 +02:00
Niels LyngsøandGitHub 38910a8d5c directly render labels without angularJS template code (#14700) 2023-08-22 11:27:16 +02:00
Kenn JacobsenandGitHub 0dc18982ee Do not allow content type property aliases that conflict with IPublishedElement (#14683) 2023-08-21 13:17:15 +02:00
311d322129 Add code infrastructure to validate file content (#14657)
* Implemented modular architecture for filestream security sanitization with an svg-html example

* 31440: Refactoring, applied to more entry points and removed test analyzer

* 31440 Added Unittests for FileStreamSecurityValidator

* PR fixes and better unittest mock names

---------

Co-authored-by: Sven Geusens <sge@umbraco.dk>
2023-08-21 13:08:26 +02:00
Andreas ZerbstandGitHub e7af98027d Updated the name of our Acceptance test project in the pipeline (#14691)
* Updated the name of our Acceptance test project.

The reason is because we want the naming to be clear and concise.

* Changed the name of the e2e pipeline project name for linux

* Updated dll file
2023-08-18 13:36:54 +03:00
Anders ReusandBjarke Berg 30f0cfc15d Add exclusion filter setting to typefinder settings (#14426)
* Obsolete constructor with deprecated IScopeProvider

* Add exclusion setting to typefinder settings

* The old TypeFinder constructor calls the new constructor now instead and excluded duplicates by using Union instead of Concat.

* Revert "The old TypeFinder constructor calls the new constructor now instead and excluded duplicates by using Union instead of Concat."

This reverts commit 87801c6c1c.

* Add changes to TypeFinder

* Do not use null when type is not nullable

---------

Co-authored-by: Bjarke Berg <mail@bergmania.dk>
2023-08-15 09:58:58 +02:00
Ronald BarendseandBjarke Berg b743e715d4 Add DynamicRequestCultureProviderBase and improve locking (#14064) 2023-08-10 11:16:23 +02:00
d3243f8700 Bugfix 31584 - Remove Lazy "caching" that retains keys of deleted ContentTypes which causes unecesary validation errors (#14643)
The validation errors should not happen as the model mapping cleans up block data for entity types that do not longer exist (which is checked on the aformentioned key)

Co-authored-by: Sven Geusens <sge@umbraco.dk>
2023-08-09 13:11:44 +02:00
264e4f8b57 Add config so it is configurable whether to explicitly index each nested property (#14648)
* Added new configuration "Umbraco:CMS:Examine:ExplicitlyIndexEachNestedProperty" that can be used to avoid nested properties like block grid to index each property individually.

* Moved the setting "Umbraco:CMS:Examine:ExplicitlyIndexEachNestedProperty" to "Umbraco:CMS:Indexing:ExplicitlyIndexEachNestedProperty" to make it more future proof

* Added missing registration

* Fixed registration

* Small readability improvement

---------

Co-authored-by: Sven Geusens <sge@umbraco.dk>
2023-08-09 11:47:45 +02:00
Sven Geusens 2b3f048db7 Revert "Implemented modular architecture for filestream security sanitization with an svg-html example"
This reverts commit 18ee016ae9.
2023-08-08 16:26:59 +02:00
Sven Geusens 18ee016ae9 Implemented modular architecture for filestream security sanitization with an svg-html example 2023-08-08 14:49:18 +02:00
Bjarke BergandGitHub 512199c8ab Pass the existing notification state to the ContentUnpublishingNotification so it can be shared. (#14638) 2023-08-08 09:40:44 +02:00
Bjarke BergandGitHub 4e410a9dd5 Stop event propagation when clicking on the expand-arrow in the tree. (#14637) 2023-08-08 09:27:23 +02:00
Jacob OvergaardandNiels Lyngsø e16e36c68f V12: Remove avatar step from login (#14629)
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
2023-08-07 11:02:53 +02:00
Bjarke Berg f384e0c30c Allow newlines in invite email and escape other html (#14618) 2023-08-02 14:17:39 +02:00
Bjarke Berg 04b74dddd0 Added missing async awaits in notifications that ensures objects are not disposed too early
Fixes https://github.com/umbraco/Umbraco-CMS/issues/14574
2023-08-02 11:37:39 +02:00
Kenn JacobsenandGitHub 43700d2bcb Ensure that the Slider does not crash the back-office (#14601)
* Ensure that the Slider does not crash the back-office

* Add field descriptions to config
2023-07-25 08:39:59 +02:00
Adrian CojocariuandGitHub eed9feb5f3 Fix method invoke. (#14597) 2023-07-24 15:18:23 +02:00
b2a5ce3e48 V10: Dropzone should handle internal and external errors when uploading (#14578)
* fix: mark files that result in error as processed

* fix: for safety measure check that a file is truthy before trying to upload it

* fix: push an error when file.$error is encountered to make sure it does not get uploaded

* fix: remove header from error messages since it is not being used anyway

* fix: check for maxFileSize before uploading pasted images in tinymce

* use stored blob variable

* feat: add property to fileManager to get and format the maxFileSize

* fix: make tinymce use fileManager to get maxFileSize

* fix(image cropper): check for maxFileSize before setting file to upload

* multiply by 1000 to get bytes

---------

Co-authored-by: Elitsa <elm@umbraco.dk>
2023-07-24 10:17:21 +02:00
Andy ButlandandGitHub 0ae404ce03 Extends JSON schema/Intellisense to full details of InstallDefaultData settings. (#14568)
* Fixes an incorrect property name used for generating JSON schema.

* Added JSON schema/intellisense for default data dictionary keys.

* Renamed private variable to match setting name.
2023-07-20 13:51:05 +02:00
ab836d2326 V10: Find and persist embedded images in rich text (#14546)
* add method to find and persist embedded base64 (data-uri) images in a html string

* use method to find embedded images in the Umbraco.TinyMce and Umbraco.Grid property editors

* rename method to better reflect what it does

* set allowed upload file types for integration tests

* add test for embedded images in Umbraco.TinyMce

* let old ctor call new ctor

* Apply suggestions from code review

Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>

* apply pattern matching

---------

Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>
2023-07-18 09:17:19 +02:00
Andy ButlandandGitHub c12cce6d8c Fixes an incorrect property name used for generating JSON schema. (#14542) 2023-07-14 09:27:02 +02:00
nikolajlauridsen 78e1da3231 Merge branch 'release/10.6' into v10/dev 2023-07-13 10:55:36 +02:00
82eae48d09 Merge pull request from GHSA-h8wc-r4jh-mg7m
* Don't login after install

* Fail the install if database is not created

---------

Co-authored-by: Zeegaan <nge@umbraco.dk>
Co-authored-by: Nikolaj <nikolajlauridsen@protonmail.ch>
2023-07-13 06:03:39 +02:00
Elitsa MarinovskaandGitHub a5ba32bfd7 Store tags as text (instead of nvarchar) (#14510)
* Migrate tags from NVarchar To NText

* Cleanup
2023-07-07 14:23:32 +02:00
Bjarke Berg c695f2192f Merge remote-tracking branch 'origin/release/10.6' into v10/dev
# Conflicts:
#	version.json
2023-07-07 08:27:51 +02:00
Zeegaan dc5c7a14a5 Bump version 2023-07-06 10:40:50 +02:00
Zeegaan c751e90928 Merge branch 'release/10.6' into v10/dev
# Conflicts:
#	version.json
2023-07-06 09:20:47 +02:00
Zeegaan d86e4b2d38 Bumb version 2023-07-05 10:46:14 +02:00
MaartenandSebastiaan Janssen 3f196a9de4 Fix broken CookieAuthenticationRedirect caused by PR #14036 for non-api requests (#14399)
* Fix broken CookieAuthenticationRedirect caused by PR #14036 when not in an API controller

* Added Integration Tests for the MemberAuthorizationFilter

* Fix merge conflict

---------

Co-authored-by: Elitsa <elm@umbraco.dk>
(cherry picked from commit 1d239a30ca)
2023-07-04 11:10:58 +02:00
Nikolaj Brask-NielsenandSebastiaan Janssen 30ec9d9bc7 fix: Allows copying from unsaved content (#14464)
#14459

(cherry picked from commit 1d14158d82)
2023-07-04 11:08:39 +02:00
Anders BjernerandSebastiaan Janssen 3087fc3ba9 Added missing Danish translation for general_change (#14461)
* Added missing Danish translation for `general_change`

* Update en_us.xml

(cherry picked from commit a090997aa1)
2023-07-04 11:07:21 +02:00
christophnzandSebastiaan Janssen 7fd7a8715d Fixed typo "optinal" to "optional" for translation dictionary import dialog and 2 other occurrences
(cherry picked from commit 77a2e4b557)
2023-07-04 10:42:56 +02:00
Bjarne FyrstenborgandSebastiaan Janssen 62fd860a9e Show SVG icons for toolbar in configuration of richtext editor (#14404)
* Load default icons to show them next to checkboxes in configuration of richtext editor

* More mapping of icons

* Fix vertical align items centered not reflected

* Wrap mapping in function

* Map a few more icons

* Cleanup and formatting

* Cleanup

* Cleanup

* Add period in description

(cherry picked from commit 583965cf9d)
2023-07-04 10:41:40 +02:00
Mads Mørch SchouandSebastiaan Janssen 76ad99beb0 Makes sure the nucache is not truncated when its null (#14395)
* Makes sure the nucache is not truncated when its null
* Removed parentheses

(cherry picked from commit 0a4a938b88)
2023-07-04 10:36:57 +02:00
Jason ElkinandSebastiaan Janssen ebe375d23b Add ContentDeletingNotification to EmptyRecycleBin (#14397)
* Add ContentDeletingNotification to EmptyRecycleBin

* Fix formatting.

(cherry picked from commit 118f914158)
2023-07-04 10:35:08 +02:00
Marco TeodoroandSebastiaan Janssen 2f35967bb2 fix: #12253 Anchor picker does not appear (#13492)
* fix: #12253 Anchor picker does not appear

* Update ContentServiceExtensions.cs

fix: #12253  #13492 ; implement PR suggestions, test the new changes to confirm that they fix the issue with the anchorlink implementation on RTE from blocklist, blockgrid and normal RTE properties
Co-Authored-By: Laura Neto <12862535+lauraneto@users.noreply.github.com>

* Removed unnecessary using and code

* Small adjustments

---------

Co-authored-by: Laura Neto <12862535+lauraneto@users.noreply.github.com>
(cherry picked from commit 1ba834a9ca)
2023-07-04 10:33:05 +02:00
Paul SealandSebastiaan Janssen f93f3d88da Fix/delete language error message 14333 (#14396)
* Update the tour text to the correct text and to save confusion

* Added extra information to the delete language warning to inform the user that it will also delete all content related to the language

* Updated language files with same message re deletion

---------

Co-authored-by: Paul Seal <p.seal@clerkswell.com>
Co-authored-by: Emma Garland <emma.garland@rocksolidknowledge.com>
(cherry picked from commit 542d0f7f74)
2023-07-04 10:06:26 +02:00
Bjarne FyrstenborgandSebastiaan Janssen dbd009ffcd Update label in Danish translation
(cherry picked from commit 575f00d6f0)
2023-07-04 10:05:17 +02:00
alevak09andSebastiaan Janssen b99e14e288 Add Croatian Language (#14379)
Croatian language translation of Umbraco backoffice and culture settings

(cherry picked from commit 9f4d3e5525)
2023-07-04 10:03:42 +02:00
Paul SealandSebastiaan Janssen b8415ed7f0 Update the tour text to the correct text and to save confusion
(cherry picked from commit 5073a26e7f)
2023-07-04 10:00:09 +02:00
Miguel PintoandSebastiaan Janssen 8f6370a480 Swapped the sortCreateDateAscending and sortCreateDateDescending translation values to match the intended behavior (#14315)
(cherry picked from commit 76cb85224e)
2023-07-04 09:53:46 +02:00
RussellandSebastiaan Janssen aa4a1b3498 Fix for User null from IP address "::1" has logged out (#14322)
(cherry picked from commit dd59ef17f5)
2023-07-04 09:51:59 +02:00
RussellandSebastiaan Janssen b716e98780 Change "Media Picker" in RTE to "Image Picker" (#14321)
(cherry picked from commit 0220621337)

# Conflicts:
#	src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js
2023-07-04 09:49:34 +02:00
Elitsa MarinovskaandGitHub e86fb0eeb6 Adding null check and descriptive error (#14469) 2023-06-27 13:35:01 +02:00
Elitsa MarinovskaandGitHub fe1080dd64 Check the cases where there might be a custom image type, instead of an the default Umbraco image type (#14463) 2023-06-27 10:33:46 +02:00
Bjarke Berg 1133c4e7f2 Merge remote-tracking branch 'origin/release/10.6' into v10/dev 2023-06-27 09:06:17 +02:00
Jacob Overgaard f5b834974d package-lock.json sync 2023-06-26 14:28:59 +02:00
Nikolaj 75113a90fb Bump version 2023-06-22 09:18:57 +02:00
miguelcrpintoandZeegaan 7e573c70a3 Updated the IsoDateTimeConverter initialization in the JsonDateTimeFormatAttribute to set the Culture to InvariantCulture so that the custom DateTime format symbols ( date and time separators) are respected independent of the CurrentCulture being used. 2023-06-21 14:04:56 +02:00
dependabot[bot]andNikolaj 5c5de77965 Bump socket.io-parser from 4.2.1 to 4.2.4 in /src/Umbraco.Web.UI.Client
Bumps [socket.io-parser](https://github.com/socketio/socket.io-parser) from 4.2.1 to 4.2.4.
- [Release notes](https://github.com/socketio/socket.io-parser/releases)
- [Changelog](https://github.com/socketio/socket.io-parser/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io-parser/compare/4.2.1...4.2.4)

---
updated-dependencies:
- dependency-name: socket.io-parser
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-21 09:45:50 +02:00
dependabot[bot]andNikolaj 2f486610bb Bump fast-xml-parser and is-svg in /src/Umbraco.Web.UI.Client
Bumps [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser) and [is-svg](https://github.com/sindresorhus/is-svg). These dependencies needed to be updated together.

Updates `fast-xml-parser` from 3.20.3 to 4.2.4
- [Release notes](https://github.com/NaturalIntelligence/fast-xml-parser/releases)
- [Changelog](https://github.com/NaturalIntelligence/fast-xml-parser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/NaturalIntelligence/fast-xml-parser/commits)

Updates `is-svg` from 4.3.1 to 4.4.0
- [Release notes](https://github.com/sindresorhus/is-svg/releases)
- [Commits](https://github.com/sindresorhus/is-svg/compare/v4.3.1...v4.4.0)

---
updated-dependencies:
- dependency-name: fast-xml-parser
  dependency-type: indirect
- dependency-name: is-svg
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-21 09:45:45 +02:00
Nikolaj d19a30768f Merge remote-tracking branch 'origin/v10/dev' into v10/dev 2023-06-21 09:20:26 +02:00
Nikolaj b451bb802b Revert "Case-insensitive tag names with SQLite provider (#14012)"
This reverts commit bb7752c483.
2023-06-21 08:45:54 +02:00
MoleandGitHub 785390efd7 Add Noop property indexer to multi url picker (#14416) 2023-06-20 12:14:35 +02:00
nikolajlauridsenandBjarke Berg 3b3e1cec40 Add Noop property indexer to multi url picker 2023-06-20 12:12:00 +02:00
Jacob OvergaardandGitHub 89d104e176 v10: Backoffice JS updates (#14406)
* update @umbraco-ui/uui to 1.3.0

* update ace editor to 1.22.1

* update diff to 5.1.0

* update autoprefixer to 10.4.14

* update underscore to 1.13.6

* update jQuery to 3.7.0

* fix pr-first-response workflow
2023-06-20 09:24:07 +02:00
Bjarne FyrstenborgandNikolaj 9a3e655645 Fix transparent background after upgrade of spectrum color picker (#14251) 2023-06-19 08:50:57 +02:00
Andy ButlandandGitHub 5f15b8abb1 Updated Forms and Deploy references in JSON schema project for Umbraco 10. (#14383) 2023-06-16 10:01:09 +02:00
Andreas ZerbstandGitHub 4df3e19af7 Added a mapper for the IPropertyType (#14373) 2023-06-12 11:18:57 +02:00
89d670372d Update security stamps on logout (#14362)
Co-authored-by: Zeegaan <nge@umbraco.dk>
2023-06-12 09:56:04 +02:00
Mole b5ab115318 Remove external login tokens before removing external logins (#14341) 2023-06-06 14:11:20 +02:00
407263d090 V10: Handle blob images (#14317)
* Handle blob images

* remove dots from mapping

* Revert bad formatting

---------

Co-authored-by: Zeegaan <nge@umbraco.dk>
2023-05-31 08:43:14 +02:00
b37bb517ab V10: Implement varying blocklist indexing (#14287)
* Implement available culture in Interface and base classes

* Add available cultures

* DI localizationService and use it

* Make the new method have default implementation to avoid breaking change

* Create implementations for old method

* Pass available cultures

* Pass localization service

* Create new method that takes available cultures

* Add ILocalizationService to DI

* implement missing method

* Add database for schema test

* Fixed issue with indexes not added correctly to nested types..

---------

Co-authored-by: Zeegaan <nge@umbraco.dk>
Co-authored-by: Bjarke Berg <mail@bergmania.dk>
2023-05-25 08:36:42 +02:00
MoleandGitHub 999a83995e V10: Add external login provider count to detailed telemetry (#14282)
* Add backoffice external login provider count to telemetry

* Update translation

* Fix integration test
2023-05-24 11:48:56 +02:00
Kenn Jacobsenandnikolajlauridsen b3a93ac86c Ensure that blocks always open automatically when added to block list or block grid (#14294) 2023-05-24 10:23:40 +02:00
Andy ButlandandGitHub e79246368b Update JSON schema package references for Forms and Deploy. (#14285) 2023-05-23 09:38:01 +02:00
Sebastiaan Janssen b67c7fbe77 Cherry pick b8d6613bd8 accidentally kept both lines instead of just the one, this fixes the problem. 2023-05-22 15:15:19 +02:00
Dhanesh Kumar MjandSebastiaan Janssen 16f448a802 [Fix] Block editor labels showing Angular JS on first load. (#14143)
Co-authored-by: Dhanesh Kumar <“dhanesh.kumar@phases.io”>
(cherry picked from commit 58695b6e9f)
2023-05-19 11:25:15 +02:00
b3bedb4efe XPath can unambiguously use $site/$parent (#14127)
* XPath can unambiguously use $site/$parent

* add deprecation notices and obsolete methods

* Update deprecation description text/instruction

Co-authored-by: Mole <nikolajlauridsen@protonmail.ch>

* Small spelling fix on deprecation description

* keep depr. getByQuery and handle legacy usage

---------

Co-authored-by: Kalle Macklin <karlmacklin@users.noreply.github.co>
Co-authored-by: Mole <nikolajlauridsen@protonmail.ch>
2023-05-15 08:48:36 +02:00
Andreas ZerbstandGitHub 5b73fc19ee V10: Fix NoopPublishedValuefallback varation context member not implemented (#14227)
* Added missing VariationContextAccessor

* Fixed identation
2023-05-10 14:31:40 +02:00
4cdab08910 Fixes #14102 - NestedPropertyIndexValueFactoryBase ignores compositions (#14115) (#14219)
Co-authored-by: Nuklon <Nuklon@users.noreply.github.com>
2023-05-09 09:49:04 +02:00
MoleandGitHub 391cade75f Merge pull request #14205 from umbraco/v10/bugfix/fix_acceptance_test
Fix acceptance test
2023-05-04 10:24:24 +02:00
Anders BrohusandSebastiaan Janssen e27e8d1189 Fixing danish typos (#14184)
* Fixed typo

* Fixed another typo

* Removed space from translation

(cherry picked from commit 7df5c9c212)
2023-05-04 10:13:51 +02:00
MichałandSebastiaan Janssen 1e0ace7a34 Save and preview translation.
(cherry picked from commit 0765a2ebbb)
2023-05-04 10:10:56 +02:00
Nikolaj 21c6828b59 Use regex for class 2023-05-04 09:32:32 +02:00
Nikolaj f7f361239c Try quick fix for test 2023-05-04 09:32:27 +02:00
Nikolaj 05908e2c78 Remove test.only 2023-05-04 09:32:18 +02:00
Jacob Overgaard 3a7ba530a2 Fix: Form elements in thirdparty dashboard views get removed (#14152) 2023-05-03 11:07:33 +02:00
Jacob Overgaard f4073c1dc7 update @umbraco-ui/uui to 1.2.1 2023-05-03 11:07:10 +02:00
Niels LyngsøandJacob Overgaard 7b5233803e fix situation when config was not available. (#14148) 2023-05-03 08:42:19 +02:00
Jacob OvergaardandGitHub 822febb8e8 update @umbraco-ui/uui to 1.2.1 (#14186) 2023-05-03 08:07:04 +02:00
MoleandGitHub bf7b9a20a8 Set culture variation when getting property types for indexing (#14167) 2023-04-26 14:51:55 +02:00
Elitsa MarinovskaandGitHub 9aadb41f4a Change state to publishing before handling ContentSavingNotification (#14114) 2023-04-25 15:08:15 +02:00
347 changed files with 10885 additions and 4262 deletions
+2 -7
View File
@@ -11,15 +11,10 @@ jobs:
issues: write
pull-requests: write
steps:
- name: Install dependencies
run: |
npm install node-fetch@2
- name: Fetch random comment 🗣️ and add it to the PR
uses: actions/github-script@v6
with:
script: |
const fetch = require('node-fetch')
const response = await fetch('https://collaboratorsv2.euwest01.umbraco.io/umbraco/api/comments/PostComment', {
method: 'post',
body: JSON.stringify({
@@ -46,13 +41,13 @@ jobs:
});
} else {
console.log("Returned data not indicate success.");
if(response.status !== 200) {
console.log("Status code:", response.status)
}
console.log("Returned data:", data);
if(data === '') {
console.log("An empty response usually indicates that either no comment was found or the actor user was not eligible for getting an automated response (HQ users are not getting auto-responses).")
}
+1
View File
@@ -49,4 +49,5 @@
<PropertyGroup>
<GitVersionBaseDirectory>$(MSBuildThisFileDirectory)</GitVersionBaseDirectory>
</PropertyGroup>
</Project>
+104 -56
View File
@@ -21,9 +21,33 @@ parameters:
displayName: Upload API docs
type: boolean
default: false
- name: forceReleaseTestFilter
displayName: Force to use the release test filters
type: boolean
default: false
- name: integrationNonReleaseTestFilter
displayName: TestFilter used for non-release type builds
type: string
default: '--filter TestCategory!=LongRunning&TestCategory!=NonCritical'
- name: integrationReleaseTestFilter
displayName: TestFilter used for release type builds
type: string
default: ' '
- name: nonWindowsIntegrationNonReleaseTestFilter
displayName: TestFilter used for non-release type builds on non windows agents
type: string
default: '--filter TestCategory!=LongRunning&TestCategory!=NonCritical'
- name: nonWindowsIntegrationReleaseTestFilter
displayName: TestFilter used for release type builds on non windows agents
type: string
default: ' '
- name: isNightly
displayName: 'Is nightly build (used for MyGet feed)'
type: boolean
default: false
variables:
nodeVersion: 14.18.1
nodeVersion: 20
dotnetVersion: 6.x
dotnetIncludePreviewVersions: false
solution: umbraco.sln
@@ -49,6 +73,7 @@ stages:
steps:
- task: NodeTool@0
displayName: Use Node.js $(nodeVersion)
retryCountOnTaskFailure: 3
inputs:
versionSpec: $(nodeVersion)
- task: Cache@2
@@ -61,9 +86,9 @@ stages:
path: $(npm_config_cache)
- script: npm ci --no-fund --no-audit --prefer-offline
workingDirectory: src/Umbraco.Web.UI.Client
displayName: Run npm ci
displayName: Run npm ci (Backoffice)
- task: gulp@0
displayName: Run gulp build
displayName: Run gulp build (Backoffice)
inputs:
gulpFile: src/Umbraco.Web.UI.Client/gulpfile.js
targets: coreBuild
@@ -80,44 +105,12 @@ stages:
command: restore
projects: $(solution)
- task: DotNetCoreCLI@2
displayName: Run dotnet build
name: build
displayName: Run dotnet build and generate NuGet packages
inputs:
command: build
projects: $(solution)
arguments: '--configuration $(buildConfiguration) --no-restore -p:ContinuousIntegrationBuild=true'
- script: |
version="$(Build.BuildNumber)"
echo "varsion: $version"
major="$(echo $version | cut -d '.' -f 1)"
echo "major version: $major"
echo "##vso[task.setvariable variable=majorVersion;isOutput=true]$major"
displayName: Set major version
name: determineMajorVersion
- task: PowerShell@2
displayName: Prepare nupkg
inputs:
targetType: inline
script: |
$umbracoVersion = "$(Build.BuildNumber)" -replace "\+",".g"
$templatePaths = Get-ChildItem 'templates/**/.template.config/template.json'
foreach ($templatePath in $templatePaths) {
$a = Get-Content $templatePath -Raw | ConvertFrom-Json
if ($a.symbols -and $a.symbols.UmbracoVersion) {
$a.symbols.UmbracoVersion.defaultValue = $umbracoVersion
$a | ConvertTo-Json -Depth 32 | Set-Content $templatePath
}
}
dotnet pack $(solution) --configuration $(buildConfiguration) -p:BuildProjectReferences=false --output $(Build.ArtifactStagingDirectory)/nupkg
- script: |
sha="$(Build.SourceVersion)"
sha=${sha:0:7}
buildnumber="$(Build.BuildNumber)_$(Build.BuildId)_$sha"
echo "##vso[build.updatebuildnumber]$buildnumber"
displayName: Update build number
arguments: '--configuration $(buildConfiguration) --no-restore --property:ContinuousIntegrationBuild=true --property:GeneratePackageOnBuild=true --property:PackageOutputPath=$(Build.ArtifactStagingDirectory)/nupkg'
- task: PublishPipelineArtifact@1
displayName: Publish nupkg
inputs:
@@ -130,11 +123,11 @@ stages:
artifactName: build_output
- stage: Build_Docs
condition: and(succeeded(), or(startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'), ${{parameters.buildApiDocs}}))
condition: and(succeeded(), or(eq(dependencies.Build.outputs['A.build.NBGV_PublicRelease'], 'True'), ${{parameters.buildApiDocs}}))
displayName: Prepare API Documentation
dependsOn: Build
variables:
umbracoMajorVersion: $[ stageDependencies.Build.A.outputs['determineMajorVersion.majorVersion'] ]
umbracoMajorVersion: $[ stageDependencies.Build.A.outputs['build.NBGV_VersionMajor'] ]
jobs:
# C# API Reference
- job:
@@ -188,9 +181,10 @@ stages:
vmImage: 'ubuntu-latest'
steps:
- task: NodeTool@0
displayName: Use Node.js 10.15.0
displayName: Use Node.js 10.15.x
retryCountOnTaskFailure: 3
inputs:
versionSpec: 10.15.0 # Won't work with higher versions
versionSpec: 10.15.x # Won't work with higher versions
- script: |
npm ci --no-fund --no-audit --prefer-offline
npx gulp docs
@@ -259,6 +253,8 @@ stages:
- stage: Integration
displayName: Integration Tests
dependsOn: Build
variables:
releaseTestFilter: eq(dependencies.Build.outputs['A.build.NBGV_PublicRelease'], 'True')
jobs:
# Integration Tests (SQLite)
- job:
@@ -286,12 +282,30 @@ stages:
performMultiLevelLookup: true
includePreviewVersions: $(dotnetIncludePreviewVersions)
- task: DotNetCoreCLI@2
displayName: Run dotnet test
displayName: Run dotnet test Windows
condition: eq(variables['Agent.OS'],'Windows_NT')
inputs:
command: test
projects: '**/*.Tests.Integration.csproj'
arguments: '--configuration $(buildConfiguration) --no-build'
testRunTitle: Integration Tests SQLite - $(Agent.OS)
${{ if or(variables.releaseTestFilter, parameters.forceReleaseTestFilter) }}:
arguments: '--configuration $(buildConfiguration) --no-build ${{parameters.integrationReleaseTestFilter}}'
${{ else }}:
arguments: '--configuration $(buildConfiguration) ${{parameters.integrationNonReleaseTestFilter}}'
env:
Tests__Database__DatabaseType: 'Sqlite'
Umbraco__CMS__Global__MainDomLock: 'FileSystemMainDomLock'
- task: DotNetCoreCLI@2
displayName: Run dotnet test Non Windows
condition: ne(variables['Agent.OS'],'Windows_NT')
inputs:
command: test
projects: '**/*.Tests.Integration.csproj'
testRunTitle: Integration Tests SQLite - $(Agent.OS)
${{ if or(variables.releaseTestFilter, parameters.forceReleaseTestFilter) }}:
arguments: '--configuration $(buildConfiguration) --no-build ${{parameters.nonWindowsIntegrationReleaseTestFilter}}'
${{ else }}:
arguments: '--configuration $(buildConfiguration) ${{parameters.nonWindowsIntegrationNonReleaseTestFilter}}'
env:
Tests__Database__DatabaseType: 'Sqlite'
Umbraco__CMS__Global__MainDomLock: 'FileSystemMainDomLock'
@@ -299,7 +313,7 @@ stages:
# Integration Tests (SQL Server)
- job:
timeoutInMinutes: 120
condition: or(startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'), ${{parameters.sqlServerIntegrationTests}})
condition: or(eq(stageDependencies.Build.A.outputs['build.NBGV_PublicRelease'], 'True'), ${{parameters.sqlServerIntegrationTests}})
displayName: Integration Tests (SQL Server)
strategy:
matrix:
@@ -310,7 +324,7 @@ stages:
Linux:
vmImage: 'ubuntu-latest'
testDb: SqlServer
connectionString: 'Server=localhost,1433;User Id=sa;Password=$(SA_PASSWORD);'
connectionString: 'Server=localhost,1433;User Id=sa;Password=$(SA_PASSWORD);TrustServerCertificate=true'
pool:
vmImage: $(vmImage)
variables:
@@ -321,6 +335,11 @@ stages:
inputs:
artifact: build_output
path: $(Build.SourcesDirectory)
- task: UseDotNet@2
displayName: Use .NET $(dotnetVersion)
inputs:
version: $(dotnetVersion)
includePreviewVersions: $(dotnetIncludePreviewVersions)
- powershell: sqllocaldb start mssqllocaldb
displayName: Start localdb (Windows only)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
@@ -328,12 +347,31 @@ stages:
displayName: Start SQL Server (Linux only)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
- task: DotNetCoreCLI@2
displayName: Run dotnet test
displayName: Run dotnet test Windows
condition: eq(variables['Agent.OS'],'Windows_NT')
inputs:
command: test
projects: '**/*.Tests.Integration.csproj'
arguments: '--configuration $(buildConfiguration) --no-build'
testRunTitle: Integration Tests SQL Server - $(Agent.OS)
${{ if or(variables.releaseTestFilter, parameters.forceReleaseTestFilter) }}:
arguments: '--configuration $(buildConfiguration) --no-build ${{parameters.integrationReleaseTestFilter}}'
${{ else }}:
arguments: '--configuration $(buildConfiguration) --no-build ${{parameters.integrationNonReleaseTestFilter}}'
env:
Tests__Database__DatabaseType: $(testDb)
Tests__Database__SQLServerMasterConnectionString: $(connectionString)
Umbraco__CMS__Global__MainDomLock: 'SqlMainDomLock'
- task: DotNetCoreCLI@2
displayName: Run dotnet test NonWindows
condition: ne(variables['Agent.OS'],'Windows_NT')
inputs:
command: test
projects: '**/*.Tests.Integration.csproj'
testRunTitle: Integration Tests SQL Server - $(Agent.OS)
${{ if or(variables.releaseTestFilter, parameters.forceReleaseTestFilter) }}:
arguments: '--configuration $(buildConfiguration) --no-build ${{parameters.nonWindowsIntegrationReleaseTestFilter}}'
${{ else }}:
arguments: '--configuration $(buildConfiguration) --no-build ${{parameters.nonWindowsIntegrationNonReleaseTestFilter}}'
env:
Tests__Database__DatabaseType: $(testDb)
Tests__Database__SQLServerMasterConnectionString: $(connectionString)
@@ -361,6 +399,7 @@ stages:
dockerImageName: umbraco-linux
Windows:
vmImage: 'windows-latest'
DOTNET_GENERATE_ASPNET_CERTIFICATE: true # Automatically generate HTTPS development certificate on Windows
# Enable console logging in Release mode
Serilog__WriteTo__0__Name: Async
Serilog__WriteTo__0__Args__configure__0__Name: Console
@@ -368,7 +407,7 @@ stages:
Umbraco__CMS__Unattended__InstallUnattended: true
Umbraco__CMS__Global__InstallMissingDatabase: true
UmbracoDatabaseServer: (LocalDB)\MSSQLLocalDB
UmbracoDatabaseName: Playwright
UmbracoDatabaseName: AcceptanceTestDB
ConnectionStrings__umbracoDbDSN: Server=$(UmbracoDatabaseServer);Database=$(UmbracoDatabaseName);Integrated Security=true;
# Custom Umbraco settings
Umbraco__CMS__Global__VersionCheckPeriod: 0
@@ -385,6 +424,7 @@ stages:
path: $(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest/misc/nupkg
- task: NodeTool@0
displayName: Use Node.js $(nodeVersion)
retryCountOnTaskFailure: 3
inputs:
versionSpec: $(nodeVersion)
- task: Cache@2
@@ -429,7 +469,7 @@ stages:
workingDirectory: tests/Umbraco.Tests.AcceptanceTest/misc
- pwsh: |
dotnet new --install ./nupkg/Umbraco.Templates.*.nupkg
dotnet new umbraco --name Playwright --no-restore --output .
dotnet new umbraco --name AcceptanceTestProject --no-restore --output .
dotnet restore --configfile ./nuget.config
dotnet build --configuration $(buildConfiguration) --no-restore
dotnet dev-certs https
@@ -450,6 +490,8 @@ stages:
workingDirectory: tests/Umbraco.Tests.AcceptanceTest
env:
CI: true
CommitId: $(Build.SourceVersion)
AgentOs: $(Agent.OS)
- pwsh: |
docker logs $(dockerImageName) > $(Build.ArtifactStagingDirectory)/playwright.log 2>&1
docker stop $(dockerImageName)
@@ -488,9 +530,11 @@ stages:
- Unit
- Integration
# - E2E # TODO: Enable when stable.
condition: and(succeeded(), or(startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'), ${{parameters.myGetDeploy}}))
condition: and(succeeded(), or(eq(dependencies.Build.outputs['A.build.NBGV_PublicRelease'], 'True'), ${{parameters.myGetDeploy}}))
jobs:
- job:
pool:
vmImage: "windows-latest" # NuGetCommand@2 is no longer supported on Ubuntu 24.04 so we'll use windows until an alternative is available.
displayName: Push to pre-release feed
steps:
- checkout: none
@@ -505,16 +549,20 @@ stages:
command: 'push'
packagesToPush: $(Build.ArtifactStagingDirectory)/**/*.nupkg
nuGetFeedType: 'external'
publishFeedCredentials: 'MyGet - Pre-releases'
${{ if eq(parameters.isNightly, true) }}:
publishFeedCredentials: 'MyGet - Umbraco Nightly'
${{ else }}:
publishFeedCredentials: 'MyGet - Pre-releases'
- stage: Deploy_NuGet
displayName: NuGet release
dependsOn:
- Deploy_MyGet
- Build_Docs
condition: and(succeeded(), or(startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'), ${{parameters.nuGetDeploy}}))
condition: and(succeeded(), or(eq(dependencies.Build.outputs['A.build.NBGV_PublicRelease'], 'True'), ${{parameters.nuGetDeploy}}))
jobs:
- job:
pool:
vmImage: "windows-latest" # NuGetCommand@2 is no longer supported on Ubuntu 24.04 so we'll use windows until an alternative is available.
displayName: Push to NuGet
steps:
- checkout: none
@@ -535,12 +583,12 @@ stages:
pool:
vmImage: 'windows-latest' # Apparently AzureFileCopy is windows only :(
variables:
umbracoMajorVersion: $[ stageDependencies.Build.A.outputs['determineMajorVersion.majorVersion'] ]
umbracoMajorVersion: $[ stageDependencies.Build.A.outputs['build.NBGV_VersionMajor'] ]
displayName: Upload API Documention
dependsOn:
- Build
- Deploy_NuGet
condition: and(succeeded(), or(startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'), ${{parameters.uploadApiDocs}}))
condition: and(succeeded(), or(eq(dependencies.Build.outputs['A.build.NBGV_PublicRelease'], 'True'), ${{parameters.uploadApiDocs}}))
jobs:
- job:
displayName: Upload C# Docs
+35
View File
@@ -0,0 +1,35 @@
name: Nightly_$(TeamProject)_$(Build.DefinitionName)_$(SourceBranchName)_$(Date:yyyyMMdd)$(Rev:.r)
pr: none
trigger: none
schedules:
- cron: '0 0 * * *'
displayName: Daily midnight build
branches:
include:
- v10/dev
- v12/dev
- v13/dev
- v14/dev
steps:
- checkout: none
- task: TriggerBuild@4
inputs:
definitionIsInCurrentTeamProject: true
buildDefinition: '301'
queueBuildForUserThatTriggeredBuild: true
ignoreSslCertificateErrors: false
useSameSourceVersion: false
useCustomSourceVersion: false
useSameBranch: true
waitForQueuedBuildsToFinish: false
storeInEnvironmentVariable: false
templateParameters: 'sqlServerIntegrationTests: true, forceReleaseTestFilter: true, myGetDeploy: true, isNightly: true'
authenticationMethod: 'OAuth Token'
enableBuildInQueueCondition: false
dependentOnSuccessfulBuildCondition: false
dependentOnFailedBuildCondition: false
checkbuildsoncurrentbranch: false
failTaskIfConditionsAreNotFulfilled: false
+6
View File
@@ -0,0 +1,6 @@
{
"sdk": {
"version": "6.0.300",
"rollForward": "latestFeature"
}
}
+67
View File
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<NoWarn>NU1507</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Dazinator.Extensions.FileProviders" Version="2.0.0" />
<PackageVersion Include="Examine" Version="3.0.1" />
<PackageVersion Include="Examine.Core" Version="3.0.1" />
<PackageVersion Include="HtmlAgilityPack" Version="1.11.54" />
<PackageVersion Include="IPNetwork2" Version="2.6.618" />
<PackageVersion Include="K4os.Compression.LZ4" Version="1.3.6" />
<PackageVersion Include="MailKit" Version="3.2.0" />
<PackageVersion Include="Markdown" Version="2.2.1" />
<PackageVersion Include="MessagePack" Version="2.5.187" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.24" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.24" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="6.0.24" />
<PackageVersion Include="Microsoft.CSharp" Version="4.7.0" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Embedded" Version="6.0.24" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Physical" Version="6.0.0" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
<PackageVersion Include="Microsoft.Extensions.Identity.Core" Version="6.0.24" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="6.0.0" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="6.0.0" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="6.0.0" />
<PackageVersion Include="Microsoft.Extensions.Options.DataAnnotations" Version="6.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="6.0.1" />
<PackageVersion Include="Microsoft.Extensions.Http" Version="6.0.0" />
<PackageVersion Include="Microsoft.Extensions.Identity.Stores" Version="6.0.24" />
<PackageVersion Include="MiniProfiler.AspNetCore.Mvc" Version="4.2.22" />
<PackageVersion Include="MiniProfiler.Shared" Version="4.2.22" />
<PackageVersion Include="ncrontab" Version="3.3.3" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="NPoco.SqlServer" Version="5.3.2" />
<PackageVersion Include="Serilog" Version="2.12.0" />
<PackageVersion Include="Serilog.AspNetCore" Version="5.0.0" />
<PackageVersion Include="Serilog.Enrichers.Process" Version="2.0.2" />
<PackageVersion Include="Serilog.Enrichers.Thread" Version="3.1.0" />
<PackageVersion Include="Serilog.Expressions" Version="3.4.1" />
<PackageVersion Include="Serilog.Extensions.Hosting" Version="4.2.0" />
<PackageVersion Include="Serilog.Formatting.Compact" Version="1.1.0" />
<PackageVersion Include="Serilog.Formatting.Compact.Reader" Version="1.0.5" />
<PackageVersion Include="Serilog.Settings.Configuration" Version="3.4.0" />
<PackageVersion Include="Serilog.Sinks.Async" Version="1.5.0" />
<PackageVersion Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageVersion Include="Serilog.Sinks.Map" Version="1.0.2" />
<PackageVersion Include="SixLabors.ImageSharp" Version="2.1.10" />
<PackageVersion Include="SixLabors.ImageSharp.Web" Version="2.0.2" />
<PackageVersion Include="Smidge.InMemory" Version="4.3.0" />
<PackageVersion Include="Smidge.Nuglify" Version="4.2.1" />
<PackageVersion Include="System.IO.FileSystem.AccessControl" Version="5.0.0" />
<PackageVersion Include="System.Security.Cryptography.Pkcs" Version="6.0.4" />
<PackageVersion Include="System.Threading.Tasks.Dataflow" Version="6.0.0" />
<PackageVersion Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageVersion Include="System.Reflection.Emit.Lightweight" Version="4.7.0" />
<PackageVersion Include="System.Runtime.Caching" Version="6.0.0" />
<PackageVersion Include="Umbraco.CSharpTest.Net.Collections" Version="14.906.1403.1085" />
<!-- Add dependencies that we force an update to, even that we do not use them explicitly and they seems to be taken from the framework instead of from Nuget -->
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
<PackageVersion Include="System.Security.Cryptography.Xml" Version="6.0.1" />
<PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />
</ItemGroup>
</Project>
+16 -1
View File
@@ -51,6 +51,7 @@ namespace JsonSchema
public ImagingSettings? Imaging { get; set; }
public IndexCreatorSettings? Examine { get; set; }
public IndexingSettings? Indexing { get; set; }
public KeepAliveSettings? KeepAlive { get; set; }
@@ -88,13 +89,27 @@ namespace JsonSchema
public HelpPageSettings? HelpPage { get; set; }
public InstallDefaultDataSettings? DefaultDataCreation { get; set; }
public InstallDefaultData? InstallDefaultData { get; set; }
public DataTypesSettings? DataTypes { get; set; }
public MarketplaceSettings? Marketplace { get; set; }
}
/// <summary>
/// Configurations for the Umbraco CMS InstallDefaultData configuration.
/// </summary>
public class InstallDefaultData
{
public InstallDefaultDataSettings? Languages { get; set; }
public InstallDefaultDataSettings? DataTypes { get; set; }
public InstallDefaultDataSettings? MediaTypes { get; set; }
public InstallDefaultDataSettings? MemberTypes { get; set; }
}
/// <summary>
/// Configurations for the Umbraco Forms package to Umbraco CMS
/// </summary>
+4 -3
View File
@@ -3,16 +3,17 @@
<OutputType>Exe</OutputType>
<IsPackable>false</IsPackable>
<EnablePackageValidation>false</EnablePackageValidation>
<ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<PackageReference Include="NJsonSchema" Version="10.7.2" />
<PackageReference Include="NJsonSchema" Version="10.9.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Umbraco.Core\Umbraco.Core.csproj" />
<PackageReference Include="Umbraco.Deploy.Core" Version="10.1.3" />
<PackageReference Include="Umbraco.Forms.Core" Version="10.3.0" />
<PackageReference Include="Umbraco.Deploy.Core" Version="10.4.0" />
<PackageReference Include="Umbraco.Forms.Core" Version="10.5.4" />
</ItemGroup>
</Project>
@@ -4,6 +4,7 @@
<Description>Contains the presentation layer for the Umbraco CMS Management API.</Description>
<IsPackable>false</IsPackable>
<EnablePackageValidation>false</EnablePackageValidation>
<ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
@@ -12,7 +13,7 @@
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer" Version="5.0.0" />
<PackageReference Include="NSwag.AspNetCore" Version="13.16.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Umbraco.Infrastructure\Umbraco.Infrastructure.csproj" />
<ProjectReference Include="..\Umbraco.New.Cms.Core\Umbraco.New.Cms.Core.csproj" />
@@ -20,7 +21,7 @@
<ProjectReference Include="..\Umbraco.New.Cms.Web.Common\Umbraco.New.Cms.Web.Common.csproj" />
<ProjectReference Include="..\Umbraco.Web.Common\Umbraco.Web.Common.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="OpenApi.json" />
</ItemGroup>
@@ -134,9 +134,10 @@ public class SqlServerDistributedLockingMechanism : IDistributedLockingMechanism
const string query = "SELECT value FROM umbracoLock WITH (REPEATABLEREAD) WHERE id=@id";
db.Execute("SET LOCK_TIMEOUT " + _timeout.TotalMilliseconds + ";");
var lockTimeoutQuery = $"SET LOCK_TIMEOUT {_timeout.TotalMilliseconds}";
var i = db.ExecuteScalar<int?>(query, new { id = LockId });
// execute the lock timeout query and the actual query in a single server roundtrip
var i = db.ExecuteScalar<int?>($"{lockTimeoutQuery};{query}", new { id = LockId });
if (i == null)
{
@@ -169,9 +170,10 @@ public class SqlServerDistributedLockingMechanism : IDistributedLockingMechanism
const string query =
@"UPDATE umbracoLock WITH (REPEATABLEREAD) SET value = (CASE WHEN (value=1) THEN -1 ELSE 1 END) WHERE id=@id";
db.Execute("SET LOCK_TIMEOUT " + _timeout.TotalMilliseconds + ";");
var lockTimeoutQuery = $"SET LOCK_TIMEOUT {_timeout.TotalMilliseconds}";
var i = db.Execute(query, new { id = LockId });
// execute the lock timeout query and the actual query in a single server roundtrip
var i = db.Execute($"{lockTimeoutQuery};{query}", new { id = LockId });
if (i == 0)
{
@@ -154,7 +154,7 @@ public class SqliteDistributedLockingMechanism : IDistributedLockingMechanism
try
{
var i = command.ExecuteNonQuery();
var i = db.ExecuteNonQuery(command);
if (i == 0)
{
@@ -5,7 +5,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Data.Sqlite" Version="6.0.5" />
<PackageReference Include="Microsoft.Data.Sqlite" />
</ItemGroup>
<ItemGroup>
+1
View File
@@ -4,6 +4,7 @@
<Description>Installs Umbraco CMS with all default dependencies in your ASP.NET Core project.</Description>
<IncludeBuildOutput>false</IncludeBuildOutput>
<IncludeSymbols>false</IncludeSymbols>
<ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
@@ -84,8 +84,8 @@ public sealed class ContentCacheRefresher : PayloadCacheRefresherBase<ContentCac
isolatedCache.ClearOfType<IContent>((k, v) => v.Path?.Contains(pathid) ?? false);
}
// if the item is being completely removed, we need to refresh the domains cache if any domain was assigned to the content
if (payload.ChangeTypes.HasTypesAny(TreeChangeTypes.Remove))
// if the item is not a blueprint and is being completely removed, we need to refresh the domains cache if any domain was assigned to the content
if (payload.Blueprint is false && payload.ChangeTypes.HasTypesAny(TreeChangeTypes.Remove))
{
idsRemoved.Add(payload.Id);
}
@@ -120,7 +120,11 @@ public sealed class ContentCacheRefresher : PayloadCacheRefresherBase<ContentCac
// should rename it, and then, this is only for Deploy, and then, ???
// if (Suspendable.PageCacheRefresher.CanUpdateDocumentCache)
// ...
NotifyPublishedSnapshotService(_publishedSnapshotService, AppCaches, payloads);
if (payloads.Any(x => x.Blueprint is false))
{
// Only notify if the payload contains actual (non-blueprint) contents
NotifyPublishedSnapshotService(_publishedSnapshotService, AppCaches, payloads);
}
base.Refresh(payloads);
}
@@ -157,8 +161,13 @@ public sealed class ContentCacheRefresher : PayloadCacheRefresherBase<ContentCac
}
}
// TODO (V14): Change into a record
public class JsonPayload
{
public JsonPayload()
{ }
[Obsolete("Use the default constructor and property initializers.")]
public JsonPayload(int id, Guid? key, TreeChangeTypes changeTypes)
{
Id = id;
@@ -166,11 +175,13 @@ public sealed class ContentCacheRefresher : PayloadCacheRefresherBase<ContentCac
ChangeTypes = changeTypes;
}
public int Id { get; }
public int Id { get; init; }
public Guid? Key { get; }
public Guid? Key { get; init; }
public TreeChangeTypes ChangeTypes { get; }
public TreeChangeTypes ChangeTypes { get; init; }
public bool Blueprint { get; init; }
}
#endregion
@@ -88,10 +88,6 @@ public sealed class DataTypeCacheRefresher : PayloadCacheRefresherBase<DataTypeC
}
}
// TODO: not sure I like these?
TagsValueConverter.ClearCaches();
SliderValueConverter.ClearCaches();
// refresh the models and cache
_publishedModelFactory.WithSafeLiveFactoryReset(() =>
_publishedSnapshotService.Notify(payloads));
@@ -134,8 +134,14 @@ public sealed class LanguageCacheRefresher : PayloadCacheRefresherBase<LanguageC
ContentCacheRefresher.RefreshContentTypes(AppCaches); // we need to evict all IContent items
// now refresh all nucache
ContentCacheRefresher.JsonPayload[] clearContentPayload =
new[] { new ContentCacheRefresher.JsonPayload(0, null, TreeChangeTypes.RefreshAll) };
ContentCacheRefresher.JsonPayload[] clearContentPayload = new[]
{
new ContentCacheRefresher.JsonPayload()
{
ChangeTypes = TreeChangeTypes.RefreshAll
}
};
ContentCacheRefresher.NotifyPublishedSnapshotService(_publishedSnapshotService, AppCaches, clearContentPayload);
}
+31 -8
View File
@@ -9,6 +9,9 @@ namespace Umbraco.Cms.Core.Cache;
/// </summary>
public class ObjectCacheAppCache : IAppPolicyCache, IDisposable
{
private static readonly TimeSpan _readLockTimeout = TimeSpan.FromSeconds(5);
private static readonly TimeSpan _writeLockTimeout = TimeSpan.FromSeconds(5);
private readonly ReaderWriterLockSlim _locker = new(LockRecursionPolicy.SupportsRecursion);
private bool _disposedValue;
@@ -33,7 +36,10 @@ public class ObjectCacheAppCache : IAppPolicyCache, IDisposable
Lazy<object?>? result;
try
{
_locker.EnterReadLock();
if (_locker.TryEnterReadLock(_readLockTimeout) is false)
{
throw new TimeoutException("Timeout exceeded to the memory cache when getting item");
}
result = MemoryCache.Get(key) as Lazy<object?>; // null if key not found
}
finally
@@ -195,7 +201,10 @@ public class ObjectCacheAppCache : IAppPolicyCache, IDisposable
{
try
{
_locker.EnterWriteLock();
if (_locker.TryEnterWriteLock(_writeLockTimeout) is false)
{
throw new TimeoutException("Timeout exceeded to the memory cache when clearing item");
}
if (MemoryCache[key] == null)
{
return;
@@ -223,8 +232,10 @@ public class ObjectCacheAppCache : IAppPolicyCache, IDisposable
var isInterface = type.IsInterface;
try
{
_locker.EnterWriteLock();
if (_locker.TryEnterWriteLock(_writeLockTimeout) is false)
{
throw new TimeoutException("Timeout exceeded to the memory cache when clearing by type");
}
// ToArray required to remove
foreach (var key in MemoryCache
.Where(x =>
@@ -259,7 +270,10 @@ public class ObjectCacheAppCache : IAppPolicyCache, IDisposable
{
try
{
_locker.EnterWriteLock();
if (_locker.TryEnterWriteLock(_writeLockTimeout) is false)
{
throw new TimeoutException("Timeout exceeded to the memory cache when clearing by generic type");
}
Type typeOfT = typeof(T);
var isInterface = typeOfT.IsInterface;
@@ -296,7 +310,10 @@ public class ObjectCacheAppCache : IAppPolicyCache, IDisposable
{
try
{
_locker.EnterWriteLock();
if (_locker.TryEnterWriteLock(_writeLockTimeout) is false)
{
throw new TimeoutException("Timeout exceeded to the memory cache when clearing generic type with predicate");
}
Type typeOfT = typeof(T);
var isInterface = typeOfT.IsInterface;
@@ -338,7 +355,10 @@ public class ObjectCacheAppCache : IAppPolicyCache, IDisposable
{
try
{
_locker.EnterWriteLock();
if (_locker.TryEnterWriteLock(_writeLockTimeout) is false)
{
throw new TimeoutException("Timeout exceeded to the memory cache when clearing with prefix");
}
// ToArray required to remove
foreach (var key in MemoryCache
@@ -365,7 +385,10 @@ public class ObjectCacheAppCache : IAppPolicyCache, IDisposable
try
{
_locker.EnterWriteLock();
if (_locker.TryEnterWriteLock(_writeLockTimeout) is false)
{
throw new TimeoutException("Timeout exceeded to the memory cach when clearing by regex");
}
// ToArray required to remove
foreach (var key in MemoryCache
@@ -3,30 +3,26 @@ using System.Collections;
namespace Umbraco.Cms.Core.Composing;
/// <summary>
/// Provides a base class for builder collections.
/// Provides a base class for builder collections.
/// </summary>
/// <typeparam name="TItem">The type of the items.</typeparam>
public abstract class BuilderCollectionBase<TItem> : IBuilderCollection<TItem>
{
private readonly LazyReadOnlyCollection<TItem> _items;
/// Initializes a new instance of the
/// <see cref="BuilderCollectionBase{TItem}" />
/// with items.
/// <summary>
/// Initializes a new instance of the <see cref="BuilderCollectionBase{TItem}" /> with items.
/// </summary>
/// <param name="items">The items.</param>
public BuilderCollectionBase(Func<IEnumerable<TItem>> items) => _items = new LazyReadOnlyCollection<TItem>(items);
public BuilderCollectionBase(Func<IEnumerable<TItem>> items)
=> _items = new LazyReadOnlyCollection<TItem>(items);
/// <inheritdoc />
public int Count => _items.Count;
/// <summary>
/// Gets an enumerator.
/// </summary>
/// <inheritdoc />
public IEnumerator<TItem> GetEnumerator() => _items.GetEnumerator();
/// <summary>
/// Gets an enumerator.
/// </summary>
/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
@@ -1,13 +1,16 @@
namespace Umbraco.Cms.Core.Composing;
/// <summary>
/// Represents a builder collection, ie an immutable enumeration of items.
/// Represents a builder collection, ie an immutable enumeration of items.
/// </summary>
/// <typeparam name="TItem">The type of the items.</typeparam>
public interface IBuilderCollection<out TItem> : IEnumerable<TItem>
{
/// <summary>
/// Gets the number of items in the collection.
/// Gets the number of items in the collection.
/// </summary>
/// <value>
/// The count.
/// </value>
int Count { get; }
}
+10 -1
View File
@@ -21,7 +21,7 @@ public class TypeFinder : ITypeFinder
/// its an exact name match
/// NOTE this means that "foo." will NOT exclude "foo.dll" but only "foo.*.dll"
/// </remarks>
internal static readonly string[] KnownAssemblyExclusionFilter =
internal static string[] KnownAssemblyExclusionFilter =
{
"mscorlib,", "netstandard,", "System,", "Antlr3.", "AutoMapper,", "AutoMapper.", "Autofac,", // DI
"Autofac.", "AzureDirectory,", "Castle.", // DI, tests
@@ -49,11 +49,20 @@ public class TypeFinder : ITypeFinder
private string[]? _assembliesAcceptingLoadExceptions;
private volatile HashSet<Assembly>? _localFilteredAssemblyCache;
[Obsolete("Please use the constructor taking all parameters. This constructor will be removed in V14.")]
public TypeFinder(ILogger<TypeFinder> logger, IAssemblyProvider assemblyProvider, ITypeFinderConfig? typeFinderConfig = null)
: this(logger, assemblyProvider, null, typeFinderConfig)
{ }
public TypeFinder(ILogger<TypeFinder> logger, IAssemblyProvider assemblyProvider, string[]? additionalExlusionAssemblies, ITypeFinderConfig? typeFinderConfig = null)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_assemblyProvider = assemblyProvider;
_typeFinderConfig = typeFinderConfig;
if (additionalExlusionAssemblies is not null)
{
KnownAssemblyExclusionFilter = KnownAssemblyExclusionFilter.Union(additionalExlusionAssemblies).ToArray();
}
}
/// <inheritdoc />
@@ -0,0 +1,18 @@
using System.ComponentModel;
namespace Umbraco.Cms.Core.Configuration.Models;
/// <summary>
/// Typed configuration options for index creator settings.
/// </summary>
[UmbracoOptions(Constants.Configuration.ConfigIndexing)]
public class IndexingSettings
{
private const bool StaticExplicitlyIndexEachNestedProperty = true;
/// <summary>
/// Gets or sets a value for whether each nested property should have it's own indexed value. Requires a rebuild of indexes when changed.
/// </summary>
[DefaultValue(StaticExplicitlyIndexEachNestedProperty)]
public bool ExplicitlyIndexEachNestedProperty { get; set; } = StaticExplicitlyIndexEachNestedProperty;
}
@@ -14,6 +14,7 @@ public class NuCacheSettings
internal const string StaticNuCacheSerializerType = "MessagePack";
internal const int StaticSqlPageSize = 1000;
internal const int StaticKitBatchSize = 1;
internal const bool StaticUsePagedSqlQuery = true;
/// <summary>
/// Gets or sets a value defining the BTree block size.
@@ -40,4 +41,7 @@ public class NuCacheSettings
public int KitBatchSize { get; set; } = StaticKitBatchSize;
public bool UnPublishedContentCompression { get; set; } = false;
[DefaultValue(StaticUsePagedSqlQuery)]
public bool UsePagedSqlQuery { get; set; } = true;
}
@@ -116,18 +116,18 @@ public class RichTextEditorSettings
new Dictionary<string, string> { ["entity_encoding"] = "raw" };
/// <summary>
/// HTML RichText Editor TinyMCE Commands
/// HTML RichText Editor TinyMCE Commands.
/// </summary>
/// WB-TODO Custom Array of objects
public RichTextEditorCommand[] Commands { get; set; } = Default_commands;
/// <summary>
/// HTML RichText Editor TinyMCE Plugins
/// HTML RichText Editor TinyMCE Plugins.
/// </summary>
public string[] Plugins { get; set; } = Default_plugins;
/// <summary>
/// HTML RichText Editor TinyMCE Custom Config
/// HTML RichText Editor TinyMCE Custom Config.
/// </summary>
/// WB-TODO Custom Dictionary
public IDictionary<string, string> CustomConfig { get; set; } = Default_custom_config;
@@ -138,7 +138,7 @@ public class RichTextEditorSettings
public string ValidElements { get; set; } = StaticValidElements;
/// <summary>
/// Invalid HTML elements for RichText Editor
/// Invalid HTML elements for RichText Editor.
/// </summary>
[DefaultValue(StaticInvalidElements)]
public string InvalidElements { get; set; } = StaticInvalidElements;
@@ -2,6 +2,7 @@
// See LICENSE for more details.
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace Umbraco.Cms.Core.Configuration.Models;
@@ -24,6 +25,8 @@ public class SecuritySettings
internal const int StaticMemberDefaultLockoutTimeInMinutes = 30 * 24 * 60;
internal const int StaticUserDefaultLockoutTimeInMinutes = 30 * 24 * 60;
private const long StaticUserDefaultFailedLoginDurationInMilliseconds = 1000;
private const long StaticUserMinimumFailedLoginDurationInMilliseconds = 250;
/// <summary>
/// Gets or sets a value indicating whether to keep the user logged in.
@@ -109,4 +112,26 @@ public class SecuritySettings
[Obsolete("Use ContentSettings.AllowEditFromInvariant instead")]
[DefaultValue(StaticAllowEditInvariantFromNonDefault)]
public bool AllowEditInvariantFromNonDefault { get; set; } = StaticAllowEditInvariantFromNonDefault;
/// <summary>
/// Gets or sets the default duration (in milliseconds) of failed login attempts.
/// </summary>
/// <value>
/// The default duration (in milliseconds) of failed login attempts.
/// </value>
/// <remarks>
/// The user login endpoint ensures that failed login attempts take at least as long as the average successful login.
/// However, if no successful logins have occurred, this value is used as the default duration.
/// </remarks>
[DefaultValue(StaticUserDefaultFailedLoginDurationInMilliseconds)]
public long UserDefaultFailedLoginDurationInMilliseconds { get; set; } = StaticUserDefaultFailedLoginDurationInMilliseconds;
/// <summary>
/// Gets or sets the minimum duration (in milliseconds) of failed login attempts.
/// </summary>
/// <value>
/// The minimum duration (in milliseconds) of failed login attempts.
/// </value>
[DefaultValue(StaticUserMinimumFailedLoginDurationInMilliseconds)]
public long UserMinimumFailedLoginDurationInMilliseconds { get; set; } = StaticUserMinimumFailedLoginDurationInMilliseconds;
}
@@ -22,4 +22,9 @@ public class TypeFinderSettings
/// scanning for plugins based on different root referenced assemblies you can add the assembly name to this list.
/// </summary>
public IEnumerable<string>? AdditionalEntryAssemblies { get; set; }
/// <summary>
/// Gets or sets a value for the assemblies that will be excluded from scanning.
/// </summary>
public string[] AdditionalAssemblyExclusionEntries { get; set; } = Array.Empty<string>();
}
@@ -38,6 +38,7 @@ public static partial class Constants
public const string ConfigHosting = ConfigPrefix + "Hosting";
public const string ConfigImaging = ConfigPrefix + "Imaging";
public const string ConfigExamine = ConfigPrefix + "Examine";
public const string ConfigIndexing = ConfigPrefix + "Indexing";
public const string ConfigKeepAlive = ConfigPrefix + "KeepAlive";
public const string ConfigLogging = ConfigPrefix + "Logging";
public const string ConfigMemberPassword = ConfigPrefix + "Security:MemberPassword";
+1
View File
@@ -28,5 +28,6 @@ public static partial class Constants
public static string IsDebug = "IsDebug";
public static string DatabaseProvider = "DatabaseProvider";
public static string CurrentServerRole = "CurrentServerRole";
public static string BackofficeExternalLoginProviderCount = "BackofficeExternalLoginProviderCount";
}
}
@@ -50,6 +50,7 @@ public static partial class UmbracoBuilderExtensions
builder
.AddUmbracoOptions<ModelsBuilderSettings>()
.AddUmbracoOptions<ActiveDirectorySettings>()
.AddUmbracoOptions<IndexCreatorSettings>()
.AddUmbracoOptions<MarketplaceSettings>()
.AddUmbracoOptions<ContentSettings>()
.AddUmbracoOptions<CoreDebugSettings>()
@@ -64,7 +65,7 @@ public static partial class UmbracoBuilderExtensions
.AddUmbracoOptions<HealthChecksSettings>()
.AddUmbracoOptions<HostingSettings>()
.AddUmbracoOptions<ImagingSettings>()
.AddUmbracoOptions<IndexCreatorSettings>()
.AddUmbracoOptions<IndexingSettings>()
.AddUmbracoOptions<KeepAliveSettings>()
.AddUmbracoOptions<LoggingSettings>()
.AddUmbracoOptions<MemberPasswordConfigurationSettings>()
@@ -318,8 +318,9 @@ namespace Umbraco.Cms.Core.DependencyInjection
Services.AddSingleton<ConflictingPackageData>();
Services.AddSingleton<CompiledPackageXmlParser>();
// Register a noop IHtmlSanitizer to be replaced
// Register a noop IHtmlSanitizer & IMarkdownSanitizer to be replaced
Services.AddUnique<IHtmlSanitizer, NoopHtmlSanitizer>();
Services.AddUnique<IMarkdownSanitizer, NoopMarkdownSanitizer>();
Services.AddUnique<IPropertyTypeUsageService, PropertyTypeUsageService>();
Services.AddUnique<IDataTypeUsageService, DataTypeUsageService>();
@@ -327,6 +328,9 @@ namespace Umbraco.Cms.Core.DependencyInjection
Services.AddUnique<ICultureImpactFactory>(provider => new CultureImpactFactory(provider.GetRequiredService<IOptionsMonitor<ContentSettings>>()));
Services.AddUnique<IDictionaryService, DictionaryService>();
Services.AddUnique<ITemporaryMediaService, TemporaryMediaService>();
// Register filestream security analyzers
Services.AddUnique<IFileStreamSecurityValidator,FileStreamSecurityValidator>();
}
}
}
+5 -10
View File
@@ -1948,7 +1948,7 @@ Da upravljate svojom web lokacijom, jednostavno otvorite Umbraco backoffice i po
<key alias="mailBody"><![CDATA[
Zdravo %0%
Ovo je automatska pošta koja vas obavještava da je za
Ovo je automatska pošta koja vas obavještava da je za
dokument '%1%' zatražen prevod na '%5%' od %2%.
Idi na http://%3%/translation/details.aspx?id=%4% za uređivanje.
@@ -2116,15 +2116,10 @@ Da upravljate svojom web lokacijom, jednostavno otvorite Umbraco backoffice i po
<key alias="userInvitedSuccessHelp">Novom korisniku je poslana pozivnica s detaljima o tome kako se prijaviti
Umbraco.
</key>
<key alias="userinviteWelcomeMessage">Pozdrav i dobrodošli u Umbraco! Za samo 1 minut možete krenuti, mi
samo trebate postaviti lozinku i dodati sliku za svoj avatar.
</key>
<key alias="userinviteWelcomeMessage">Pozdrav i dobrodošli u Umbraco! Za samo 1 minut možete krenuti, mi samo trebate postaviti lozinku.</key>
<key alias="userinviteExpiredMessage">Dobrodošli u Umbraco! Nažalost, vaš poziv je istekao. Molimo kontaktirajte svoju
administratora i zamolite ih da ga ponovo pošalju.
</key>
<key alias="userinviteAvatarMessage">Ako otpremite svoju fotografiju, drugi korisnici će ga lako prepoznati
ti. Kliknite na krug iznad da otpremite svoju fotografiju.
</key>
<key alias="writer">Pisac</key>
<key alias="change">Promjena</key>
<key alias="yourProfile" version="7.0">Vaš profil</key>
@@ -2238,8 +2233,8 @@ Da upravljate svojom web lokacijom, jednostavno otvorite Umbraco backoffice i po
<key alias="stateInactive">Neaktivan</key>
<key alias="sortNameAscending">Ime (A-Z)</key>
<key alias="sortNameDescending">Ime (Z-A)</key>
<key alias="sortCreateDateAscending">Najnovije</key>
<key alias="sortCreateDateDescending">Najstarije</key>
<key alias="sortCreateDateAscending">Najstarije</key>
<key alias="sortCreateDateDescending">Najnovije</key>
<key alias="sortLastLoginDateDescending">Zadnja prijava</key>
<key alias="noUserGroupsAdded">Nijedna korisnička grupa nije dodana</key>
<key alias="2faDisableText">Ako želite da onemogućite ovog dvofaktorskog provajdera, onda morate uneti kod prikazan na vašem uređaju za autentifikaciju:</key>
@@ -2296,7 +2291,7 @@ Da upravljate svojom web lokacijom, jednostavno otvorite Umbraco backoffice i po
1: Recommended value
-->
<key alias="macroErrorModeCheckSuccessMessage">Makro greške su postavljene na '%0%'.</key>
<key alias="macroErrorModeCheckErrorMessage">Greške makroa su postavljene na '%0%' što će spriječiti potpuno učitavanje nekih ili svih stranica
<key alias="macroErrorModeCheckErrorMessage">Greške makroa su postavljene na '%0%' što će spriječiti potpuno učitavanje nekih ili svih stranica
na vašem sajtu ako postoje greške u makroima. Ako ovo ispravite, vrijednost će biti postavljena na '%1%'.
</key>
<!-- The following keys get these tokens passed in:
@@ -1754,9 +1754,8 @@
<key alias="usergroup">Uživatelská skupina</key>
<key alias="userInvited">byl pozván</key>
<key alias="userInvitedSuccessHelp">Novému uživateli byla zaslána pozvánka s informacemi, jak se přihlásit do Umbraco.</key>
<key alias="userinviteWelcomeMessage">Dobrý den, vítejte v Umbraco! Za pouhou 1 minutu budete moci používat Umbraco. Jenom od vás potřebujeme, abyste si nastavili heslo a přidali obrázek pro svůj avatar.</key>
<key alias="userinviteWelcomeMessage">Dobrý den, vítejte v Umbraco! Za pouhou 1 minutu budete moci používat Umbraco. Jenom od vás potřebujeme, abyste si nastavili heslo.</key>
<key alias="userinviteExpiredMessage">Vítejte v Umbraco! Vaše pozvánka bohužel vypršela. Obraťte se na svého správce a požádejte jej, aby jí znovu odeslal.</key>
<key alias="userinviteAvatarMessage">Nahrání vaší fotografie usnadní ostatním uživatelům, aby vás poznali. Kliknutím na kruh výše nahrajte svou fotku.</key>
<key alias="writer">Spisovatel</key>
<key alias="change">Změnit</key>
<key alias="yourProfile" version="7.0">Váš profil</key>
@@ -1869,8 +1868,8 @@
<key alias="stateInactive">Neaktivní</key>
<key alias="sortNameAscending">Jméno (A-Z)</key>
<key alias="sortNameDescending">Jméno (Z-A)</key>
<key alias="sortCreateDateAscending">Nejnovější</key>
<key alias="sortCreateDateDescending">Nejstarší</key>
<key alias="sortCreateDateAscending">Nejstarší</key>
<key alias="sortCreateDateDescending">Nejnovější</key>
<key alias="sortLastLoginDateDescending">Poslední přihlášení</key>
<key alias="noUserGroupsAdded">Nebyly přidány žádné skupiny uživatelů</key>
</area>
@@ -576,7 +576,7 @@
<area alias="dictionary">
<key alias="noItems">Nid oes unrhyw eitemau geiriadur.</key>
<key alias="importDictionaryItemHelp">
I fewnforio eitem geiriadur, dewch o hyd i'r ffeil ".udt" ar eich cyfrifiadur trwy glicio
I fewnforio eitem geiriadur, dewch o hyd i'r ffeil ".udt" ar eich cyfrifiadur trwy glicio
ar y botwm "Mewnforio" (bydd gofyn i chi am gadarnhad ar y sgrin nesaf)
</key>
<key alias="itemDoesNotExists">Nid yw eitem geiriadur yn bodoli.</key>
@@ -2308,9 +2308,8 @@ Er mwyn gweinyddu eich gwefan, agorwch swyddfa gefn Umbraco a dechreuwch ychwang
<key alias="userGroups">Grwpiau defnyddiwr</key>
<key alias="userInvited">wedi'i wahodd</key>
<key alias="userInvitedSuccessHelp">Mae gwahoddiad wedi cael ei anfon at y defnyddiwr newydd gyda manylion ar sut i fewngofnodi i Umbraco.</key>
<key alias="userinviteWelcomeMessage">Helo a chroeso i Umbraco! Mewn 1 munud yn unig, byddech chi'n barod i fynd, rydym dim ond angen gosod cyfrinair a llun ar gyfer eich avatar.</key>
<key alias="userinviteWelcomeMessage">Helo a chroeso i Umbraco! Mewn 1 munud yn unig, byddech chi'n barod i fynd, rydym dim ond angen gosod cyfrinair.</key>
<key alias="userinviteExpiredMessage">Croeso i Umbraco! Yn anffodus, mae eich gwahoddiad wedi terfynu. Cysylltwch â'ch gweinyddwr a gofynnwch iddynt ail-anfon.</key>
<key alias="userinviteAvatarMessage">Lanlwythwch lun i wneud o'n haws i boble eich adnabod chi.</key>
<key alias="writer">Ysgrifennydd</key>
<key alias="translator">Cyfieithydd</key>
<key alias="change">Newid</key>
+8 -10
View File
@@ -54,8 +54,8 @@
<key alias="setPermissions">Sæt rettigheder</key>
<key alias="unlock">Lås op</key>
<key alias="createblueprint">Opret indholdsskabelon</key>
<key alias="resendInvite">Gensend Invitation</key>
<key alias="defaultValue">Standard værdi</key>
<key alias="resendInvite">Gensend invitation</key>
<key alias="defaultValue">Standardværdi</key>
</area>
<area alias="actionCategories">
<key alias="content">Indhold</key>
@@ -717,6 +717,7 @@
<key alias="by">af</key>
<key alias="cancel">Fortryd</key>
<key alias="cellMargin">Celle margen</key>
<key alias="change">Skift</key>
<key alias="choose">Vælg</key>
<key alias="clear">Ryd</key>
<key alias="close">Luk</key>
@@ -1894,14 +1895,11 @@ Mange hilsner fra Umbraco robotten
logger ind i Umbraco.
</key>
<key alias="userinviteWelcomeMessage">Hej og velkommen til Umbraco! På bare 1 minut vil du være klar til at komme i
gang, vi skal bare have dig til at oprette en adgangskode og tilføje et billede til din avatar.
gang, vi skal bare have dig til at oprette en adgangskode.
</key>
<key alias="userinviteExpiredMessage">Velkommen til Umbraco! Desværre er din invitation udløbet. Kontakt din
administrator og bed om at gensende invitationen.
</key>
<key alias="userinviteAvatarMessage">Hvis du uploader et billede af dig selv, gør du det nemt for andre brugere at
genkende dig. Klik på cirklen ovenfor for at uploade et billede.
</key>
<key alias="writer">Forfatter</key>
<key alias="configureTwoFactor">Konfigurer totrinsbekræftelse</key>
<key alias="change">Skift</key>
@@ -1927,8 +1925,8 @@ Mange hilsner fra Umbraco robotten
<key alias="stateInactive">Inaktiv</key>
<key alias="sortNameAscending">Navn (A-Å)</key>
<key alias="sortNameDescending">Navn (Å-A)</key>
<key alias="sortCreateDateAscending">Nyeste</key>
<key alias="sortCreateDateDescending">Ældste</key>
<key alias="sortCreateDateAscending">Ældste</key>
<key alias="sortCreateDateDescending">Nyeste</key>
<key alias="sortLastLoginDateDescending">Sidst logget ind</key>
<key alias="noUserGroupsAdded">Ingen brugere er blevet tilføjet</key>
<key alias="2faDisableText">Hvis du ønsker at slå denne totrinsbekræftelse fra, så skal du nu indtaste koden fra din enhed:</key>
@@ -2232,7 +2230,7 @@ Mange hilsner fra Umbraco robotten
<key alias="allowedBlockColumnsHelp">Vælg de forskellige antal kolonner denne blok må optage i layoutet. Dette forhindre ikke blokken i at optræde i et mindre område.</key>
<key alias="allowedBlockRows">TIlgængelige række-størrelser</key>
<key alias="allowedBlockRowsHelp">Vælg hvor mange rækker denne blok på optage i layoutet.</key>
<key alias="allowBlockInRoot">Tillad på rodniveay</key>
<key alias="allowBlockInRoot">Tillad på rodniveau</key>
<key alias="allowBlockInRootHelp">Gør denne blok tilgængelig i layoutets rodniveau. Hvis dette ikke er valgt, kan denne blok kun bruges inden for andre blokkes definerede områder.</key>
<key alias="areas">Blok-områder</key>
<key alias="areasLayoutColumns">Layout-kolonner</key>
@@ -2240,7 +2238,7 @@ Mange hilsner fra Umbraco robotten
<key alias="areasConfigurations">Opsætning af områder</key>
<key alias="areasConfigurationsHelp">Hvis det skal være muligt at indsætte nye blokke indeni denne blok, skal der oprettes ét eller flere områder til at indsætte de nye blokke i.</key>
<key alias="invalidDropPosition">Ikke tilladt placering.</key>
<key alias="defaultLayoutStylesheet">Standart layout stylesheet</key>
<key alias="defaultLayoutStylesheet">Standardlayout stylesheet</key>
<key alias="confirmPasteDisallowedNestedBlockHeadline">Ikke tilladt indhold blev afvist</key>
<key alias="confirmPasteDisallowedNestedBlockMessage">
<![CDATA[Det indsatte indhold bestod af ikke tilladt del-indhold, disse dele er blevet afvist. Vil du beholde det resterene alligevel?]]></key>
+30 -31
View File
@@ -110,7 +110,7 @@
Außerdem werden Pfade mit erstem URL-Segment unterstützt z. B.: "example.com/en" or "/en".]]></key>
<key alias="inherit">Vererben</key>
<key alias="setLanguage">Kultur</key>
<key alias="setLanguageHelp">Definiert die Kultureinstellung für untergeordnete Elemente dieses Elements oder vererbt vom übergeordneten Element.
<key alias="setLanguageHelp">Definiert die Kultureinstellung für untergeordnete Elemente dieses Elements oder vererbt vom übergeordneten Element.
Wird auch auf das aktuelle Element angewendet, sofern auf tieferer Ebene keine Domain zugeordnet ist.</key>
<key alias="setDomains">Domainen</key>
</area>
@@ -232,10 +232,10 @@
<key alias="noMediaLink">Dieses Media-Element hat keinen Link</key>
<key alias="noProperties">Diesem Element kann kein Inhalt zugewiesen werden</key>
<key alias="otherElements">Eigenschaften</key>
<key alias="parentNotPublished">Dieses Dokument ist veröffentlicht aber nicht sichtbar,
<key alias="parentNotPublished">Dieses Dokument ist veröffentlicht aber nicht sichtbar,
da das übergeordnete Dokument '%0%' nicht publiziert ist
</key>
<key alias="parentCultureNotPublished">Diese Kultur wurde veröffentlicht, aber wird nicht angezeigt,
<key alias="parentCultureNotPublished">Diese Kultur wurde veröffentlicht, aber wird nicht angezeigt,
weil sie auf dem Oberknoten '%0%' unveröffentlicht ist
</key>
<key alias="parentNotPublishedAnomaly">Ups! Dieses Dokument ist veröffentlicht aber nicht im internen Cache aufzufinden: Systemfehler.</key>
@@ -255,7 +255,7 @@
<key alias="removeDate">Datum entfernen</key>
<key alias="setDate">Datum wählen</key>
<key alias="sortDone">Sortierung abgeschlossen</key>
<key alias="sortHelp">Um die Dokumente zu sortieren, ziehen Sie sie einfach an die gewünschte Position.
<key alias="sortHelp">Um die Dokumente zu sortieren, ziehen Sie sie einfach an die gewünschte Position.
Sie können mehrere Zeilen markieren indem Sie die Umschalttaste ("Shift") oder die Steuerungstaste ("Strg") gedrückt halten
</key>
<key alias="statistics">Statistiken</key>
@@ -281,7 +281,7 @@
<![CDATA[<a href="https://docs.umbraco.com/umbraco-cms/fundamentals/data/scheduled-publishing#timezones" target="_blank" rel="noopener">Was bedeutet dies?</a>]]></key>
<key alias="nestedContentDeleteItem">Wollen Sie dieses Element wirklich entfernen?</key>
<key alias="nestedContentDeleteAllItems">Sicher das Sie alle Elemente entfernen wollen?</key>
<key alias="nestedContentEditorNotSupported">Eigenschaft %0% verwendet Editor %1%,
<key alias="nestedContentEditorNotSupported">Eigenschaft %0% verwendet Editor %1%,
welcher nicht von Nested Content unterstützt wird.
</key>
<key alias="nestedContentNoContentTypes">Keine Dokument-Typen für diese Eigenschaft konfiguriert.</key>
@@ -299,14 +299,14 @@
<key alias="removeTextBox">Entferne dieses Textfeld</key>
<key alias="contentRoot">Inhalt-Basis</key>
<key alias="includeUnpublished">Inklusive Entwürfen: veröffentliche auch unveröffentlichte Elemente.</key>
<key alias="isSensitiveValue">Dieser Wert ist verborgen.
<key alias="isSensitiveValue">Dieser Wert ist verborgen.
Wenn Sie diesen Wert einsehen müssen, wenden Sie sich bitte an einen Administrator.
</key>
<key alias="isSensitiveValue_short">Dieser Wert ist verborgen.</key>
<key alias="languagesToPublish">Welche Sprache möchten Sie veröffentlichen?</key>
<key alias="languagesToSendForApproval">Welche Sprachen möchten Sie zur Freigabe schicken?</key>
<key alias="languagesToSchedule">Welche Sprachen möchten Sie zu einer bestimmten Zeit veröffentlichen?</key>
<key alias="languagesToUnpublish">Wählen Sie die Sprachen, deren Veröffentlichung zurück genommen werden soll.
<key alias="languagesToUnpublish">Wählen Sie die Sprachen, deren Veröffentlichung zurück genommen werden soll.
Das Zurücknehmen der Veröffentlichung einer Pflichtsprache betrifft alle Sprachen.
</key>
<key alias="variantsWillBeSaved">Alle neuen Variationen werden gespeichert.</key>
@@ -335,7 +335,7 @@
<key alias="createdBlueprintHeading">Inhaltsvorlage erzeugt</key>
<key alias="createdBlueprintMessage">Inhaltsvorlage von '%0%' wurde erzeugt</key>
<key alias="duplicateBlueprintMessage">Eine gleichnamige Inhaltsvorlage ist bereits vorhanden</key>
<key alias="blueprintDescription">Eine Inhaltsvorlage ist vordefinierter Inhalt,
<key alias="blueprintDescription">Eine Inhaltsvorlage ist vordefinierter Inhalt,
den ein Redakteur als Basis für neuen Inhalt verwenden kann
</key>
</area>
@@ -343,7 +343,7 @@
<key alias="clickToUpload">Für Upload klicken</key>
<key alias="orClickHereToUpload">oder klicken Sie hier um eine Datei zu wählen</key>
<key alias="disallowedFileType">Dieser Dateityp darf nicht hochgeladen werden</key>
<key alias="invalidFileName">Diese Datei kann nicht hochgeladen werden wil der Dateiname ungültig ist.</key><key alias="disallowedMediaType">Diese Datei kann nicht hochgeladen werden, der Medienttype mit dem Alias '%0%' ist hier nicht erlaubt.</key>
<key alias="maxFileSize">Max. Dateigröße ist</key>
<key alias="mediaRoot">Media-Basis</key>
@@ -386,16 +386,16 @@
<![CDATA[Es stehen keine erlaubten Dokumenttypen zur Verfügung. Sie müssen diese in den Einstellungen (unter "Dokumenttypen") aktivieren.]]></key>
<key alias="noDocumentTypesAtRoot">
<![CDATA[Es stehen keine erlaubten Dokumenttypen zur Verfügung. Sie müssen diese in den Einstellungen (unter "Dokumenttypen") aktivieren.]]></key>
<key alias="noDocumentTypesWithNoSettingsAccess">Die im Inhaltsbaum ausgewählte Seite
<key alias="noDocumentTypesWithNoSettingsAccess">Die im Inhaltsbaum ausgewählte Seite
erlaubt keine Unterseiten.
</key>
<key alias="noDocumentTypesEditPermissions">Bearbeitungsrechte für diesen Dokumenttyp</key>
<key alias="noDocumentTypesCreateNew">Neuen Dokumenttypen erstellen</key>
<key alias="noDocumentTypesAllowedAtRoot">
<![CDATA[Keine Dokumenttypen vorhanden welche hier eingefügt werden dürfen. Sie müssen diese in den Einstellungen (unter "Dokumenttypen") aktivieren.]]></key>
<key alias="noMediaTypes" version="7.0"><![CDATA[Es stehen keine erlaubten Medientypen zur Verfügung.
<key alias="noMediaTypes" version="7.0"><![CDATA[Es stehen keine erlaubten Medientypen zur Verfügung.
Sie müssen diese in den Einstellungen (unter "Medientypen") aktivieren.]]></key>
<key alias="noMediaTypesWithNoSettingsAccess">Das im Strukturbaum ausgewählte Medienelement
<key alias="noMediaTypesWithNoSettingsAccess">Das im Strukturbaum ausgewählte Medienelement
erlaubt keine untergeordneten Elemente.
</key>
<key alias="noMediaTypesEditPermissions">Bearbeitungsrechte für diesen Medientyp</key>
@@ -444,15 +444,15 @@
<key alias="stay">Bleiben</key>
<key alias="discardChanges">Änderungen verwerfen</key>
<key alias="unsavedChanges">Es gibt ungesicherte Änderungen</key>
<key alias="unsavedChangesWarning">Wollen Sie diese Seite wirklich verlassen?
<key alias="unsavedChangesWarning">Wollen Sie diese Seite wirklich verlassen?
- es gibt ungesicherte Änderungen
</key>
<key alias="confirmListViewPublish">Veröffentlichen macht die ausgewählten Elemente auf der Website sichtbar.</key>
<key alias="confirmListViewUnpublish">Aufheben der Veröffentlichung entfernt die ausgewählten Elemente
<key alias="confirmListViewUnpublish">Aufheben der Veröffentlichung entfernt die ausgewählten Elemente
und ihre Unterknoten von der Website.
</key>
<key alias="confirmUnpublish">Aufheben der Veröffentlichung entfernt diese Seite und ihre Unterseiten von der Website.</key>
<key alias="doctypeChangeWarning">Es gibt ungesicherte Änderungen.
<key alias="doctypeChangeWarning">Es gibt ungesicherte Änderungen.
Ändern des Dokumenttyps macht diese rückgängig.
</key>
</area>
@@ -518,7 +518,7 @@
<key alias="permissionsSet">Berechtigungen vergeben für</key>
<key alias="permissionsSetForGroup">Berechtigungen vergeben für %0% für Benutzer-Gruppe %1%</key>
<key alias="permissionsHelp">Wählen Sie die Benutzer-Gruppe, deren Berechtigungen Sie setzen möchten</key>
<key alias="recycleBinDeleting">Der Papierkorb wird geleert.
<key alias="recycleBinDeleting">Der Papierkorb wird geleert.
Bitte warten Sie und schließen Sie das Fenster erst, wenn der Vorgang abgeschlossen ist.
</key>
<key alias="recycleBinIsEmpty">Der Papierkorb ist leer</key>
@@ -531,10 +531,10 @@
<key alias="removeMacro">Macro entfernen</key>
<key alias="requiredField">Pflichtfeld</key>
<key alias="sitereindexed">Die Website-Index wurd neu erstellt</key>
<key alias="siterepublished">Der Zwischenspeicher der Website wurde aktualisiert und alle veröffentlichten Inhalte sind jetzt auf dem neuesten Stand.
<key alias="siterepublished">Der Zwischenspeicher der Website wurde aktualisiert und alle veröffentlichten Inhalte sind jetzt auf dem neuesten Stand.
Bisher unveröffentliche Inhalte wurden dabei nicht veröffentlicht.
</key>
<key alias="siterepublishHelp">Der Zwischenspeicher der Website wird aktualisiert und der veröffentlichte Inhalt auf den neuesten Stand gebracht.
<key alias="siterepublishHelp">Der Zwischenspeicher der Website wird aktualisiert und der veröffentlichte Inhalt auf den neuesten Stand gebracht.
Unveröffentlichte Inhalte bleiben dabei weiterhin unveröffentlicht.
</key>
<key alias="tableColumns">Anzahl der Spalten</key>
@@ -696,21 +696,21 @@
<key alias="wasMoved">wurde verschoben in</key>
<key alias="hasReferencesDeleteConsequence">
<![CDATA[Löschen von <strong>%0%</strong> wird die Eigenschaften und Daten von folgenden Element löschen]]></key>
<key alias="acceptDeleteConsequence">Ich verstehe das diese Aktion Eigenschaften und Daten basierend auf diesem
<key alias="acceptDeleteConsequence">Ich verstehe das diese Aktion Eigenschaften und Daten basierend auf diesem
DataTyps löschen wird.
</key>
</area>
<area alias="errorHandling">
<key alias="errorButDataWasSaved">Ihre Daten wurden gespeichert.
<key alias="errorButDataWasSaved">Ihre Daten wurden gespeichert.
Bevor Sie diese Seite jedoch veröffentlichen können, müssen Sie die folgenden Korrekturen vornehmen:
</key>
<key alias="errorChangingProviderPassword">Der aktuelle Mitgliedschaftsanbieter erlaubt keine Kennwortänderung
<key alias="errorChangingProviderPassword">Der aktuelle Mitgliedschaftsanbieter erlaubt keine Kennwortänderung
(EnablePasswordRetrieval muss auf "true" gesetzt sein)
</key>
<key alias="errorExistsWithoutTab">'%0%' ist bereits vorhanden</key>
<key alias="errorHeader">Bitte prüfen und korrigieren:</key>
<key alias="errorHeaderWithoutTab">Bitte prüfen und korrigieren:</key>
<key alias="errorInPasswordFormat">Für das Kennwort ist eine Mindestlänge von %0% Zeichen vorgesehen,
<key alias="errorInPasswordFormat">Für das Kennwort ist eine Mindestlänge von %0% Zeichen vorgesehen,
wovon mindestens %1% Sonderzeichen (nicht alphanumerisch) sein müssen
</key>
<key alias="errorIntegerWithoutTab">'%0%' muss eine Zahl sein</key>
@@ -724,7 +724,7 @@
<key alias="concurrencyError">Optimistic concurrency Fehler, Objekte wurde geändert.</key>
<key alias="receivedErrorFromServer">Der Server hat einen Fehler gemeldet</key>
<key alias="dissallowedMediaType">Dieser Dateityp wird durch die Systemeinstellungen blockiert</key>
<key alias="codemirroriewarning">ACHTUNG! Obwohl CodeMirror in den Einstellungen aktiviert ist,
<key alias="codemirroriewarning">ACHTUNG! Obwohl CodeMirror in den Einstellungen aktiviert ist,
bleibt das Modul wegen mangelnder Stabilität in Internet Explorer deaktiviert.
</key>
<key alias="contentTypeAliasAndNameNotNull">Bitte geben Sie die Bezeichnung und den Alias des neuen Dokumenttyps ein.</key>
@@ -732,7 +732,7 @@
<key alias="macroErrorLoadingPartialView">Fehler beim Laden einer "Partial View Kodedatei" (Datei: %0%)</key>
<key alias="missingTitle">Bitte geben Sie einen Titel ein</key>
<key alias="missingType">Bitte wählen Sie einen Typ</key>
<key alias="pictureResizeBiggerThanOrg">Soll die Abbildung wirklich über die
<key alias="pictureResizeBiggerThanOrg">Soll die Abbildung wirklich über die
Originalgröße hinaus vergrößert werden?
</key>
<key alias="startNodeDoesNotExists">Startelement gelöscht, bitte kontaktieren Sie den System-Administrator.</key>
@@ -957,7 +957,7 @@
<![CDATA[
Klicken Sie auf <strong>Installieren</strong>, um die Datenbank für Umbraco %0% einzurichten.
]]></key>
<key alias="databaseInstallDone">Die Datenbank wurde für Umbraco %0% konfiguriert.
<key alias="databaseInstallDone">Die Datenbank wurde für Umbraco %0% konfiguriert.
Klicken Sie auf &lt;strong&gt;weiter&lt;/strong&gt;, um fortzufahren.</key>
<key alias="databaseText">Um diesen Schritt abzuschließen, müssen Sie die notwendigen Informationen zur Datenbankverbindung angeben.&lt;br /&gt;Bitte kontaktieren Sie Ihren Provider bzw. Server-Administrator für weitere Informationen.</key>
<key alias="databaseUpgrade">
@@ -2059,9 +2059,8 @@
<key alias="usergroup">Benutzergruppe</key>
<key alias="userInvited">wurde eingeladen</key>
<key alias="userInvitedSuccessHelp">Eine Einladung mit Anweisungen zur Anmeldung im Umbraco-Back-Office wurde dem neuen Benutzer zugeschickt.</key>
<key alias="userinviteWelcomeMessage">Hallo und Willkommen bei Umbraco! In nur einer Minute sind Sie bereit loszulegen, Sie müssen nur ein Kennwort festlegen und optinal Ihrem Avatar ein Bild hinzufügen.</key>
<key alias="userinviteWelcomeMessage">Hallo und Willkommen bei Umbraco! In nur einer Minute sind Sie bereit loszulegen, Sie müssen nur ein Kennwort festlegen.</key>
<key alias="userinviteExpiredMessage">Willkommen bei Umbraco! Bedauerlicherweise ist Ihre Einladung verfallen. Bitte kontaktieren Sie Ihren Administrator und bitten Sie ihn, diese erneut zu schicken.</key>
<key alias="userinviteAvatarMessage">Laden Sie ein Foto von sich hoch, um es anderen Benutzern zu erleichtern, sie zu erkennen. Klicken Sie auf den Kreis oben, um Ihr Foto hochzuladen.</key>
<key alias="writer">Autor</key>
<key alias="change">Änderung</key>
<!--???-->
@@ -2179,8 +2178,8 @@
<key alias="stateInactive">Nicht aktiv</key>
<key alias="sortNameAscending">Name (A-Z)</key>
<key alias="sortNameDescending">Name (Z-A)</key>
<key alias="sortCreateDateAscending">Newest</key>
<key alias="sortCreateDateDescending">Oldest</key>
<key alias="sortCreateDateAscending">Oldest</key>
<key alias="sortCreateDateDescending">Newest</key>
<key alias="sortLastLoginDateDescending">Last login</key>
</area>
<area alias="validation">
@@ -2339,7 +2338,7 @@
</area>
<area alias="contentTemplatesDashboard">
<key alias="whatHeadline">Was sind Inhaltsvorlagen?</key>
<key alias="whatDescription">Inhaltsvorlagen sind vordefinierte Inhalte die ausgewählt werden können
<key alias="whatDescription">Inhaltsvorlagen sind vordefinierte Inhalte die ausgewählt werden können
wenn Sie einen neuen Inhaltsknoten anlegen wollen.
</key>
<key alias="createHeadline">Wie erstelle ich eine Inhaltsvorlage?</key>
@@ -2381,7 +2380,7 @@
<key alias="FileWritingForPackages">Dateien durch Packages erstellen lassen</key>
<key alias="FileWriting">Dateien schreiben</key>
<key alias="MediaFolderCreation">Medien Ordner stellen</key>
</area>
</area>
<area alias="treeSearch">
<key alias="searchResult">Element zurückgegeben</key>
<key alias="searchResults">Elemente zurückgegeben</key>
@@ -341,6 +341,7 @@
<key alias="createFolderFailed">Failed to create a folder under parent id %0%</key>
<key alias="renameFolderFailed">Failed to rename the folder with id %0%</key>
<key alias="dragAndDropYourFilesIntoTheArea">Drag and drop your file(s) into the area</key>
<key alias="fileSecurityValidationFailure">One or more file security validations have failed</key>
</area>
<area alias="member">
<key alias="createNewMember">Create a new member</key>
@@ -488,7 +489,7 @@
<key alias="insertlink">Insert link</key>
<key alias="insertMacro">Click to add a Macro</key>
<key alias="inserttable">Insert table</key>
<key alias="languagedeletewarning">This will delete the language</key>
<key alias="languagedeletewarning">This will delete the language and all content related to the language</key>
<key alias="languageChangeWarning">Changing the culture for a language may be an expensive operation and will result
in the content cache and indexes being rebuilt
</key>
@@ -2124,14 +2125,11 @@ To manage your website, simply open the Umbraco backoffice and start adding cont
Umbraco.
</key>
<key alias="userinviteWelcomeMessage">Hello there and welcome to Umbraco! In just 1 minute youll be good to go, we
just need you to setup a password and add a picture for your avatar.
just need you to setup a password.
</key>
<key alias="userinviteExpiredMessage">Welcome to Umbraco! Unfortunately your invite has expired. Please contact your
administrator and ask them to resend it.
</key>
<key alias="userinviteAvatarMessage">Uploading a photo of yourself will make it easy for other users to recognize
you. Click the circle above to upload your photo.
</key>
<key alias="writer">Writer</key>
<key alias="change">Change</key>
<key alias="yourProfile" version="7.0">Your profile</key>
@@ -2245,8 +2243,8 @@ To manage your website, simply open the Umbraco backoffice and start adding cont
<key alias="stateInactive">Inactive</key>
<key alias="sortNameAscending">Name (A-Z)</key>
<key alias="sortNameDescending">Name (Z-A)</key>
<key alias="sortCreateDateAscending">Newest</key>
<key alias="sortCreateDateDescending">Oldest</key>
<key alias="sortCreateDateAscending">Oldest</key>
<key alias="sortCreateDateDescending">Newest</key>
<key alias="sortLastLoginDateDescending">Last login</key>
<key alias="noUserGroupsAdded">No user groups have been added</key>
<key alias="2faDisableText">If you wish to disable this two-factor provider, then you must enter the code shown on your authentication device:</key>
@@ -352,6 +352,7 @@
<key alias="renameFolderFailed">Failed to rename the folder with id %0%</key>
<key alias="dragAndDropYourFilesIntoTheArea">Drag and drop your file(s) into the area</key>
<key alias="uploadNotAllowed">Upload is not allowed in this location.</key>
<key alias="fileSecurityValidationFailure">One or more file security validations have failed</key>
</area>
<area alias="member">
<key alias="createNewMember">Create a new member</key>
@@ -503,7 +504,7 @@
<key alias="insertlink">Insert link</key>
<key alias="insertMacro">Click to add a Macro</key>
<key alias="inserttable">Insert table</key>
<key alias="languagedeletewarning">This will delete the language</key>
<key alias="languagedeletewarning">This will delete the language and all content related to the language</key>
<key alias="languageChangeWarning">Changing the culture for a language may be an expensive operation and will result
in the content cache and indexes being rebuilt
</key>
@@ -757,6 +758,7 @@
<key alias="by">by</key>
<key alias="cancel">Cancel</key>
<key alias="cellMargin">Cell margin</key>
<key alias="change">Change</key>
<key alias="choose">Choose</key>
<key alias="clear">Clear</key>
<key alias="close">Close</key>
@@ -2218,14 +2220,11 @@ To manage your website, simply open the Umbraco backoffice and start adding cont
Umbraco.
</key>
<key alias="userinviteWelcomeMessage">Hello there and welcome to Umbraco! In just 1 minute youll be good to go, we
just need you to setup a password and add a picture for your avatar.
just need you to setup a password.
</key>
<key alias="userinviteExpiredMessage">Welcome to Umbraco! Unfortunately your invite has expired. Please contact your
administrator and ask them to resend it.
</key>
<key alias="userinviteAvatarMessage">Uploading a photo of yourself will make it easy for other users to recognize
you. Click the circle above to upload your photo.
</key>
<key alias="writer">Writer</key>
<key alias="configureTwoFactor">Configure Two-Factor</key>
<key alias="change">Change</key>
@@ -2340,8 +2339,8 @@ To manage your website, simply open the Umbraco backoffice and start adding cont
<key alias="stateInactive">Inactive</key>
<key alias="sortNameAscending">Name (A-Z)</key>
<key alias="sortNameDescending">Name (Z-A)</key>
<key alias="sortCreateDateAscending">Newest</key>
<key alias="sortCreateDateDescending">Oldest</key>
<key alias="sortCreateDateAscending">Oldest</key>
<key alias="sortCreateDateDescending">Newest</key>
<key alias="sortLastLoginDateDescending">Last login</key>
<key alias="noUserGroupsAdded">No user groups have been added</key>
<key alias="2faDisableText">If you wish to disable this two-factor provider, then you must enter the code shown on your authentication device:</key>
@@ -3005,7 +3004,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont
We will send:
<ul>
<li>Anonymized site ID, Umbraco version, and packages installed.</li>
<li>Number of: Root nodes, Content nodes, Macros, Media, Document Types, Templates, Languages, Domains, User Group, Users, Members, and Property Editors in use.</li>
<li>Number of: Root nodes, Content nodes, Macros, Media, Document Types, Templates, Languages, Domains, User Group, Users, Members, Backoffice external login providers, and Property Editors in use.</li>
<li>System information: Webserver, server OS, server framework, server OS language, and database provider.</li>
<li>Configuration settings: Modelsbuilder mode, if custom Umbraco path exists, ASP environment, and if you are in debug mode.</li>
</ul>
@@ -1394,8 +1394,7 @@
<key alias="usergroup">Grupo de usuario</key>
<key alias="userInvited">ha sido invitado</key>
<key alias="userInvitedSuccessHelp">Se ha enviado una invitación al nuevo usuario con detalles sobre cómo acceder a Umbraco.</key>
<key alias="userinviteWelcomeMessage">¡Hola y bienvenido a Umbraco!. En un minuto todo estará listo para empezar, sólo necesitamos que configures tu contraseña y una imagen para tu avatar.</key>
<key alias="userinviteAvatarMessage">Sube una foto para que otros usuarios te reconozcan más fácilmente.</key>
<key alias="userinviteWelcomeMessage">¡Hola y bienvenido a Umbraco!. En un minuto todo estará listo para empezar, sólo necesitamos que configures tu contraseña.</key>
<key alias="writer">Redactor</key>
<key alias="change">Cambiar</key>
<key alias="yourProfile" version="7.0">Tu perfil</key>
@@ -1795,9 +1795,8 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à
<key alias="usergroup">Groupe d'utilisateurs</key>
<key alias="userInvited">a été invité</key>
<key alias="userInvitedSuccessHelp">Une invitation a été envoyée au nouvel utilisateur avec les détails concernant la connexion à Umbraco.</key>
<key alias="userinviteWelcomeMessage">Bien le bonjour et bienvenue dans Umbraco! Vous serez prêt.e dans moins d'1 minute, vous devez encore simplement configurer votre mot de passe et ajouter une photo pour votre avatar.</key>
<key alias="userinviteWelcomeMessage">Bien le bonjour et bienvenue dans Umbraco! Vous serez prêt.e dans moins d'1 minute, vous devez encore simplement configurer votre mot de passe.</key>
<key alias="userinviteExpiredMessage">Bienvenue dans Umbraco! Malheureusement, votre invitation a expiré. Veuillez contacter votre administrateur et demandez-lui de vous l'envoyer à nouveau.</key>
<key alias="userinviteAvatarMessage">Chargez une photo afin que les autres utilisateurs puissent vous reconnaître facilement. Cliquez sur le cercle ci-dessus pour charger votre photo.</key>
<key alias="writer">Rédacteur</key>
<key alias="change">Modifier</key>
<key alias="yourProfile" version="7.0">Votre profil</key>
@@ -1910,8 +1909,8 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à
<key alias="stateInactive">Inactif</key>
<key alias="sortNameAscending">Nom (A-Z)</key>
<key alias="sortNameDescending">Nom (Z-A)</key>
<key alias="sortCreateDateAscending">Plus récent</key>
<key alias="sortCreateDateDescending">Plus ancien</key>
<key alias="sortCreateDateAscending">Plus ancien</key>
<key alias="sortCreateDateDescending">Plus récent</key>
<key alias="sortLastLoginDateDescending">Dernière connexion</key>
</area>
<area alias="validation">
File diff suppressed because it is too large Load Diff
@@ -2197,13 +2197,10 @@ Per gestire il tuo sito web, è sufficiente aprire il backoffice di Umbraco e in
<key alias="userInvitedSuccessHelp">
<![CDATA[Un invito è stato invitato al nuovo utente con le istruzioni su come effettuare il login in Umbraco.]]></key>
<key alias="userinviteWelcomeMessage">Ciao e benvenuto su Umbraco! In solo 1 minuto sarai pronto a partire, dovrai
solamente impostare una password e aggiungere una foto profilo.
solamente impostare una password.
</key>
<key alias="userinviteExpiredMessage">
<![CDATA[Benvenuto su Umbraco! Purtroppo il tuo invito è scaduto. Per favore contatta l'amministratore e chiedigli di rispedirlo.]]></key>
<key alias="userinviteAvatarMessage">Caricando una tua foto, gli altri utenti potranno riconoscerti facilmente. Fai
clic sul cerchio sopra per caricare la tua foto.
</key>
<key alias="writer">Autore</key>
<key alias="change">Modifica</key>
<key alias="yourProfile" version="7.0">Il tuo profilo</key>
@@ -2319,8 +2316,8 @@ Per gestire il tuo sito web, è sufficiente aprire il backoffice di Umbraco e in
<key alias="stateInactive">Inattivi</key>
<key alias="sortNameAscending">Nome (A-Z)</key>
<key alias="sortNameDescending">Nome (Z-A)</key>
<key alias="sortCreateDateAscending"><![CDATA[Più nuovi]]></key>
<key alias="sortCreateDateDescending"><![CDATA[Più vecchi]]></key>
<key alias="sortCreateDateAscending"><![CDATA[Più vecchi]]></key>
<key alias="sortCreateDateDescending"><![CDATA[Più nuovi]]></key>
<key alias="sortLastLoginDateDescending">Ultimo login</key>
<key alias="noUserGroupsAdded">Non sono stati aggiunti gruppi di utenti</key>
</area>
@@ -340,6 +340,7 @@
<key alias="renameFolderFailed">Kan de map met id %0% niet hernoemen</key>
<key alias="dragAndDropYourFilesIntoTheArea">Sleep en zet je bestand(en) neer in dit gebied</key>
<key alias="uploadNotAllowed">Upload is niet toegelaten in deze locatie.</key>
<key alias="fileSecurityValidationFailure">Een of meerdere veiligheid validaties zijn gefaald voor het bestand</key>
</area>
<area alias="member">
<key alias="createNewMember">Maak nieuw lid aan</key>
@@ -1937,12 +1938,11 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je
te loggen in Umbraco
</key>
<key alias="userinviteWelcomeMessage">Hallo en welkom in Umbraco! Binnen ongeveer één minuut kan je aan de slag. Je
moet enkel je wachtwoord instellen en een foto toevoegen.
moet enkel je wachtwoord instellen.
</key>
<key alias="userinviteExpiredMessage">Welkom bij Umbraco! Helaas is je uitnodiging vervallen. Vraag aan je
administrator om de uitnodiging opnieuw te versturen.
</key>
<key alias="userinviteAvatarMessage">Wijzig je foto zodat andere gebruikers je makkelijk kunnen herkennen.</key>
<key alias="writer">Auteur</key>
<key alias="configureTwoFactor">Configureer tweestapsverificatie</key>
<key alias="change">Wijzig</key>
@@ -2056,8 +2056,8 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je
<key alias="stateInactive">Inactief</key>
<key alias="sortNameAscending">Naam (A-Z)</key>
<key alias="sortNameDescending">Naam (Z-A)</key>
<key alias="sortCreateDateAscending">Nieuwste</key>
<key alias="sortCreateDateDescending">Oudste</key>
<key alias="sortCreateDateAscending">Oudste</key>
<key alias="sortCreateDateDescending">Nieuwste</key>
<key alias="sortLastLoginDateDescending">Laatste login</key>
<key alias="noUserGroupsAdded">Er zijn geen gebruikersgroepen toegevoegd</key>
</area>
@@ -822,6 +822,8 @@ Você pode publicar esta página e todas suas sub-páginas ao selecionar <em>pub
<key alias="usertype">Tipo de usuário</key>
<key alias="userTypes">Tipos de usuários</key>
<key alias="writer">Escrevente</key>
<key alias="sortCreateDateAscending">Mais antigo</key>
<key alias="sortCreateDateDescending">Mais recente</key>
</area>
<area alias="logViewer">
<key alias="selectAllLogLevelFilters">Selecionar tudo</key>
@@ -1703,8 +1703,7 @@
<key alias="usergroup">Группа пользователей</key>
<key alias="userInvited"> был приглашен</key>
<key alias="userInvitedSuccessHelp">Новому пользователю было отправлено приглашение, в котором содержатся инструкции для входа в панель Umbraco.</key>
<key alias="userinviteWelcomeMessage">Здравствуйте и добро пожаловать в Umbraco! Все будет готово в течении пары минут, нам лишь нужно задать Ваш пароль для входа и добавить аватар.</key>
<key alias="userinviteAvatarMessage">Загрузите изображение, это поможет другим пользователям идентифицировать Вас.</key>
<key alias="userinviteWelcomeMessage">Здравствуйте и добро пожаловать в Umbraco! Все будет готово в течении пары минут, нам лишь нужно задать Ваш пароль для входа.</key>
<key alias="userManagement">Управление пользователями</key>
<key alias="userPermissions">Разрешения для пользователя</key>
<key alias="writer">Автор</key>
@@ -134,7 +134,7 @@
<key alias="saveToPublish">Spara och skicka för godkännande</key>
<key alias="schedulePublish">Schemaläggning</key>
<key alias="select">Välj</key>
<key alias="saveAndPreview">Förhandsgranska</key>
<key alias="saveAndPreview">Spara och förhandsgranska</key>
<key alias="showPageDisabled">Förhandsgranskning är avstängt på grund av att det inte finns någon mall tilldelad</key>
<key alias="somethingElse">Gör något annat</key>
<key alias="styleChoose">Välj stil</key>
@@ -1001,8 +1001,8 @@
<key alias="writer">Skribent</key>
<key alias="yourHistory">Din nuvarande historik</key>
<key alias="yourProfile">Din profil</key>
<key alias="sortCreateDateAscending">Nyast</key>
<key alias="sortCreateDateDescending">Äldst</key>
<key alias="sortCreateDateAscending">Äldst</key>
<key alias="sortCreateDateDescending">Nyast</key>
<key alias="sortLastLoginDateDescending">Senaste login</key>
</area>
<area alias="logViewer">
@@ -1879,9 +1879,8 @@ Web sitenizi yönetmek için, Umbraco'nun arka ofisini açın ve içerik eklemey
<key alias="usergroup">Kullanıcı grubu</key>
<key alias="userInvited">davet edildi</key>
<key alias="userInvitedSuccessHelp">Yeni kullanıcıya, Umbraco'da nasıl oturum açılacağına ilişkin ayrıntıları içeren bir davetiye gönderildi.</key>
<key alias="userinviteWelcomeMessage">Merhabalar, Umbraco'ya hoş geldiniz! Sadece 1 dakika içinde hazır olacaksınız, sadece bir şifre belirlemeniz ve avatarınız için bir resim eklemeniz gerekiyor.</key>
<key alias="userinviteWelcomeMessage">Merhabalar, Umbraco'ya hoş geldiniz! Sadece 1 dakika içinde hazır olacaksınız, sadece bir şifre belirlemeniz.</key>
<key alias="userinviteExpiredMessage">Umbraco'ya hoş geldiniz! Maalesef davetinizin süresi doldu. Lütfen yöneticinizle iletişime geçin ve yeniden göndermesini isteyin.</key>
<key alias="userinviteAvatarMessage">Kendi fotoğrafınızı yüklemek, diğer kullanıcıların sizi tanımasını kolaylaştıracaktır. Fotoğrafınızı yüklemek için yukarıdaki daireyi tıklayın.</key>
<key alias="writer">Yazar</key>
<key alias="change">Değiştir</key>
<key alias="yourProfile" version="7.0">Profiliniz</key>
@@ -1996,8 +1995,8 @@ Web sitenizi yönetmek için, Umbraco'nun arka ofisini açın ve içerik eklemey
<key alias="stateInactive">Etkin Değil</key>
<key alias="sortNameAscending">Ad (AZ)</key>
<key alias="sortNameDescending">Ad (ZA)</key>
<key alias="sortCreateDateAscending">En yeni</key>
<key alias="sortCreateDateDescending">En eski</key>
<key alias="sortCreateDateAscending">En eski</key>
<key alias="sortCreateDateDescending">En yeni</key>
<key alias="sortLastLoginDateDescending">Son giriş</key>
<key alias="noUserGroupsAdded">Hiçbir kullanıcı grubu eklenmedi</key>
</area>
@@ -1703,8 +1703,7 @@
<key alias="usergroup">Група користувачів</key>
<key alias="userInvited"> був запрошений</key>
<key alias="userInvitedSuccessHelp">Новому користувачеві було надіслано запрошення, яке містить інструкції для входу в панель Umbraco.</key>
<key alias="userinviteWelcomeMessage">Привіт і ласкаво просимо до Umbraco! Все буде готове протягом декількох хвилин, нам потрібно задати пароль для входу і додати аватар.</key>
<key alias="userinviteAvatarMessage">Завантажте зображення, що допоможе іншим користувачам ідентифікувати Вас.</key>
<key alias="userinviteWelcomeMessage">Привіт і ласкаво просимо до Umbraco! Все буде готове протягом декількох хвилин, нам потрібно задати пароль для входу.</key>
<key alias="userManagement">Управління користувачами</key>
<key alias="userPermissions">Дозволи для користувача</key>
<key alias="writer">Автор</key>
@@ -137,7 +137,7 @@ internal class NotificationAsyncHandlerWrapperImpl<TNotification> : Notification
/// confusion.
/// </para>
/// </remarks>
public override Task HandleAsync(
public override async Task HandleAsync(
INotification notification,
CancellationToken cancellationToken,
ServiceFactory serviceFactory,
@@ -155,7 +155,7 @@ internal class NotificationAsyncHandlerWrapperImpl<TNotification> : Notification
(theNotification, theToken) =>
x.HandleAsync((TNotification)theNotification, theToken)));
return publish(handlers, notification, cancellationToken);
await publish(handlers, notification, cancellationToken);
}
}
+2 -2
View File
@@ -50,7 +50,7 @@ public partial class EventAggregator : IEventAggregator
=> _serviceFactory = serviceFactory;
/// <inheritdoc />
public Task PublishAsync<TNotification>(TNotification notification, CancellationToken cancellationToken = default)
public async Task PublishAsync<TNotification>(TNotification notification, CancellationToken cancellationToken = default)
where TNotification : INotification
{
// TODO: Introduce codegen efficient Guard classes to reduce noise.
@@ -60,7 +60,7 @@ public partial class EventAggregator : IEventAggregator
}
PublishNotification(notification);
return PublishNotificationAsync(notification, cancellationToken);
await PublishNotificationAsync(notification, cancellationToken);
}
/// <inheritdoc />
@@ -134,27 +134,6 @@ public static class PublishedElementExtensions
#endregion
#region CheckVariation
/// <summary>
/// Method to check if VariationContext culture differs from culture parameter, if so it will update the VariationContext for the PublishedValueFallback.
/// </summary>
/// <param name="publishedValueFallback">The requested PublishedValueFallback.</param>
/// <param name="culture">The requested culture.</param>
/// <param name="segment">The requested segment.</param>
/// <returns></returns>
private static void EventuallyUpdateVariationContext(IPublishedValueFallback publishedValueFallback, string? culture, string? segment)
{
IVariationContextAccessor? variationContextAccessor = publishedValueFallback.VariationContextAccessor;
//If there is a difference in requested culture and the culture that is set in the VariationContext, it will pick wrong localized content.
//This happens for example using links to localized content in a RichText Editor.
if (!string.IsNullOrEmpty(culture) && variationContextAccessor?.VariationContext?.Culture != culture)
{
variationContextAccessor!.VariationContext = new VariationContext(culture, segment);
}
}
#endregion
#region Value<T>
/// <summary>
@@ -195,8 +174,6 @@ public static class PublishedElementExtensions
{
IPublishedProperty? property = content.GetProperty(alias);
EventuallyUpdateVariationContext(publishedValueFallback, culture, segment);
// if we have a property, and it has a value, return that value
if (property != null && property.HasValue(culture, segment))
{
+79 -80
View File
@@ -219,96 +219,52 @@ public static class TypeExtensions
/// <returns></returns>
public static PropertyInfo[] GetAllProperties(this Type type)
{
if (type.IsInterface)
{
var propertyInfos = new List<PropertyInfo>();
var considered = new List<Type>();
var queue = new Queue<Type>();
considered.Add(type);
queue.Enqueue(type);
while (queue.Count > 0)
{
Type subType = queue.Dequeue();
foreach (Type subInterface in subType.GetInterfaces())
{
if (considered.Contains(subInterface))
{
continue;
}
considered.Add(subInterface);
queue.Enqueue(subInterface);
}
PropertyInfo[] typeProperties = subType.GetProperties(
BindingFlags.FlattenHierarchy
| BindingFlags.Public
| BindingFlags.NonPublic
| BindingFlags.Instance);
IEnumerable<PropertyInfo> newPropertyInfos = typeProperties
.Where(x => !propertyInfos.Contains(x));
propertyInfos.InsertRange(0, newPropertyInfos);
}
return propertyInfos.ToArray();
}
return type.GetProperties(BindingFlags.FlattenHierarchy
| BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
const BindingFlags bindingFlags = BindingFlags.FlattenHierarchy
| BindingFlags.Public
| BindingFlags.NonPublic
| BindingFlags.Instance;
return type.GetAllMemberInfos(t => t.GetProperties(bindingFlags));
}
/// <summary>
/// Returns all public properties including inherited properties even for interfaces
/// Returns public properties including inherited properties even for interfaces
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
/// <remarks>
/// taken from
/// http://stackoverflow.com/questions/358835/getproperties-to-return-all-properties-for-an-interface-inheritance-hierarchy
/// </remarks>
public static PropertyInfo[] GetPublicProperties(this Type type)
{
if (type.IsInterface)
{
var propertyInfos = new List<PropertyInfo>();
const BindingFlags bindingFlags = BindingFlags.FlattenHierarchy
| BindingFlags.Public
| BindingFlags.Instance;
return type.GetAllMemberInfos(t => t.GetProperties(bindingFlags));
}
var considered = new List<Type>();
var queue = new Queue<Type>();
considered.Add(type);
queue.Enqueue(type);
while (queue.Count > 0)
{
Type subType = queue.Dequeue();
foreach (Type subInterface in subType.GetInterfaces())
{
if (considered.Contains(subInterface))
{
continue;
}
/// <summary>
/// Returns public methods including inherited methods even for interfaces
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static MethodInfo[] GetPublicMethods(this Type type)
{
const BindingFlags bindingFlags = BindingFlags.FlattenHierarchy
| BindingFlags.Public
| BindingFlags.Instance;
return type.GetAllMemberInfos(t => t.GetMethods(bindingFlags));
}
considered.Add(subInterface);
queue.Enqueue(subInterface);
}
PropertyInfo[] typeProperties = subType.GetProperties(
BindingFlags.FlattenHierarchy
| BindingFlags.Public
| BindingFlags.Instance);
IEnumerable<PropertyInfo> newPropertyInfos = typeProperties
.Where(x => !propertyInfos.Contains(x));
propertyInfos.InsertRange(0, newPropertyInfos);
}
return propertyInfos.ToArray();
}
return type.GetProperties(BindingFlags.FlattenHierarchy
| BindingFlags.Public | BindingFlags.Instance);
/// <summary>
/// Returns all methods including inherited methods even for interfaces
/// </summary>
/// <remarks>Includes both Public and Non-Public methods</remarks>
/// <param name="type"></param>
/// <returns></returns>
public static MethodInfo[] GetAllMethods(this Type type)
{
const BindingFlags bindingFlags = BindingFlags.FlattenHierarchy
| BindingFlags.Public
| BindingFlags.NonPublic
| BindingFlags.Instance;
return type.GetAllMemberInfos(t => t.GetMethods(bindingFlags));
}
/// <summary>
@@ -512,4 +468,47 @@ public static class TypeExtensions
return attempt;
}
/// <remarks>
/// taken from
/// http://stackoverflow.com/questions/358835/getproperties-to-return-all-properties-for-an-interface-inheritance-hierarchy
/// </remarks>
private static T[] GetAllMemberInfos<T>(this Type type, Func<Type, T[]> getMemberInfos)
where T : MemberInfo
{
if (type.IsInterface is false)
{
return getMemberInfos(type);
}
var memberInfos = new List<T>();
var considered = new List<Type>();
var queue = new Queue<Type>();
considered.Add(type);
queue.Enqueue(type);
while (queue.Count > 0)
{
Type subType = queue.Dequeue();
foreach (Type subInterface in subType.GetInterfaces())
{
if (considered.Contains(subInterface))
{
continue;
}
considered.Add(subInterface);
queue.Enqueue(subInterface);
}
T[] typeMethodInfos = getMemberInfos(subType);
IEnumerable<T> newMethodInfos = typeMethodInfos
.Where(x => !memberInfos.Contains(x));
memberInfos.InsertRange(0, newMethodInfos);
}
return memberInfos.ToArray();
}
}
+1 -1
View File
@@ -358,7 +358,7 @@ namespace Umbraco.Cms.Core.IO
// nothing prevents us to reach the file, security-wise, yet it is outside
// this filesystem's root - throw
throw new UnauthorizedAccessException($"File original: [{originalPath}] full: [{path}] is outside this filesystem's root.");
throw new UnauthorizedAccessException($"Requested path {originalPath} is outside this filesystem's root.");
}
/// <summary>
+19 -19
View File
@@ -7,19 +7,21 @@ namespace Umbraco.Cms.Core.IO;
internal class ShadowWrapper : IFileSystem, IFileProviderFactory
{
private static readonly string ShadowFsPath = Constants.SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs";
private readonly IHostingEnvironment _hostingEnvironment;
private readonly IIOHelper _ioHelper;
private const string ShadowFsPath = "ShadowFs";
private readonly Func<bool?>? _isScoped;
private readonly IIOHelper _ioHelper;
private readonly IHostingEnvironment _hostingEnvironment;
private readonly ILoggerFactory _loggerFactory;
private readonly string _shadowPath;
private readonly Func<bool?>? _isScoped;
private string? _shadowDir;
private ShadowFileSystem? _shadowFileSystem;
public ShadowWrapper(IFileSystem innerFileSystem, IIOHelper ioHelper, IHostingEnvironment hostingEnvironment, ILoggerFactory loggerFactory, string shadowPath, Func<bool?>? isScoped = null)
{
InnerFileSystem = innerFileSystem;
_ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper));
_hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment));
_loggerFactory = loggerFactory;
@@ -35,18 +37,19 @@ internal class ShadowWrapper : IFileSystem, IFileProviderFactory
{
get
{
if (_isScoped is not null && _shadowFileSystem is not null)
Func<bool?>? isScoped = _isScoped;
if (isScoped is not null && _shadowFileSystem is not null)
{
var isScoped = _isScoped!();
bool? scoped = isScoped();
// if the filesystem is created *after* shadowing starts, it won't be shadowing
// better not ignore that situation and raised a meaningful (?) exception
if (isScoped.HasValue && isScoped.Value && _shadowFileSystem == null)
// better not ignore that situation and raise a meaningful (?) exception
if (scoped.HasValue && scoped.Value && _shadowFileSystem == null)
{
throw new Exception("The filesystems are shadowing, but this filesystem is not.");
}
return isScoped.HasValue && isScoped.Value
return scoped.HasValue && scoped.Value
? _shadowFileSystem
: InnerFileSystem;
}
@@ -56,8 +59,7 @@ internal class ShadowWrapper : IFileSystem, IFileProviderFactory
}
/// <inheritdoc />
public IFileProvider? Create() =>
InnerFileSystem.TryCreateFileProvider(out IFileProvider? fileProvider) ? fileProvider : null;
public IFileProvider? Create() => InnerFileSystem.TryCreateFileProvider(out IFileProvider? fileProvider) ? fileProvider : null;
public IEnumerable<string> GetDirectories(string path) => FileSystem.GetDirectories(path);
@@ -69,8 +71,7 @@ internal class ShadowWrapper : IFileSystem, IFileProviderFactory
public void AddFile(string path, Stream stream) => FileSystem.AddFile(path, stream);
public void AddFile(string path, Stream stream, bool overrideExisting) =>
FileSystem.AddFile(path, stream, overrideExisting);
public void AddFile(string path, Stream stream, bool overrideExisting) => FileSystem.AddFile(path, stream, overrideExisting);
public IEnumerable<string> GetFiles(string path) => FileSystem.GetFiles(path);
@@ -107,8 +108,7 @@ internal class ShadowWrapper : IFileSystem, IFileProviderFactory
{
var id = GuidUtils.ToBase32String(Guid.NewGuid(), idLength);
var virt = ShadowFsPath + "/" + id;
var shadowDir = hostingEnvironment.MapPathContentRoot(virt);
var shadowDir = Path.Combine(hostingEnvironment.LocalTempPath, ShadowFsPath, id);
if (Directory.Exists(shadowDir))
{
continue;
@@ -129,10 +129,10 @@ internal class ShadowWrapper : IFileSystem, IFileProviderFactory
// note: no thread-safety here, because ShadowFs is thread-safe due to the check
// on ShadowFileSystemsScope.None - and if None is false then we should be running
// in a single thread anyways
var virt = Path.Combine(ShadowFsPath, id, _shadowPath);
_shadowDir = _hostingEnvironment.MapPathContentRoot(virt);
var rootUrl = Path.Combine(ShadowFsPath, id, _shadowPath);
_shadowDir = Path.Combine(_hostingEnvironment.LocalTempPath, rootUrl);
Directory.CreateDirectory(_shadowDir);
var tempfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _loggerFactory.CreateLogger<PhysicalFileSystem>(), _shadowDir, _hostingEnvironment.ToAbsolute(virt));
var tempfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _loggerFactory.CreateLogger<PhysicalFileSystem>(), _shadowDir, rootUrl);
_shadowFileSystem = new ShadowFileSystem(InnerFileSystem, tempfs);
}
@@ -160,7 +160,7 @@ internal class ShadowWrapper : IFileSystem, IFileProviderFactory
// shadowPath make be path/to/dir, remove each
dir = dir!.Replace('/', Path.DirectorySeparatorChar);
var min = _hostingEnvironment.MapPathContentRoot(ShadowFsPath).Length;
var min = Path.Combine(_hostingEnvironment.LocalTempPath, ShadowFsPath).Length;
var pos = dir.LastIndexOf(Path.DirectorySeparatorChar);
while (pos > min)
{
@@ -19,6 +19,9 @@ public class Issuu : EmbedProviderBase
public override Dictionary<string, string> RequestParams => new()
{
// ApiUrl/?iframe=true
{ "iframe", "true" },
// ApiUrl/?format=xml
{ "format", "xml" },
};
@@ -55,11 +55,12 @@ public abstract class OEmbedProviderBase : IEmbedProvider
if (_httpClient == null)
{
_httpClient = new HttpClient();
_httpClient.DefaultRequestHeaders.UserAgent.TryParseAdd("Umbraco-CMS");
}
using (var request = new HttpRequestMessage(HttpMethod.Get, url))
{
HttpResponseMessage response = _httpClient.SendAsync(request).Result;
HttpResponseMessage response = _httpClient.SendAsync(request).GetAwaiter().GetResult();
return response.Content.ReadAsStringAsync().Result;
}
}
@@ -1,49 +1,88 @@
namespace Umbraco.Cms.Core.Models.Editors;
/// <summary>
/// Used to track reference to other entities in a property value
/// Used to track a reference to another entity in a property value.
/// </summary>
public struct UmbracoEntityReference : IEquatable<UmbracoEntityReference>
{
private static readonly UmbracoEntityReference _empty = new(UnknownTypeUdi.Instance, string.Empty);
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoEntityReference" /> struct.
/// </summary>
/// <param name="udi">The UDI.</param>
/// <param name="relationTypeAlias">The relation type alias.</param>
public UmbracoEntityReference(Udi udi, string relationTypeAlias)
{
Udi = udi ?? throw new ArgumentNullException(nameof(udi));
RelationTypeAlias = relationTypeAlias ?? throw new ArgumentNullException(nameof(relationTypeAlias));
}
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoEntityReference" /> struct for a document or media item.
/// </summary>
/// <param name="udi">The UDI.</param>
public UmbracoEntityReference(Udi udi)
{
Udi = udi ?? throw new ArgumentNullException(nameof(udi));
switch (udi.EntityType)
{
case Constants.UdiEntityType.Document:
RelationTypeAlias = Constants.Conventions.RelationTypes.RelatedDocumentAlias;
break;
case Constants.UdiEntityType.Media:
RelationTypeAlias = Constants.Conventions.RelationTypes.RelatedMediaAlias;
break;
default:
RelationTypeAlias = Constants.Conventions.RelationTypes.RelatedDocumentAlias;
// No relation type alias convention for this entity type, so leave it empty
RelationTypeAlias = string.Empty;
break;
}
}
/// <summary>
/// Gets the UDI.
/// </summary>
/// <value>
/// The UDI.
/// </value>
public Udi Udi { get; }
public static UmbracoEntityReference Empty() => _empty;
public static bool IsEmpty(UmbracoEntityReference reference) => reference == Empty();
/// <summary>
/// Gets the relation type alias.
/// </summary>
/// <value>
/// The relation type alias.
/// </value>
public string RelationTypeAlias { get; }
public static bool operator ==(UmbracoEntityReference left, UmbracoEntityReference right) => left.Equals(right);
/// <summary>
/// Gets an empty reference.
/// </summary>
/// <returns>
/// An empty reference.
/// </returns>
public static UmbracoEntityReference Empty() => _empty;
/// <summary>
/// Determines whether the specified reference is empty.
/// </summary>
/// <param name="reference">The reference.</param>
/// <returns>
/// <c>true</c> if the specified reference is empty; otherwise, <c>false</c>.
/// </returns>
public static bool IsEmpty(UmbracoEntityReference reference) => reference == Empty();
/// <inheritdoc />
public override bool Equals(object? obj) => obj is UmbracoEntityReference reference && Equals(reference);
/// <inheritdoc />
public bool Equals(UmbracoEntityReference other) =>
EqualityComparer<Udi>.Default.Equals(Udi, other.Udi) &&
RelationTypeAlias == other.RelationTypeAlias;
/// <inheritdoc />
public override int GetHashCode()
{
var hashCode = -487348478;
@@ -52,5 +91,9 @@ public struct UmbracoEntityReference : IEquatable<UmbracoEntityReference>
return hashCode;
}
/// <inheritdoc />
public static bool operator ==(UmbracoEntityReference left, UmbracoEntityReference right) => left.Equals(right);
/// <inheritdoc />
public static bool operator !=(UmbracoEntityReference left, UmbracoEntityReference right) => !(left == right);
}
@@ -5,6 +5,7 @@ namespace Umbraco.Cms.Core.Models.PublishedContent;
/// </summary>
public interface IPublishedValueFallback
{
[Obsolete("Scheduled for removal in v14")]
/// <summary>
/// VariationContextAccessor that is not required to be implemented, therefore throws NotImplementedException as default.
/// </summary>
@@ -7,7 +7,15 @@ namespace Umbraco.Cms.Core.Models.PublishedContent;
/// <para>This is for tests etc - does not implement fallback at all.</para>
/// </remarks>
public class NoopPublishedValueFallback : IPublishedValueFallback
{
/// <inheritdoc />
public IVariationContextAccessor VariationContextAccessor
{
get => new ThreadCultureVariationContextAccessor();
set { }
}
/// <inheritdoc />
public bool TryGetValue(IPublishedProperty property, string? culture, string? segment, Fallback fallback, object? defaultValue, out object? value)
{
@@ -20,6 +20,7 @@ public class PublishedValueFallback : IPublishedValueFallback
_variationContextAccessor = variationContextAccessor;
}
[Obsolete("Scheduled for removal in v14")]
public IVariationContextAccessor VariationContextAccessor { get { return _variationContextAccessor; } }
/// <inheritdoc />
@@ -0,0 +1,18 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Models;
namespace Umbraco.Cms.Core.Notifications;
/// <summary>
/// Notification that is send out when a Content item has been scaffolded from an original item and basic cleaning has been performed
/// </summary>
public sealed class ContentScaffoldedNotification : ScaffoldedNotification<IContent>
{
public ContentScaffoldedNotification(IContent original, IContent scaffold, int parentId, EventMessages messages)
: base(original, scaffold, parentId, messages)
{
}
}
@@ -0,0 +1,23 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.
using Umbraco.Cms.Core.Events;
namespace Umbraco.Cms.Core.Notifications;
public abstract class ScaffoldedNotification<T> : CancelableObjectNotification<T>
where T : class
{
protected ScaffoldedNotification(T original, T scaffold, int parentId, EventMessages messages)
: base(original, messages)
{
Scaffold = scaffold;
ParentId = parentId;
}
public T Original => Target;
public T Scaffold { get; }
public int ParentId { get; }
}
@@ -4,64 +4,156 @@ using Umbraco.Cms.Core.Models.Editors;
namespace Umbraco.Cms.Core.PropertyEditors;
/// <summary>
/// Provides a builder collection for <see cref="IDataValueReferenceFactory" /> items.
/// </summary>
public class DataValueReferenceFactoryCollection : BuilderCollectionBase<IDataValueReferenceFactory>
{
public DataValueReferenceFactoryCollection(Func<IEnumerable<IDataValueReferenceFactory>> items)
: base(items)
{
}
// TODO: We could further reduce circular dependencies with PropertyEditorCollection by not having IDataValueReference implemented
// by property editors and instead just use the already built in IDataValueReferenceFactory and/or refactor that into a more normal collection
public IEnumerable<UmbracoEntityReference> GetAllReferences(
IPropertyCollection properties,
PropertyEditorCollection propertyEditors)
{
var trackedRelations = new HashSet<UmbracoEntityReference>();
foreach (IProperty p in properties)
/// <summary>
/// Initializes a new instance of the <see cref="DataValueReferenceFactoryCollection" /> class.
/// </summary>
/// <param name="items">The items.</param>
public DataValueReferenceFactoryCollection(Func<IEnumerable<IDataValueReferenceFactory>> items)
: base(items)
{ }
/// <summary>
/// Gets all unique references from the specified properties.
/// </summary>
/// <param name="properties">The properties.</param>
/// <param name="propertyEditors">The property editors.</param>
/// <returns>
/// The unique references from the specified properties.
/// </returns>
public ISet<UmbracoEntityReference> GetAllReferences(IPropertyCollection properties, PropertyEditorCollection propertyEditors)
{
var references = new HashSet<UmbracoEntityReference>();
// Group by property editor alias to avoid duplicate lookups and optimize value parsing
foreach (var propertyValuesByPropertyEditorAlias in properties.GroupBy(x => x.PropertyType.PropertyEditorAlias, x => x.Values))
{
if (!propertyEditors.TryGet(p.PropertyType.PropertyEditorAlias, out IDataEditor? editor))
if (!propertyEditors.TryGet(propertyValuesByPropertyEditorAlias.Key, out IDataEditor? dataEditor))
{
continue;
}
// TODO: We will need to change this once we support tracking via variants/segments
// for now, we are tracking values from ALL variants
foreach (IPropertyValue propertyVal in p.Values)
// Use distinct values to avoid duplicate parsing of the same value
var values = new HashSet<object?>(properties.Count);
foreach (IPropertyValue propertyValue in propertyValuesByPropertyEditorAlias.SelectMany(x => x))
{
var val = propertyVal.EditedValue;
values.Add(propertyValue.EditedValue);
values.Add(propertyValue.PublishedValue);
}
IDataValueEditor? valueEditor = editor?.GetValueEditor();
if (valueEditor is IDataValueReference reference)
{
IEnumerable<UmbracoEntityReference> refs = reference.GetReferences(val);
foreach (UmbracoEntityReference r in refs)
{
trackedRelations.Add(r);
}
}
references.UnionWith(GetReferences(dataEditor, values));
}
// Loop over collection that may be add to existing property editors
// implementation of GetReferences in IDataValueReference.
// Allows developers to add support for references by a
// package /property editor that did not implement IDataValueReference themselves
foreach (IDataValueReferenceFactory item in this)
{
// Check if this value reference is for this datatype/editor
// Then call it's GetReferences method - to see if the value stored
// in the dataeditor/property has referecnes to media/content items
if (item.IsForEditor(editor))
{
foreach (UmbracoEntityReference r in item.GetDataValueReference().GetReferences(val))
{
trackedRelations.Add(r);
}
}
}
return references;
}
/// <summary>
/// Gets the references.
/// </summary>
/// <param name="dataEditor">The data editor.</param>
/// <param name="values">The values.</param>
/// <returns>
/// The references.
/// </returns>
public IEnumerable<UmbracoEntityReference> GetReferences(IDataEditor dataEditor, params object?[] values)
=> GetReferences(dataEditor, (IEnumerable<object?>)values);
/// <summary>
/// Gets the references.
/// </summary>
/// <param name="dataEditor">The data editor.</param>
/// <param name="values">The values.</param>
/// <returns>
/// The references.
/// </returns>
public IEnumerable<UmbracoEntityReference> GetReferences(IDataEditor dataEditor, IEnumerable<object?> values)
{
// TODO: We will need to change this once we support tracking via variants/segments
// for now, we are tracking values from ALL variants
if (dataEditor.GetValueEditor() is IDataValueReference dataValueReference)
{
foreach (UmbracoEntityReference reference in values.SelectMany(dataValueReference.GetReferences))
{
yield return reference;
}
}
return trackedRelations;
// Loop over collection that may be add to existing property editors
// implementation of GetReferences in IDataValueReference.
// Allows developers to add support for references by a
// package /property editor that did not implement IDataValueReference themselves
foreach (IDataValueReferenceFactory dataValueReferenceFactory in this)
{
// Check if this value reference is for this datatype/editor
// Then call it's GetReferences method - to see if the value stored
// in the dataeditor/property has references to media/content items
if (dataValueReferenceFactory.IsForEditor(dataEditor))
{
IDataValueReference factoryDataValueReference = dataValueReferenceFactory.GetDataValueReference();
foreach (UmbracoEntityReference reference in values.SelectMany(factoryDataValueReference.GetReferences))
{
yield return reference;
}
}
}
}
/// <summary>
/// Gets all relation type aliases that are automatically tracked.
/// </summary>
/// <param name="propertyEditors">The property editors.</param>
/// <returns>
/// All relation type aliases that are automatically tracked.
/// </returns>
public ISet<string> GetAllAutomaticRelationTypesAliases(PropertyEditorCollection propertyEditors)
{
// Always add default automatic relation types
var automaticRelationTypeAliases = new HashSet<string>(Constants.Conventions.RelationTypes.AutomaticRelationTypes);
// Add relation types for all property editors
foreach (IDataEditor dataEditor in propertyEditors)
{
automaticRelationTypeAliases.UnionWith(GetAutomaticRelationTypesAliases(dataEditor));
}
return automaticRelationTypeAliases;
}
/// <summary>
/// Gets the automatic relation types aliases.
/// </summary>
/// <param name="dataEditor">The data editor.</param>
/// <returns>
/// The automatic relation types aliases.
/// </returns>
public IEnumerable<string> GetAutomaticRelationTypesAliases(IDataEditor dataEditor)
{
if (dataEditor.GetValueEditor() is IDataValueReference dataValueReference)
{
// Return custom relation types from value editor implementation
foreach (var alias in dataValueReference.GetAutomaticRelationTypesAliases())
{
yield return alias;
}
}
foreach (IDataValueReferenceFactory dataValueReferenceFactory in this)
{
if (dataValueReferenceFactory.IsForEditor(dataEditor))
{
// Return custom relation types from factory
foreach (var alias in dataValueReferenceFactory.GetDataValueReference().GetAutomaticRelationTypesAliases())
{
yield return alias;
}
}
}
}
}
@@ -9,11 +9,22 @@ namespace Umbraco.Cms.Core.PropertyEditors;
/// </summary>
public class DefaultPropertyIndexValueFactory : IPropertyIndexValueFactory
{
/// <inheritdoc />
public IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture, string? segment, bool published)
public IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture, string? segment, bool published,
IEnumerable<string> availableCultures, IDictionary<Guid, IContentType> contentTypeDictionary)
{
yield return new KeyValuePair<string, IEnumerable<object?>>(
property.Alias,
property.GetValue(culture, segment, published).Yield());
}
/// <inheritdoc />
[Obsolete("Use the non-obsolete overload, scheduled for removal in v14")]
public IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture,
string? segment, bool published, IEnumerable<string> availableCultures)
=> GetIndexValues(property, culture, segment, published, availableCultures,
new Dictionary<Guid, IContentType>());
[Obsolete("Use the non-obsolete overload, scheduled for removal in v14")]
public IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture, string? segment, bool published)
=> GetIndexValues(property, culture, segment, published, Enumerable.Empty<string>(), new Dictionary<Guid, IContentType>());
}
@@ -16,11 +16,10 @@ public class DefaultPropertyValueConverterAttribute : Attribute
/// a DefaultPropertyValueConverter can be more specific than another one.
/// </summary>
/// <remarks>
/// An example where this is useful is that both the RelatedLiksEditorValueConverter and the JsonValueConverter
/// An example where this is useful is that both the MultiUrlPickerValueConverter and the JsonValueConverter
/// will be returned as value converters for the Related Links Property editor, however the JsonValueConverter
/// is a very generic converter and the RelatedLiksEditorValueConverter is more specific than it, so the
/// RelatedLiksEditorValueConverter
/// can specify that it 'shadows' the JsonValueConverter.
/// is a very generic converter and the MultiUrlPickerValueConverter is more specific than it, so the
/// MultiUrlPickerValueConverter can specify that it 'shadows' the JsonValueConverter.
/// </remarks>
public Type[] DefaultConvertersToShadow { get; }
}
@@ -22,5 +22,14 @@ public interface IPropertyIndexValueFactory
/// more than one value for a given field.
/// </para>
/// </remarks>
IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture,
string? segment, bool published, IEnumerable<string> availableCultures,
IDictionary<Guid, IContentType> contentTypeDictionary) => GetIndexValues(property, culture, segment, published);
[Obsolete("Use non-obsolete overload, scheduled for removal in v14")]
IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture, string? segment, bool published, IEnumerable<string> availableCultures)
=> GetIndexValues(property, culture, segment, published);
[Obsolete("Use non-obsolete overload, scheduled for removal in v14")]
IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture, string? segment, bool published);
}
@@ -1,5 +1,10 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Web.Common.DependencyInjection;
using Umbraco.Extensions;
namespace Umbraco.Cms.Core.PropertyEditors;
@@ -11,21 +16,37 @@ namespace Umbraco.Cms.Core.PropertyEditors;
public abstract class JsonPropertyIndexValueFactoryBase<TSerialized> : IPropertyIndexValueFactory
{
private readonly IJsonSerializer _jsonSerializer;
private IndexingSettings _indexingSettings;
protected bool ForceExplicitlyIndexEachNestedProperty { get; set; }
/// <summary>
/// Constructor for the JsonPropertyIndexValueFactoryBase.
/// </summary>
protected JsonPropertyIndexValueFactoryBase(IJsonSerializer jsonSerializer)
protected JsonPropertyIndexValueFactoryBase(IJsonSerializer jsonSerializer, IOptionsMonitor<IndexingSettings> indexingSettings)
{
_jsonSerializer = jsonSerializer;
_indexingSettings = indexingSettings.CurrentValue;
indexingSettings.OnChange(newValue => _indexingSettings = newValue);
}
/// <summary>
/// Constructor for the JsonPropertyIndexValueFactoryBase.
/// </summary>
[Obsolete("Use non-obsolete constructor. This will be removed in Umbraco 14.")]
protected JsonPropertyIndexValueFactoryBase(IJsonSerializer jsonSerializer): this(jsonSerializer, StaticServiceProvider.Instance.GetRequiredService<IOptionsMonitor<IndexingSettings>>())
{
}
/// <inheritdoc />
public IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(
IProperty property,
string? culture,
string? segment,
bool published)
bool published,
IEnumerable<string> availableCultures,
IDictionary<Guid, IContentType> contentTypeDictionary)
{
var result = new List<KeyValuePair<string, IEnumerable<object?>>>();
@@ -43,7 +64,7 @@ public abstract class JsonPropertyIndexValueFactoryBase<TSerialized> : IProperty
return result;
}
result.AddRange(Handle(deserializedPropertyValue, property, culture, segment, published));
result.AddRange(Handle(deserializedPropertyValue, property, culture, segment, published, availableCultures, contentTypeDictionary));
}
catch (InvalidCastException)
{
@@ -57,13 +78,44 @@ public abstract class JsonPropertyIndexValueFactoryBase<TSerialized> : IProperty
}
}
result.AddRange(HandleResume(result, property, culture, segment, published));
IEnumerable<KeyValuePair<string, IEnumerable<object?>>> summary = HandleResume(result, property, culture, segment, published);
if (_indexingSettings.ExplicitlyIndexEachNestedProperty || ForceExplicitlyIndexEachNestedProperty)
{
result.AddRange(summary);
return result;
}
return result;
return summary;
}
/// <inheritdoc />
[Obsolete("Use non-obsolete constructor. This will be removed in Umbraco 14.")]
public IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(
IProperty property,
string? culture,
string? segment,
bool published,
IEnumerable<string> availableCultures)
=> GetIndexValues(
property,
culture,
segment,
published,
Enumerable.Empty<string>(),
StaticServiceProvider.Instance.GetRequiredService<IContentTypeService>().GetAll().ToDictionary(x=>x.Key));
[Obsolete("Use method overload that has availableCultures, scheduled for removal in v14")]
public IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture, string? segment, bool published)
=> GetIndexValues(
property,
culture,
segment,
published,
Enumerable.Empty<string>(),
StaticServiceProvider.Instance.GetRequiredService<IContentTypeService>().GetAll().ToDictionary(x=>x.Key));
/// <summary>
/// Method to return a list of resume of the content. By default this returns an empty list
/// Method to return a list of summary of the content. By default this returns an empty list
/// </summary>
protected virtual IEnumerable<KeyValuePair<string, IEnumerable<object?>>> HandleResume(
List<KeyValuePair<string, IEnumerable<object?>>> result,
@@ -75,10 +127,33 @@ public abstract class JsonPropertyIndexValueFactoryBase<TSerialized> : IProperty
/// <summary>
/// Method that handle the deserialized object.
/// </summary>
[Obsolete("Use the non-obsolete overload instead, scheduled for removal in v14")]
protected abstract IEnumerable<KeyValuePair<string, IEnumerable<object?>>> Handle(
TSerialized deserializedPropertyValue,
IProperty property,
string? culture,
string? segment,
bool published);
[Obsolete("Use the non-obsolete overload instead, scheduled for removal in v14")]
protected virtual IEnumerable<KeyValuePair<string, IEnumerable<object?>>> Handle(
TSerialized deserializedPropertyValue,
IProperty property,
string? culture,
string? segment,
bool published,
IEnumerable<string> availableCultures) => Handle(deserializedPropertyValue, property, culture, segment, published);
/// <summary>
/// Method that handle the deserialized object.
/// </summary>
protected virtual IEnumerable<KeyValuePair<string, IEnumerable<object?>>> Handle(
TSerialized deserializedPropertyValue,
IProperty property,
string? culture,
string? segment,
bool published,
IEnumerable<string> availableCultures,
IDictionary<Guid, IContentType> contentTypeDictionary)
=> Handle(deserializedPropertyValue, property, culture, segment, published, availableCultures);
}
@@ -0,0 +1,39 @@
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models.Editors;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Strings;
using Umbraco.Extensions;
namespace Umbraco.Cms.Core.PropertyEditors;
/// <summary>
/// A custom value editor to ensure that macro syntax is parsed when being persisted and formatted correctly for
/// display in the editor
/// </summary>
internal class MarkDownPropertyValueEditor : DataValueEditor
{
private readonly IMarkdownSanitizer _markdownSanitizer;
public MarkDownPropertyValueEditor(
ILocalizedTextService localizedTextService,
IShortStringHelper shortStringHelper,
IJsonSerializer jsonSerializer,
IIOHelper ioHelper,
DataEditorAttribute attribute,
IMarkdownSanitizer markdownSanitizer)
: base(localizedTextService, shortStringHelper, jsonSerializer, ioHelper, attribute) => _markdownSanitizer = markdownSanitizer;
public override object? FromEditor(ContentPropertyData editorValue, object? currentValue)
{
if (string.IsNullOrWhiteSpace(editorValue.Value?.ToString()))
{
return null;
}
var sanitized = _markdownSanitizer.Sanitize(editorValue.Value.ToString()!);
return sanitized.NullOrWhiteSpaceAsNull();
}
}
@@ -3,6 +3,7 @@
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Web.Common.DependencyInjection;
@@ -50,4 +51,11 @@ public class MarkdownPropertyEditor : DataEditor
/// <inheritdoc />
protected override IConfigurationEditor CreateConfigurationEditor() =>
new MarkdownConfigurationEditor(_ioHelper, _editorConfigurationParser);
/// <summary>
/// Create a custom value editor
/// </summary>
/// <returns></returns>
protected override IDataValueEditor CreateValueEditor() =>
DataValueEditorFactory.Create<MarkDownPropertyValueEditor>(Attribute!);
}
@@ -8,5 +8,15 @@ namespace Umbraco.Cms.Core.PropertyEditors;
public class NoopPropertyIndexValueFactory : IPropertyIndexValueFactory
{
/// <inheritdoc />
public IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture, string? segment, bool published) => Array.Empty<KeyValuePair<string, IEnumerable<object?>>>();
public IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture, string? segment, bool published,
IEnumerable<string> availableCultures, IDictionary<Guid, IContentType> contentTypeDictionary)
=> Array.Empty<KeyValuePair<string, IEnumerable<object?>>>();
[Obsolete("Use the overload with the availableCultures parameter instead, scheduled for removal in v14")]
public IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture, string? segment, bool published, IEnumerable<string> availableCultures) => Array.Empty<KeyValuePair<string, IEnumerable<object?>>>();
[Obsolete("Use the overload with the availableCultures parameter instead, scheduled for removal in v14")]
public IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture, string? segment, bool published)
=> GetIndexValues(property, culture, segment, published);
}
@@ -14,12 +14,12 @@ public class SliderConfiguration
[ConfigurationField("initVal2", "Initial value 2", "number", Description = "Used when range is enabled")]
public decimal InitialValue2 { get; set; }
[ConfigurationField("minVal", "Minimum value", "number")]
[ConfigurationField("minVal", "Minimum value", "number", Description = "Must be smaller than the Maximum value")]
public decimal MinimumValue { get; set; }
[ConfigurationField("maxVal", "Maximum value", "number")]
[ConfigurationField("maxVal", "Maximum value", "number", Description = "Must be larger than the Minimum value")]
public decimal MaximumValue { get; set; }
[ConfigurationField("step", "Step increments", "number")]
[ConfigurationField("step", "Step increments", "number", Description = "Must be a positive value")]
public decimal StepIncrements { get; set; }
}
@@ -25,4 +25,19 @@ public class SliderConfigurationEditor : ConfigurationEditor<SliderConfiguration
ioHelper, editorConfigurationParser)
{
}
public override Dictionary<string, object> ToConfigurationEditor(SliderConfiguration? configuration)
{
// negative step increments can be configured in the back-office. they will cause the slider to
// crash the entire back-office. as we can't configure min and max values for the number prevalue
// editor, we have to this instead to limit the damage.
// logically, the step increments should be inverted instead of hardcoding them to 1, but the
// latter might point people in the direction of their misconfiguration.
if (configuration?.StepIncrements <= 0)
{
configuration.StepIncrements = 1;
}
return base.ToConfigurationEditor(configuration);
}
}
@@ -1,14 +1,41 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Web.Common.DependencyInjection;
namespace Umbraco.Cms.Core.PropertyEditors;
public class TagPropertyIndexValueFactory : JsonPropertyIndexValueFactoryBase<string[]>, ITagPropertyIndexValueFactory
{
public TagPropertyIndexValueFactory(IJsonSerializer jsonSerializer) : base(jsonSerializer)
public TagPropertyIndexValueFactory(
IJsonSerializer jsonSerializer,
IOptionsMonitor<IndexingSettings> indexingSettings)
: base(jsonSerializer, indexingSettings)
{
ForceExplicitlyIndexEachNestedProperty = true;
}
[Obsolete("Use non-obsolete constructor. This will be removed in Umbraco 14.")]
public TagPropertyIndexValueFactory(IJsonSerializer jsonSerializer)
: this(jsonSerializer, StaticServiceProvider.Instance.GetRequiredService<IOptionsMonitor<IndexingSettings>>())
{
}
protected override IEnumerable<KeyValuePair<string, IEnumerable<object?>>> Handle(
string[] deserializedPropertyValue,
IProperty property,
string? culture,
string? segment,
bool published,
IEnumerable<string> availableCultures)
{
yield return new KeyValuePair<string, IEnumerable<object?>>(property.Alias, deserializedPropertyValue);
}
[Obsolete("Use the overload that specifies availableCultures, scheduled for removal in v14")]
protected override IEnumerable<KeyValuePair<string, IEnumerable<object?>>> Handle(
string[] deserializedPropertyValue,
IProperty property,
@@ -1,4 +1,4 @@
using System.Collections.Concurrent;
using System.Globalization;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Services;
@@ -6,74 +6,123 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters;
/// <summary>
/// The slider property value converter.
/// </summary>
/// <seealso cref="Umbraco.Cms.Core.PropertyEditors.PropertyValueConverterBase" />
[DefaultPropertyValueConverter]
public class SliderValueConverter : PropertyValueConverterBase
{
private static readonly ConcurrentDictionary<int, bool> Storages = new();
private readonly IDataTypeService _dataTypeService;
/// <summary>
/// Initializes a new instance of the <see cref="SliderValueConverter" /> class.
/// </summary>
public SliderValueConverter()
{ }
public SliderValueConverter(IDataTypeService dataTypeService) => _dataTypeService =
dataTypeService ?? throw new ArgumentNullException(nameof(dataTypeService));
/// <summary>
/// Initializes a new instance of the <see cref="SliderValueConverter" /> class.
/// </summary>
/// <param name="dataTypeService">The data type service.</param>
[Obsolete("The IDataTypeService is not used anymore. This constructor will be removed in a future version.")]
public SliderValueConverter(IDataTypeService dataTypeService)
{ }
public static void ClearCaches() => Storages.Clear();
/// <summary>
/// Clears the data type configuration caches.
/// </summary>
[Obsolete("Caching of data type configuration is not done anymore. This method will be removed in a future version.")]
public static void ClearCaches()
{ }
/// <inheritdoc />
public override bool IsConverter(IPublishedPropertyType propertyType)
=> propertyType.EditorAlias.InvariantEquals(Constants.PropertyEditors.Aliases.Slider);
/// <inheritdoc />
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
=> IsRangeDataType(propertyType.DataType.Id) ? typeof(Range<decimal>) : typeof(decimal);
=> IsRange(propertyType) ? typeof(Range<decimal>) : typeof(decimal);
/// <inheritdoc />
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
=> PropertyCacheLevel.Element;
/// <inheritdoc />
public override object? ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object? source, bool preview)
{
if (source == null)
bool isRange = IsRange(propertyType);
var sourceString = source?.ToString();
return isRange
? HandleRange(sourceString)
: HandleDecimal(sourceString);
}
private static Range<decimal> HandleRange(string? sourceString)
{
if (sourceString is null)
{
return null;
return new Range<decimal>();
}
if (IsRangeDataType(propertyType.DataType.Id))
{
var rangeRawValues = source.ToString()!.Split(Constants.CharArrays.Comma);
Attempt<decimal> minimumAttempt = rangeRawValues[0].TryConvertTo<decimal>();
Attempt<decimal> maximumAttempt = rangeRawValues[1].TryConvertTo<decimal>();
string[] rangeRawValues = sourceString.Split(Constants.CharArrays.Comma);
if (minimumAttempt.Success && maximumAttempt.Success)
if (TryParseDecimal(rangeRawValues[0], out var minimum))
{
if (rangeRawValues.Length == 1)
{
return new Range<decimal> { Maximum = maximumAttempt.Result, Minimum = minimumAttempt.Result };
// Configuration is probably changed from single to range, return range with same min/max
return new Range<decimal>
{
Minimum = minimum,
Maximum = minimum
};
}
if (rangeRawValues.Length == 2 && TryParseDecimal(rangeRawValues[1], out var maximum))
{
return new Range<decimal>
{
Minimum = minimum,
Maximum = maximum
};
}
}
Attempt<decimal> valueAttempt = source.ToString().TryConvertTo<decimal>();
if (valueAttempt.Success)
return new Range<decimal>();
}
private static decimal HandleDecimal(string? sourceString)
{
if (string.IsNullOrEmpty(sourceString))
{
return valueAttempt.Result;
return default;
}
// Something failed in the conversion of the strings to decimals
return null;
// This used to be a range slider, so we'll assign the minimum value as the new value
if (sourceString.Contains(','))
{
var minimumValueRepresentation = sourceString.Split(Constants.CharArrays.Comma)[0];
if (TryParseDecimal(minimumValueRepresentation, out var minimum))
{
return minimum;
}
}
else if (TryParseDecimal(sourceString, out var value))
{
return value;
}
return default;
}
/// <summary>
/// Discovers if the slider is set to range mode.
/// Helper method for parsing a double consistently
/// </summary>
/// <param name="dataTypeId">
/// The data type id.
/// </param>
/// <returns>
/// The <see cref="bool" />.
/// </returns>
private bool IsRangeDataType(int dataTypeId) =>
private static bool TryParseDecimal(string? representation, out decimal value)
=> decimal.TryParse(representation, NumberStyles.Number, CultureInfo.InvariantCulture, out value);
// GetPreValuesCollectionByDataTypeId is cached at repository level;
// still, the collection is deep-cloned so this is kinda expensive,
// better to cache here + trigger refresh in DataTypeCacheRefresher
// TODO: this is cheap now, remove the caching
Storages.GetOrAdd(dataTypeId, id =>
{
IDataType? dataType = _dataTypeService.GetDataType(id);
SliderConfiguration? configuration = dataType?.ConfigurationAs<SliderConfiguration>();
return configuration?.EnableRange ?? false;
});
private static bool IsRange(IPublishedPropertyType propertyType)
=> propertyType.DataType.ConfigurationAs<SliderConfiguration>()?.EnableRange == true;
}
@@ -1,4 +1,3 @@
using System.Collections.Concurrent;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Serialization;
@@ -7,69 +6,66 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters;
/// <summary>
/// The tags property value converter.
/// </summary>
/// <seealso cref="Umbraco.Cms.Core.PropertyEditors.PropertyValueConverterBase" />
[DefaultPropertyValueConverter]
public class TagsValueConverter : PropertyValueConverterBase
{
private static readonly ConcurrentDictionary<int, bool> Storages = new();
private readonly IDataTypeService _dataTypeService;
private readonly IJsonSerializer _jsonSerializer;
/// <summary>
/// Initializes a new instance of the <see cref="TagsValueConverter" /> class.
/// </summary>
/// <param name="jsonSerializer">The JSON serializer.</param>
/// <exception cref="System.ArgumentNullException">jsonSerializer</exception>
public TagsValueConverter(IJsonSerializer jsonSerializer)
=> _jsonSerializer = jsonSerializer ?? throw new ArgumentNullException(nameof(jsonSerializer));
/// <summary>
/// Initializes a new instance of the <see cref="TagsValueConverter" /> class.
/// </summary>
/// <param name="dataTypeService">The data type service.</param>
/// <param name="jsonSerializer">The JSON serializer.</param>
[Obsolete("The IDataTypeService is not used anymore. This constructor will be removed in a future version.")]
public TagsValueConverter(IDataTypeService dataTypeService, IJsonSerializer jsonSerializer)
{
_dataTypeService = dataTypeService ?? throw new ArgumentNullException(nameof(dataTypeService));
_jsonSerializer = jsonSerializer ?? throw new ArgumentNullException(nameof(jsonSerializer));
}
: this(jsonSerializer)
{ }
public static void ClearCaches() => Storages.Clear();
/// <summary>
/// Clears the data type configuration caches.
/// </summary>
[Obsolete("Caching of data type configuration is not done anymore. This method will be removed in a future version.")]
public static void ClearCaches()
{ }
/// <inheritdoc />
public override bool IsConverter(IPublishedPropertyType propertyType)
=> propertyType.EditorAlias.InvariantEquals(Constants.PropertyEditors.Aliases.Tags);
/// <inheritdoc />
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
=> typeof(IEnumerable<string>);
/// <inheritdoc />
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
=> PropertyCacheLevel.Element;
/// <inheritdoc />
public override object? ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object? source, bool preview)
{
if (source == null)
string? sourceString = source?.ToString();
if (string.IsNullOrEmpty(sourceString))
{
return Array.Empty<string>();
}
// if Json storage type deserialize and return as string array
if (JsonStorageType(propertyType.DataType.Id))
{
var array = source.ToString() is not null
? _jsonSerializer.Deserialize<string[]>(source.ToString()!)
: null;
return array ?? Array.Empty<string>();
}
// Otherwise assume CSV storage type and return as string array
return source.ToString()?.Split(Constants.CharArrays.Comma, StringSplitOptions.RemoveEmptyEntries);
return IsJson(propertyType)
? _jsonSerializer.Deserialize<string[]>(sourceString) ?? Array.Empty<string>()
: sourceString.Split(Constants.CharArrays.Comma, StringSplitOptions.RemoveEmptyEntries);
}
public override object? ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object? source, bool preview) => (string[]?)source;
/// <summary>
/// Discovers if the tags data type is storing its data in a Json format
/// </summary>
/// <param name="dataTypeId">
/// The data type id.
/// </param>
/// <returns>
/// The <see cref="bool" />.
/// </returns>
private bool JsonStorageType(int dataTypeId) =>
// GetDataType(id) is cached at repository level; still, there is some
// deep-cloning involved (expensive) - better cache here + trigger
// refresh in DataTypeCacheRefresher
Storages.GetOrAdd(dataTypeId, id =>
{
TagConfiguration? configuration = _dataTypeService.GetDataType(id)?.ConfigurationAs<TagConfiguration>();
return configuration?.StorageType == TagsStorageType.Json;
});
private static bool IsJson(IPublishedPropertyType propertyType)
=> propertyType.DataType.ConfigurationAs<TagConfiguration>()?.StorageType == TagsStorageType.Json;
}
@@ -1,6 +1,8 @@
using System.Xml.XPath;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Xml;
using Umbraco.Cms.Web.Common.DependencyInjection;
using Umbraco.Extensions;
namespace Umbraco.Cms.Core.PublishedCache;
@@ -9,10 +11,24 @@ public abstract class PublishedCacheBase : IPublishedCache
{
private readonly IVariationContextAccessor? _variationContextAccessor;
public PublishedCacheBase(IVariationContextAccessor variationContextAccessor) => _variationContextAccessor =
variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor));
protected PublishedCacheBase(bool previewDefault) => PreviewDefault = previewDefault;
[Obsolete("Use ctor with all parameters. This will be removed in V15")]
public PublishedCacheBase(IVariationContextAccessor variationContextAccessor)
: this(variationContextAccessor, false)
{
}
[Obsolete("Use ctor with all parameters. This will be removed in V15")]
protected PublishedCacheBase(bool previewDefault)
: this(StaticServiceProvider.Instance.GetRequiredService<IVariationContextAccessor>(), previewDefault)
{
}
public PublishedCacheBase(IVariationContextAccessor variationContextAccessor, bool previewDefault)
{
_variationContextAccessor = variationContextAccessor;
PreviewDefault = previewDefault;
}
public bool PreviewDefault { get; }
+24
View File
@@ -50,4 +50,28 @@ public class WebPath
return sb.ToString();
}
/// <summary>
/// Determines whether the provided web path is well-formed according to the specified UriKind.
/// </summary>
/// <param name="webPath">The web path to check. This can be null.</param>
/// <param name="uriKind">The kind of Uri (Absolute, Relative, or RelativeOrAbsolute).</param>
/// <returns>
/// true if <paramref name="webPath"/> is well-formed; otherwise, false.
/// </returns>
public static bool IsWellFormedWebPath(string? webPath, UriKind uriKind)
{
if (string.IsNullOrWhiteSpace(webPath))
{
return false;
}
if (webPath.StartsWith("//"))
{
return uriKind is not UriKind.Relative;
}
return Uri.IsWellFormedUriString(webPath, uriKind);
}
}
@@ -7,26 +7,56 @@ using System.Security.Principal;
namespace Umbraco.Extensions;
/// <summary>
/// Extension methods for <see cref="IIdentity" />.
/// </summary>
public static class AuthenticationExtensions
{
/// <summary>
/// Ensures that the thread culture is set based on the back office user's culture
/// Ensures that the thread culture is set based on the back office user's culture.
/// </summary>
/// <param name="identity">The identity.</param>
public static void EnsureCulture(this IIdentity identity)
{
CultureInfo? culture = GetCulture(identity);
if (!(culture is null))
if (culture is not null)
{
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = culture;
}
}
/// <summary>
/// Gets the culture string from the back office user.
/// </summary>
/// <param name="identity">The identity.</param>
/// <returns>
/// The culture string.
/// </returns>
public static string? GetCultureString(this IIdentity identity)
{
if (identity is ClaimsIdentity umbIdentity &&
umbIdentity.VerifyBackOfficeIdentity(out _) &&
umbIdentity.IsAuthenticated)
{
return umbIdentity.GetCultureString();
}
return null;
}
/// <summary>
/// Gets the culture from the back office user.
/// </summary>
/// <param name="identity">The identity.</param>
/// <returns>
/// The culture.
/// </returns>
public static CultureInfo? GetCulture(this IIdentity identity)
{
if (identity is ClaimsIdentity umbIdentity && umbIdentity.VerifyBackOfficeIdentity(out _) &&
umbIdentity.IsAuthenticated && umbIdentity.GetCultureString() is not null)
string? culture = identity.GetCultureString();
if (!string.IsNullOrEmpty(culture))
{
return CultureInfo.GetCultureInfo(umbIdentity.GetCultureString()!);
return CultureInfo.GetCultureInfo(culture);
}
return null;
+23 -36
View File
@@ -167,12 +167,7 @@ public class ContentPermissions
throw new ArgumentNullException(nameof(user));
}
if (permissionsToCheck == null)
{
permissionsToCheck = Array.Empty<char>();
}
bool? hasPathAccess = null;
bool hasPathAccess;
entity = null;
if (nodeId == Constants.System.Root)
@@ -183,19 +178,17 @@ public class ContentPermissions
{
hasPathAccess = user.HasContentBinAccess(_entityService, _appCaches);
}
if (hasPathAccess.HasValue)
else
{
return hasPathAccess.Value ? ContentAccess.Granted : ContentAccess.Denied;
}
entity = _entityService.Get(nodeId, UmbracoObjectTypes.Document);
entity = _entityService.Get(nodeId, UmbracoObjectTypes.Document);
if (entity == null)
{
return ContentAccess.NotFound;
}
if (entity == null)
{
return ContentAccess.NotFound;
}
hasPathAccess = user.HasContentPathAccess(entity, _entityService, _appCaches);
hasPathAccess = user.HasContentPathAccess(entity, _entityService, _appCaches);
}
if (hasPathAccess == false)
{
@@ -208,7 +201,8 @@ public class ContentPermissions
}
// get the implicit/inherited permissions for the user for this path
return CheckPermissionsPath(entity.Path, user, permissionsToCheck)
// if there is no entity for this id, than just use the id as the path (i.e. -1 or -20)
return CheckPermissionsPath(entity?.Path ?? nodeId.ToString(), user, permissionsToCheck)
? ContentAccess.Granted
: ContentAccess.Denied;
}
@@ -235,12 +229,7 @@ public class ContentPermissions
throw new ArgumentNullException(nameof(user));
}
if (permissionsToCheck == null)
{
permissionsToCheck = Array.Empty<char>();
}
bool? hasPathAccess = null;
bool hasPathAccess;
contentItem = null;
if (nodeId == Constants.System.Root)
@@ -251,19 +240,17 @@ public class ContentPermissions
{
hasPathAccess = user.HasContentBinAccess(_entityService, _appCaches);
}
if (hasPathAccess.HasValue)
else
{
return hasPathAccess.Value ? ContentAccess.Granted : ContentAccess.Denied;
}
contentItem = _contentService.GetById(nodeId);
contentItem = _contentService.GetById(nodeId);
if (contentItem == null)
{
return ContentAccess.NotFound;
}
if (contentItem == null)
{
return ContentAccess.NotFound;
}
hasPathAccess = user.HasPathAccess(contentItem, _entityService, _appCaches);
hasPathAccess = user.HasPathAccess(contentItem, _entityService, _appCaches);
}
if (hasPathAccess == false)
{
@@ -276,7 +263,8 @@ public class ContentPermissions
}
// get the implicit/inherited permissions for the user for this path
return CheckPermissionsPath(contentItem.Path, user, permissionsToCheck)
// if there is no content item for this id, than just use the id as the path (i.e. -1 or -20)
return CheckPermissionsPath(contentItem?.Path ?? nodeId.ToString(), user, permissionsToCheck)
? ContentAccess.Granted
: ContentAccess.Denied;
}
@@ -288,8 +276,7 @@ public class ContentPermissions
permissionsToCheck = Array.Empty<char>();
}
// get the implicit/inherited permissions for the user for this path,
// if there is no content item for this id, than just use the id as the path (i.e. -1 or -20)
// get the implicit/inherited permissions for the user for this path
EntityPermissionSet permission = _userService.GetPermissionsForPath(user, path);
var allowed = true;
@@ -0,0 +1,38 @@
namespace Umbraco.Cms.Core.Security;
public class FileStreamSecurityValidator : IFileStreamSecurityValidator
{
private readonly IEnumerable<IFileStreamSecurityAnalyzer> _fileAnalyzers;
public FileStreamSecurityValidator(IEnumerable<IFileStreamSecurityAnalyzer> fileAnalyzers)
{
_fileAnalyzers = fileAnalyzers;
}
/// <summary>
/// Analyzes whether the file content is considered safe with registered IFileStreamSecurityAnalyzers
/// </summary>
/// <param name="fileStream">Needs to be a Read seekable stream</param>
/// <returns>Whether the file is considered safe after running the necessary analyzers</returns>
public bool IsConsideredSafe(Stream fileStream)
{
foreach (var fileAnalyzer in _fileAnalyzers)
{
fileStream.Seek(0, SeekOrigin.Begin);
if (!fileAnalyzer.ShouldHandle(fileStream))
{
continue;
}
fileStream.Seek(0, SeekOrigin.Begin);
if (fileAnalyzer.IsConsideredSafe(fileStream) == false)
{
return false;
}
}
fileStream.Seek(0, SeekOrigin.Begin);
// If no analyzer we consider the file to be safe as the implementer has the possibility to add additional analyzers
// Or all analyzers deem te file to be safe
return true;
}
}
@@ -0,0 +1,20 @@
namespace Umbraco.Cms.Core.Security;
public interface IFileStreamSecurityAnalyzer
{
/// <summary>
/// Indicates whether the analyzer should process the file
/// The implementation should be considerably faster than IsConsideredSafe
/// </summary>
/// <param name="fileStream"></param>
/// <returns></returns>
bool ShouldHandle(Stream fileStream);
/// <summary>
/// Analyzes whether the file content is considered safe
/// </summary>
/// <param name="fileStream">Needs to be a Read/Write seekable stream</param>
/// <returns>Whether the file is considered safe</returns>
bool IsConsideredSafe(Stream fileStream);
}
@@ -0,0 +1,11 @@
namespace Umbraco.Cms.Core.Security;
public interface IFileStreamSecurityValidator
{
/// <summary>
/// Analyzes wether the file content is considered safe with registered IFileStreamSecurityAnalyzers
/// </summary>
/// <param name="fileStream">Needs to be a Read seekable stream</param>
/// <returns>Whether the file is considered safe after running the necessary analyzers</returns>
bool IsConsideredSafe(Stream fileStream);
}
@@ -0,0 +1,14 @@
namespace Umbraco.Cms.Core.Security;
/// <summary>
/// Sanitizer service for the markdown editor.
/// </summary>
public interface IMarkdownSanitizer
{
/// <summary>
/// Sanitizes Markdown
/// </summary>
/// <param name="markdown">Markdown to be sanitized</param>
/// <returns>Sanitized Markdown</returns>
string Sanitize(string markdown);
}
@@ -0,0 +1,8 @@
namespace Umbraco.Cms.Core.Security;
/// <inheritdoc />
public class NoopMarkdownSanitizer : IMarkdownSanitizer
{
/// <inheritdoc />
public string Sanitize(string markdown) => markdown;
}
+49 -34
View File
@@ -36,20 +36,20 @@ public class ContentService : RepositoryService, IContentService
#region Constructors
public ContentService(
ICoreScopeProvider provider,
ILoggerFactory loggerFactory,
IEventMessagesFactory eventMessagesFactory,
IDocumentRepository documentRepository,
IEntityRepository entityRepository,
IAuditRepository auditRepository,
IContentTypeRepository contentTypeRepository,
IDocumentBlueprintRepository documentBlueprintRepository,
ILanguageRepository languageRepository,
Lazy<IPropertyValidationService> propertyValidationService,
IShortStringHelper shortStringHelper,
ICultureImpactFactory cultureImpactFactory)
: base(provider, loggerFactory, eventMessagesFactory)
public ContentService(
ICoreScopeProvider provider,
ILoggerFactory loggerFactory,
IEventMessagesFactory eventMessagesFactory,
IDocumentRepository documentRepository,
IEntityRepository entityRepository,
IAuditRepository auditRepository,
IContentTypeRepository contentTypeRepository,
IDocumentBlueprintRepository documentBlueprintRepository,
ILanguageRepository languageRepository,
Lazy<IPropertyValidationService> propertyValidationService,
IShortStringHelper shortStringHelper,
ICultureImpactFactory cultureImpactFactory)
: base(provider, loggerFactory, eventMessagesFactory)
{
_documentRepository = documentRepository;
_entityRepository = entityRepository;
@@ -59,7 +59,7 @@ public class ContentService : RepositoryService, IContentService
_languageRepository = languageRepository;
_propertyValidationService = propertyValidationService;
_shortStringHelper = shortStringHelper;
_cultureImpactFactory = cultureImpactFactory;
_cultureImpactFactory = cultureImpactFactory;
_logger = loggerFactory.CreateLogger<ContentService>();
}
@@ -372,7 +372,7 @@ public class ContentService : RepositoryService, IContentService
public IContent CreateAndSave(string name, int parentId, string contentTypeAlias, int userId = Constants.Security.SuperUserId)
{
// TODO: what about culture?
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
{
// locking the content tree secures content types too
scope.WriteLock(Constants.Locks.ContentTree);
@@ -395,6 +395,8 @@ public class ContentService : RepositoryService, IContentService
Save(content, userId);
scope.Complete();
return content;
}
}
@@ -416,7 +418,7 @@ public class ContentService : RepositoryService, IContentService
throw new ArgumentNullException(nameof(parent));
}
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
{
// locking the content tree secures content types too
scope.WriteLock(Constants.Locks.ContentTree);
@@ -431,6 +433,7 @@ public class ContentService : RepositoryService, IContentService
Save(content, userId);
scope.Complete();
return content;
}
}
@@ -508,10 +511,11 @@ public class ContentService : RepositoryService, IContentService
/// <inheritdoc />
public void PersistContentSchedule(IContent content, ContentScheduleCollection contentSchedule)
{
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
{
scope.WriteLock(Constants.Locks.ContentTree);
_documentRepository.PersistContentSchedule(content, contentSchedule);
scope.Complete();
}
}
@@ -1146,6 +1150,8 @@ public class ContentService : RepositoryService, IContentService
var allLangs = _languageRepository.GetMany().ToList();
// Change state to publishing
content.PublishedState = PublishedState.Publishing;
var savingNotification = new ContentSavingNotification(content, evtMsgs);
if (scope.Notifications.PublishCancelable(savingNotification))
{
@@ -1156,7 +1162,7 @@ public class ContentService : RepositoryService, IContentService
// if culture is '*', then publish them all (including variants)
// this will create the correct culture impact even if culture is * or null
var impact = _cultureImpactFactory.Create(culture, IsDefaultCulture(allLangs, culture), content);
var impact = _cultureImpactFactory.Create(culture, IsDefaultCulture(allLangs, culture), content);
// publish the culture(s)
// we don't care about the response here, this response will be rechecked below but we need to set the culture info values now.
@@ -1540,7 +1546,7 @@ public class ContentService : RepositoryService, IContentService
// handling events, business rules, etc
// note: StrategyUnpublish flips the PublishedState to Unpublishing!
// note: This unpublishes the entire document (not different variants)
unpublishResult = StrategyCanUnpublish(scope, content, eventMessages);
unpublishResult = StrategyCanUnpublish(scope, content, eventMessages, notificationState);
if (unpublishResult.Success)
{
unpublishResult = StrategyUnpublish(content, eventMessages);
@@ -1843,7 +1849,7 @@ public class ContentService : RepositoryService, IContentService
// publish the culture values and validate the property values, if validation fails, log the invalid properties so the develeper has an idea of what has failed
IProperty[]? invalidProperties = null;
var impact = _cultureImpactFactory.ImpactExplicit(culture, IsDefaultCulture(allLangs.Value, culture));
var impact = _cultureImpactFactory.ImpactExplicit(culture, IsDefaultCulture(allLangs.Value, culture));
var tryPublish = d.PublishCulture(impact) &&
_propertyValidationService.Value.IsPropertyDataValid(d, out invalidProperties, impact);
if (invalidProperties != null && invalidProperties.Length > 0)
@@ -1927,14 +1933,14 @@ public class ContentService : RepositoryService, IContentService
{
return culturesToPublish.All(culture =>
{
var impact = _cultureImpactFactory.Create(culture, IsDefaultCulture(allLangs, culture), content);
var impact = _cultureImpactFactory.Create(culture, IsDefaultCulture(allLangs, culture), content);
return content.PublishCulture(impact) &&
_propertyValidationService.Value.IsPropertyDataValid(content, out _, impact);
});
}
return content.PublishCulture(_cultureImpactFactory.ImpactInvariant())
&& _propertyValidationService.Value.IsPropertyDataValid(content, out _, _cultureImpactFactory.ImpactInvariant());
return content.PublishCulture(_cultureImpactFactory.ImpactInvariant())
&& _propertyValidationService.Value.IsPropertyDataValid(content, out _, _cultureImpactFactory.ImpactInvariant());
}
// utility 'ShouldPublish' func used by SaveAndPublishBranch
@@ -2103,7 +2109,7 @@ public class ContentService : RepositoryService, IContentService
}
// deal with the branch root - if it fails, abort
PublishResult? result = SaveAndPublishBranchItem(scope, document, shouldPublish, publishCultures, true, publishedDocuments, eventMessages, userId, allLangs);
PublishResult? result = SaveAndPublishBranchItem(scope, document, shouldPublish, publishCultures, true, publishedDocuments, eventMessages, userId, allLangs, out IDictionary<string, object?> notificationState);
if (result != null)
{
results.Add(result);
@@ -2138,7 +2144,7 @@ public class ContentService : RepositoryService, IContentService
}
// no need to check path here, parent has to be published here
result = SaveAndPublishBranchItem(scope, d, shouldPublish, publishCultures, false, publishedDocuments, eventMessages, userId, allLangs);
result = SaveAndPublishBranchItem(scope, d, shouldPublish, publishCultures, false, publishedDocuments, eventMessages, userId, allLangs, out _);
if (result != null)
{
results.Add(result);
@@ -2162,7 +2168,7 @@ public class ContentService : RepositoryService, IContentService
// (SaveAndPublishBranchOne does *not* do it)
scope.Notifications.Publish(
new ContentTreeChangeNotification(document, TreeChangeTypes.RefreshBranch, eventMessages));
scope.Notifications.Publish(new ContentPublishedNotification(publishedDocuments, eventMessages));
scope.Notifications.Publish(new ContentPublishedNotification(publishedDocuments, eventMessages).WithState(notificationState));
scope.Complete();
}
@@ -2183,8 +2189,10 @@ public class ContentService : RepositoryService, IContentService
ICollection<IContent> publishedDocuments,
EventMessages evtMsgs,
int userId,
IReadOnlyCollection<ILanguage> allLangs)
IReadOnlyCollection<ILanguage> allLangs,
out IDictionary<string, object?> notificationState)
{
notificationState = new Dictionary<string, object?>();
HashSet<string>? culturesToPublish = shouldPublish(document);
// null = do not include
@@ -2216,6 +2224,7 @@ public class ContentService : RepositoryService, IContentService
if (result.Success)
{
publishedDocuments.Add(document);
notificationState = savingNotification.State;
}
return result;
@@ -2432,7 +2441,7 @@ public class ContentService : RepositoryService, IContentService
/// <param name="userId">Optional Id of the User moving the Content</param>
public void Move(IContent content, int parentId, int userId = Constants.Security.SuperUserId)
{
if(content.ParentId == parentId)
if (content.ParentId == parentId)
{
return;
}
@@ -2583,7 +2592,8 @@ public class ContentService : RepositoryService, IContentService
IContent[] contents = _documentRepository.Get(query).ToArray();
var emptyingRecycleBinNotification = new ContentEmptyingRecycleBinNotification(contents, eventMessages);
if (scope.Notifications.PublishCancelable(emptyingRecycleBinNotification))
var deletingContentNotification = new ContentDeletingNotification(contents, eventMessages);
if (scope.Notifications.PublishCancelable(emptyingRecycleBinNotification) || scope.Notifications.PublishCancelable(deletingContentNotification))
{
scope.Complete();
return OperationResult.Cancel(eventMessages);
@@ -2948,13 +2958,13 @@ public class ContentService : RepositoryService, IContentService
{
scope.Notifications.Publish(new ContentPublishedNotification(published, eventMessages));
}
return OperationResult.Succeed(eventMessages);
}
public ContentDataIntegrityReport CheckDataIntegrity(ContentDataIntegrityReportOptions options)
{
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
{
scope.WriteLock(Constants.Locks.ContentTree);
@@ -2967,6 +2977,8 @@ public class ContentService : RepositoryService, IContentService
scope.Notifications.Publish(new ContentTreeChangeNotification(root, TreeChangeTypes.RefreshAll, EventMessagesFactory.Get()));
}
scope.Complete();
return report;
}
}
@@ -3293,10 +3305,10 @@ public class ContentService : RepositoryService, IContentService
/// <param name="content"></param>
/// <param name="evtMsgs"></param>
/// <returns></returns>
private PublishResult StrategyCanUnpublish(ICoreScope scope, IContent content, EventMessages evtMsgs)
private PublishResult StrategyCanUnpublish(ICoreScope scope, IContent content, EventMessages evtMsgs, IDictionary<string, object?>? notificationState)
{
// raise Unpublishing notification
if (scope.Notifications.PublishCancelable(new ContentUnpublishingNotification(content, evtMsgs)))
if (scope.Notifications.PublishCancelable(new ContentUnpublishingNotification(content, evtMsgs).WithState(notificationState)))
{
_logger.LogInformation(
"Document {ContentName} (id={ContentId}) cannot be unpublished: unpublishing was cancelled.", content.Name, content.Id);
@@ -3562,6 +3574,7 @@ public class ContentService : RepositoryService, IContentService
Audit(AuditType.Save, Constants.Security.SuperUserId, content.Id, $"Saved content template: {content.Name}");
scope.Notifications.Publish(new ContentSavedBlueprintNotification(content, evtMsgs));
scope.Notifications.Publish(new ContentTreeChangeNotification(content, TreeChangeTypes.RefreshNode, evtMsgs));
scope.Complete();
}
@@ -3576,6 +3589,7 @@ public class ContentService : RepositoryService, IContentService
scope.WriteLock(Constants.Locks.ContentTree);
_documentBlueprintRepository.Delete(content);
scope.Notifications.Publish(new ContentDeletedBlueprintNotification(content, evtMsgs));
scope.Notifications.Publish(new ContentTreeChangeNotification(content, TreeChangeTypes.Remove, evtMsgs));
scope.Complete();
}
}
@@ -3676,6 +3690,7 @@ public class ContentService : RepositoryService, IContentService
}
scope.Notifications.Publish(new ContentDeletedBlueprintNotification(blueprints, evtMsgs));
scope.Notifications.Publish(new ContentTreeChangeNotification(blueprints, TreeChangeTypes.Remove, evtMsgs));
scope.Complete();
}
}
@@ -1,4 +1,4 @@
// Copyright (c) Umbraco.
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Text.RegularExpressions;
@@ -16,7 +16,8 @@ public static class ContentServiceExtensions
{
#region RTE Anchor values
private static readonly Regex AnchorRegex = new("<a id=\"(.*?)\">", RegexOptions.Compiled);
private static readonly Regex AnchorRegex = new(@"<a id=\\*""(.*?)\\*"">", RegexOptions.Compiled);
private static readonly string[] _propertyTypesWithRte = new[] { Constants.PropertyEditors.Aliases.TinyMce, Constants.PropertyEditors.Aliases.BlockList, Constants.PropertyEditors.Aliases.BlockGrid };
public static IEnumerable<IContent>? GetByIds(this IContentService contentService, IEnumerable<Udi> ids)
{
@@ -67,21 +68,22 @@ public static class ContentServiceExtensions
public static IEnumerable<string> GetAnchorValuesFromRTEs(this IContentService contentService, int id, string? culture = "*")
{
var result = new List<string>();
culture = culture is not "*" ? culture : null;
IContent? content = contentService.GetById(id);
if (content is not null)
if (content is null)
{
foreach (IProperty contentProperty in content.Properties)
return result;
}
foreach (IProperty contentProperty in content.Properties.Where(s => _propertyTypesWithRte.Contains(s.PropertyType.PropertyEditorAlias)))
{
var value = contentProperty.GetValue(culture)?.ToString();
if (!string.IsNullOrEmpty(value))
{
if (contentProperty.PropertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.Aliases
.TinyMce))
{
var value = contentProperty.GetValue(culture)?.ToString();
if (!string.IsNullOrEmpty(value))
{
result.AddRange(contentService.GetAnchorValuesFromRTEContent(value));
}
}
result.AddRange(contentService.GetAnchorValuesFromRTEContent(value));
}
}
@@ -96,7 +98,7 @@ public static class ContentServiceExtensions
MatchCollection matches = AnchorRegex.Matches(rteContent);
foreach (Match match in matches)
{
result.Add(match.Value.Split(Constants.CharArrays.DoubleQuote)[1]);
result.Add(match.Groups[1].Value);
}
return result;
@@ -322,7 +322,6 @@ public abstract class ContentTypeServiceBase<TRepository, TItem> : ContentTypeSe
}
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
{
scope.ReadLock(ReadLockIds);
return Repository.GetMany(ids.ToArray());
@@ -68,7 +68,7 @@ internal class ContentVersionService : IContentVersionService
/// <inheritdoc />
public void SetPreventCleanup(int versionId, bool preventCleanup, int userId = -1)
{
using (ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true))
using (ICoreScope scope = _scopeProvider.CreateCoreScope())
{
scope.WriteLock(Constants.Locks.ContentTree);
_documentVersionRepository.SetPreventCleanup(versionId, preventCleanup);
@@ -77,6 +77,7 @@ internal class ContentVersionService : IContentVersionService
if (version is null)
{
scope.Complete();
return;
}
@@ -87,6 +88,7 @@ internal class ContentVersionService : IContentVersionService
var message = $"set preventCleanup = '{preventCleanup}' for version '{versionId}'";
Audit(auditType, userId, version.ContentId, message, $"{version.VersionDate}");
scope.Complete();
}
}
@@ -120,13 +122,14 @@ internal class ContentVersionService : IContentVersionService
*
* tl;dr lots of scopes to enable other connections to use the DB whilst we work.
*/
using (ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true))
using (ICoreScope scope = _scopeProvider.CreateCoreScope())
{
IReadOnlyCollection<ContentVersionMeta>? allHistoricVersions =
_documentVersionRepository.GetDocumentVersionsEligibleForCleanup();
if (allHistoricVersions is null)
{
scope.Complete();
return Array.Empty<ContentVersionMeta>();
}
@@ -149,6 +152,8 @@ internal class ContentVersionService : IContentVersionService
versionsToDelete.Add(version);
}
scope.Complete();
}
if (!versionsToDelete.Any())
@@ -161,7 +166,7 @@ internal class ContentVersionService : IContentVersionService
foreach (IEnumerable<ContentVersionMeta> group in versionsToDelete.InGroupsOf(Constants.Sql.MaxParameterCount))
{
using (ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true))
using (ICoreScope scope = _scopeProvider.CreateCoreScope())
{
scope.WriteLock(Constants.Locks.ContentTree);
var groupEnumerated = group.ToList();
@@ -174,12 +179,16 @@ internal class ContentVersionService : IContentVersionService
scope.Notifications.Publish(
new ContentDeletedVersionsNotification(version.ContentId, messages, version.VersionId));
}
scope.Complete();
}
}
using (_scopeProvider.CreateCoreScope(autoComplete: true))
using (ICoreScope scope = _scopeProvider.CreateCoreScope())
{
Audit(AuditType.Delete, Constants.Security.SuperUserId, -1, $"Removed {versionsToDelete.Count} ContentVersion(s) according to cleanup policy");
scope.Complete();
}
return versionsToDelete;
+1 -1
View File
@@ -608,7 +608,7 @@ namespace Umbraco.Cms.Core.Services.Implement
public IReadOnlyDictionary<Udi, IEnumerable<string>> GetReferences(int id)
{
using ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete:true);
using ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true);
return _dataTypeRepository.FindUsages(id);
}
@@ -33,7 +33,7 @@ public class DefaultContentVersionCleanupPolicy : IContentVersionCleanupPolicy
var theRest = new List<ContentVersionMeta>();
using (_scopeProvider.CreateCoreScope(autoComplete: true))
using (ICoreScope scope = _scopeProvider.CreateCoreScope())
{
var policyOverrides = _documentVersionRepository.GetCleanupPolicies()?
.ToDictionary(x => x.ContentTypeId);
@@ -77,6 +77,8 @@ public class DefaultContentVersionCleanupPolicy : IContentVersionCleanupPolicy
yield return version;
}
}
scope.Complete();
}
}
+2 -1
View File
@@ -1197,7 +1197,7 @@ namespace Umbraco.Cms.Core.Services
public ContentDataIntegrityReport CheckDataIntegrity(ContentDataIntegrityReportOptions options)
{
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
{
scope.WriteLock(Constants.Locks.MediaTree);
@@ -1210,6 +1210,7 @@ namespace Umbraco.Cms.Core.Services
scope.Notifications.Publish(new MediaTreeChangeNotification(root, TreeChangeTypes.RefreshAll, EventMessagesFactory.Get()));
}
scope.Complete();
return report;
}
}
@@ -59,8 +59,10 @@ public class TwoFactorLoginService : ITwoFactorLoginService2
/// <inheritdoc />
public async Task DeleteUserLoginsAsync(Guid userOrMemberKey)
{
using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true);
using ICoreScope scope = _scopeProvider.CreateCoreScope();
await _twoFactorLoginRepository.DeleteUserLoginsAsync(userOrMemberKey);
scope.Complete();
}
/// <inheritdoc />
@@ -155,8 +157,12 @@ public class TwoFactorLoginService : ITwoFactorLoginService2
/// <inheritdoc />
public async Task<bool> DisableAsync(Guid userOrMemberKey, string providerName)
{
using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true);
return await _twoFactorLoginRepository.DeleteUserLoginsAsync(userOrMemberKey, providerName);
using ICoreScope scope = _scopeProvider.CreateCoreScope();
var result = await _twoFactorLoginRepository.DeleteUserLoginsAsync(userOrMemberKey, providerName);
scope.Complete();
return result;
}
/// <inheritdoc />
@@ -173,9 +179,10 @@ public class TwoFactorLoginService : ITwoFactorLoginService2
/// <inheritdoc />
public Task SaveAsync(TwoFactorLogin twoFactorLogin)
{
using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true);
using ICoreScope scope = _scopeProvider.CreateCoreScope();
_twoFactorLoginRepository.Save(twoFactorLogin);
scope.Complete();
return Task.CompletedTask;
}
@@ -8,6 +8,11 @@ namespace Umbraco.Extensions;
public static class UserServiceExtensions
{
public static EntityPermission? GetPermissions(this IUserService userService, IUser? user, string path)
{
return userService.GetAllPermissions(user, path).FirstOrDefault();
}
public static EntityPermissionCollection GetAllPermissions(this IUserService userService, IUser? user, string path)
{
var ids = path.Split(Constants.CharArrays.Comma, StringSplitOptions.RemoveEmptyEntries)
.Select(x =>
@@ -23,7 +28,7 @@ public static class UserServiceExtensions
" could not be parsed into an array of integers or the path was empty");
}
return userService.GetPermissions(user, ids[^1]).FirstOrDefault();
return userService.GetPermissions(user, ids[^1]);
}
/// <summary>
+118
View File
@@ -0,0 +1,118 @@
using System.Diagnostics;
namespace Umbraco.Cms.Core;
/// <summary>
/// Makes a code block timed (take at least a certain amount of time). This class cannot be inherited.
/// </summary>
public sealed class TimedScope : IDisposable, IAsyncDisposable
{
private readonly TimeSpan _duration;
private readonly CancellationTokenSource _cancellationTokenSource;
private readonly Stopwatch _stopwatch;
/// <summary>
/// Gets the elapsed time.
/// </summary>
/// <value>
/// The elapsed time.
/// </value>
public TimeSpan Elapsed => _stopwatch.Elapsed;
/// <summary>
/// Gets the remaining time.
/// </summary>
/// <value>
/// The remaining time.
/// </value>
public TimeSpan Remaining
=> TryGetRemaining(out TimeSpan remaining) ? remaining : TimeSpan.Zero;
/// <summary>
/// Initializes a new instance of the <see cref="TimedScope" /> class.
/// </summary>
/// <param name="millisecondsDuration">The number of milliseconds the scope should at least take.</param>
public TimedScope(long millisecondsDuration)
: this(TimeSpan.FromMilliseconds(millisecondsDuration))
{ }
/// <summary>
/// Initializes a new instance of the <see cref="TimedScope" /> class.
/// </summary>
/// <param name="millisecondsDuration">The number of milliseconds the scope should at least take.</param>
/// <param name="cancellationToken">The cancellation token.</param>
public TimedScope(long millisecondsDuration, CancellationToken cancellationToken)
: this(TimeSpan.FromMilliseconds(millisecondsDuration), cancellationToken)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="TimedScope"/> class.
/// </summary>
/// <param name="duration">The duration the scope should at least take.</param>
public TimedScope(TimeSpan duration)
: this(duration, new CancellationTokenSource())
{ }
/// <summary>
/// Initializes a new instance of the <see cref="TimedScope" /> class.
/// </summary>
/// <param name="duration">The duration the scope should at least take.</param>
/// <param name="cancellationToken">The cancellation token.</param>
public TimedScope(TimeSpan duration, CancellationToken cancellationToken)
: this(duration, CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
{ }
private TimedScope(TimeSpan duration, CancellationTokenSource cancellationTokenSource)
{
_duration = duration;
_cancellationTokenSource = cancellationTokenSource;
_stopwatch = new Stopwatch();
_stopwatch.Start();
}
/// <summary>
/// Cancels the timed scope.
/// </summary>
public void Cancel()
=> _cancellationTokenSource.Cancel();
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <remarks>
/// This will block using <see cref="Thread.Sleep(TimeSpan)" /> until the remaining time has elapsed, if not cancelled.
/// </remarks>
public void Dispose()
{
if (_cancellationTokenSource.IsCancellationRequested is false &&
TryGetRemaining(out TimeSpan remaining))
{
Thread.Sleep(remaining);
}
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources asynchronously.
/// </summary>
/// <returns>
/// A task that represents the asynchronous dispose operation.
/// </returns>
/// <remarks>
/// This will delay using <see cref="Task.Delay(TimeSpan, CancellationToken)" /> until the remaining time has elapsed, if not cancelled.
/// </remarks>
public async ValueTask DisposeAsync()
{
if (_cancellationTokenSource.IsCancellationRequested is false &&
TryGetRemaining(out TimeSpan remaining))
{
await Task.Delay(remaining, _cancellationTokenSource.Token).ConfigureAwait(false);
}
}
private bool TryGetRemaining(out TimeSpan remaining)
{
remaining = _duration.Subtract(Elapsed);
return remaining > TimeSpan.Zero;
}
}
+16 -16
View File
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PackageId>Umbraco.Cms.Core</PackageId>
<Title>Umbraco CMS - Core</Title>
@@ -7,22 +7,22 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="6.0.5" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Physical" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="6.0.5" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Options.DataAnnotations" Version="6.0.0" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.7.0" />
<PackageReference Include="System.Runtime.Caching" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Physical" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions"/>
<PackageReference Include="Microsoft.Extensions.Identity.Core" />
<PackageReference Include="Microsoft.Extensions.Logging" />
<PackageReference Include="Microsoft.Extensions.Options"/>
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" />
<PackageReference Include="Microsoft.Extensions.Options.DataAnnotations"/>
<PackageReference Include="System.ComponentModel.Annotations" />
<PackageReference Include="System.Reflection.Emit.Lightweight" />
<PackageReference Include="System.Runtime.Caching" />
<!-- Add dependencies that we force an update to, even that we do not use them explicitly and they seems to be taken from the framework instead of from Nuget -->
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="System.Security.Cryptography.Xml" Version="6.0.1" />
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
<PackageReference Include="System.Net.Http" />
<PackageReference Include="System.Security.Cryptography.Xml" />
<PackageReference Include="System.Text.RegularExpressions" />
</ItemGroup>
<ItemGroup>
@@ -8,13 +8,23 @@ namespace Umbraco.Cms.Core.Xml;
/// </summary>
public class UmbracoXPathPathSyntaxParser
{
[Obsolete("This will be removed in Umbraco 13. Use ParseXPathQuery which accepts a parentId instead")]
public static string ParseXPathQuery(
string xpathExpression,
int? nodeContextId,
Func<int, IEnumerable<string>?> getPath,
Func<int, bool> publishedContentExists) => ParseXPathQuery(xpathExpression, nodeContextId, null, getPath, publishedContentExists);
/// <summary>
/// Parses custom umbraco xpath expression
/// </summary>
/// <param name="xpathExpression">The Xpath expression</param>
/// <param name="nodeContextId">
/// The current node id context of executing the query - null if there is no current node, in which case
/// some of the parameters like $current, $parent, $site will be disabled
/// The current node id context of executing the query - null if there is no current node.
/// </param>
/// <param name="parentId">
/// The parent node id of the current node id context of executing the query. With this we can determine the
/// $parent and $site parameters even if the current node is not yet published.
/// </param>
/// <param name="getPath">The callback to create the nodeId path, given a node Id</param>
/// <param name="publishedContentExists">The callback to return whether a published node exists based on Id</param>
@@ -22,6 +32,7 @@ public class UmbracoXPathPathSyntaxParser
public static string ParseXPathQuery(
string xpathExpression,
int? nodeContextId,
int? parentId,
Func<int, IEnumerable<string>?> getPath,
Func<int, bool> publishedContentExists)
{
@@ -84,19 +95,27 @@ public class UmbracoXPathPathSyntaxParser
// parseable items:
var vars = new Dictionary<string, Func<string, string>>();
// These parameters must have a node id context
if (nodeContextId.HasValue)
if (parentId.HasValue)
{
vars.Add("$parent", q =>
{
var path = getPath(parentId.Value)?.ToArray();
var closestPublishedAncestorId = getClosestPublishedAncestor(path);
return q.Replace("$parent", string.Format(rootXpath, closestPublishedAncestorId));
});
vars.Add("$site", q =>
{
var closestPublishedAncestorId = getClosestPublishedAncestor(getPath(parentId.Value));
return q.Replace(
"$site",
string.Format(rootXpath, closestPublishedAncestorId) + "/ancestor-or-self::*[@level = 1]");
});
}
else if (nodeContextId.HasValue)
{
vars.Add("$current", q =>
{
var closestPublishedAncestorId = getClosestPublishedAncestor(getPath(nodeContextId.Value));
return q.Replace("$current", string.Format(rootXpath, closestPublishedAncestorId));
});
vars.Add("$parent", q =>
{
// remove the first item in the array if its the current node
// this happens when current is published, but we are looking for its parent specifically
var path = getPath(nodeContextId.Value)?.ToArray();
if (path?[0] == nodeContextId.ToString())
{
@@ -116,6 +135,16 @@ public class UmbracoXPathPathSyntaxParser
});
}
// These parameters must have a node id context
if (nodeContextId.HasValue)
{
vars.Add("$current", q =>
{
var closestPublishedAncestorId = getClosestPublishedAncestor(getPath(nodeContextId.Value));
return q.Replace("$current", string.Format(rootXpath, closestPublishedAncestorId));
});
}
// TODO: This used to just replace $root with string.Empty BUT, that would never work
// the root is always "/root . Need to confirm with Per why this was string.Empty before!
vars.Add("$root", q => q.Replace("$root", "/root"));
@@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Examine" Version="3.0.1" />
<PackageReference Include="Examine" />
</ItemGroup>
<ItemGroup>
@@ -67,15 +67,6 @@ public class DistributedCacheBinder :
_distributedCache.RefreshContentCache(notification.Changes.ToArray());
}
// private void ContentService_SavedBlueprint(IContentService sender, SaveEventArgs<IContent> e)
// {
// _distributedCache.RefreshUnpublishedPageCache(e.SavedEntities.ToArray());
// }
// private void ContentService_DeletedBlueprint(IContentService sender, DeleteEventArgs<IContent> e)
// {
// _distributedCache.RemoveUnpublishedPageCache(e.DeletedEntities.ToArray());
// }
#endregion
#region LocalizationService / Dictionary
@@ -1,4 +1,4 @@
// Copyright (c) Umbraco.
// Copyright (c) Umbraco.
// See LICENSE for more details.
using Umbraco.Cms.Core.Cache;
@@ -132,7 +132,13 @@ public static class DistributedCacheExtensions
public static void RefreshAllContentCache(this DistributedCache dc)
{
ContentCacheRefresher.JsonPayload[] payloads = new[] { new ContentCacheRefresher.JsonPayload(0, null, TreeChangeTypes.RefreshAll) };
ContentCacheRefresher.JsonPayload[] payloads = new[]
{
new ContentCacheRefresher.JsonPayload()
{
ChangeTypes = TreeChangeTypes.RefreshAll
}
};
// note: refresh all content cache does refresh content types too
dc.RefreshByPayload(ContentCacheRefresher.UniqueId, payloads);
@@ -145,8 +151,13 @@ public static class DistributedCacheExtensions
return;
}
IEnumerable<ContentCacheRefresher.JsonPayload> payloads = changes
.Select(x => new ContentCacheRefresher.JsonPayload(x.Item.Id, x.Item.Key, x.ChangeTypes));
IEnumerable<ContentCacheRefresher.JsonPayload> payloads = changes.Select(x => new ContentCacheRefresher.JsonPayload()
{
Id = x.Item.Id,
Key = x.Item.Key,
ChangeTypes = x.ChangeTypes,
Blueprint = x.Item.Blueprint
});
dc.RefreshByPayload(ContentCacheRefresher.UniqueId, payloads);
}
@@ -358,10 +358,13 @@ public static partial class UmbracoBuilderExtensions
builder
.AddNotificationHandler<ContentSavingNotification, BlockListPropertyNotificationHandler>()
.AddNotificationHandler<ContentCopyingNotification, BlockListPropertyNotificationHandler>()
.AddNotificationHandler<ContentScaffoldedNotification, BlockListPropertyNotificationHandler>()
.AddNotificationHandler<ContentSavingNotification, BlockGridPropertyNotificationHandler>()
.AddNotificationHandler<ContentCopyingNotification, BlockGridPropertyNotificationHandler>()
.AddNotificationHandler<ContentScaffoldedNotification, BlockGridPropertyNotificationHandler>()
.AddNotificationHandler<ContentSavingNotification, NestedContentPropertyHandler>()
.AddNotificationHandler<ContentCopyingNotification, NestedContentPropertyHandler>()
.AddNotificationHandler<ContentScaffoldedNotification, NestedContentPropertyHandler>()
.AddNotificationHandler<ContentCopiedNotification, FileUploadPropertyEditor>()
.AddNotificationHandler<ContentDeletedNotification, FileUploadPropertyEditor>()
.AddNotificationHandler<MediaDeletedNotification, FileUploadPropertyEditor>()
@@ -37,7 +37,8 @@ public static partial class UmbracoBuilderExtensions
factory.GetRequiredService<IUserService>(),
factory.GetRequiredService<IShortStringHelper>(),
factory.GetRequiredService<IScopeProvider>(),
true));
true,
factory.GetRequiredService<ILocalizationService>()));
builder.Services.AddUnique<IContentValueSetBuilder>(factory =>
new ContentValueSetBuilder(
factory.GetRequiredService<PropertyEditorCollection>(),
@@ -45,7 +46,8 @@ public static partial class UmbracoBuilderExtensions
factory.GetRequiredService<IUserService>(),
factory.GetRequiredService<IShortStringHelper>(),
factory.GetRequiredService<IScopeProvider>(),
false));
false,
factory.GetRequiredService<ILocalizationService>()));
builder.Services.AddUnique<IValueSetBuilder<IMedia>, MediaValueSetBuilder>();
builder.Services.AddUnique<IValueSetBuilder<IMember>, MemberValueSetBuilder>();
builder.Services.AddSingleton<ExamineIndexRebuilder>();
@@ -1,6 +1,9 @@
using Examine;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Web.Common.DependencyInjection;
using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Examine;
@@ -22,7 +25,28 @@ public abstract class BaseValueSetBuilder<TContent> : IValueSetBuilder<TContent>
/// <inheritdoc />
public abstract IEnumerable<ValueSet> GetValueSets(params TContent[] content);
[Obsolete("Use the overload that specifies availableCultures, scheduled for removal in v14")]
protected void AddPropertyValue(IProperty property, string? culture, string? segment, IDictionary<string, IEnumerable<object?>>? values)
=> AddPropertyValue(
property,
culture,
segment,
values,
Enumerable.Empty<string>(),
StaticServiceProvider.Instance.GetRequiredService<IContentTypeService>().GetAll().ToDictionary(x=>x.Key));
[Obsolete("Use the overload that specifies availableCultures, scheduled for removal in v14")]
protected void AddPropertyValue(IProperty property, string? culture, string? segment,
IDictionary<string, IEnumerable<object?>>? values, IEnumerable<string> availableCultures)
=> AddPropertyValue(
property,
culture,
segment,
values,
Enumerable.Empty<string>(),
StaticServiceProvider.Instance.GetRequiredService<IContentTypeService>().GetAll().ToDictionary(x=>x.Key));
protected void AddPropertyValue(IProperty property, string? culture, string? segment, IDictionary<string, IEnumerable<object?>>? values, IEnumerable<string> availableCultures, IDictionary<Guid, IContentType> contentTypeDictionary)
{
IDataEditor? editor = _propertyEditors[property.PropertyType.PropertyEditorAlias];
if (editor == null)
@@ -31,7 +55,7 @@ public abstract class BaseValueSetBuilder<TContent> : IValueSetBuilder<TContent>
}
IEnumerable<KeyValuePair<string, IEnumerable<object?>>> indexVals =
editor.PropertyIndexValueFactory.GetIndexValues(property, culture, segment, PublishedValuesOnly);
editor.PropertyIndexValueFactory.GetIndexValues(property, culture, segment, PublishedValuesOnly, availableCultures, contentTypeDictionary);
foreach (KeyValuePair<string, IEnumerable<object?>> keyVal in indexVals)
{
if (keyVal.Key.IsNullOrWhiteSpace())

Some files were not shown because too many files have changed in this diff Show More