Compare commits

..
Author SHA1 Message Date
Andy ButlandandNiels Lyngsø 8a6615da76 Make sure not to early return when verifying ancestor path is published without completing scope (#19029)
* Make sure not to early return when verifying ancestor path is published without completing scope.

* Added comment.
2025-04-14 20:31:46 +02:00
a5d1b7c122 Use maximum available value for JSON serialization depth (#19001)
* Use maximum available value for JSON serialization depth.

* Updated unittests with best practices

---------

Co-authored-by: Migaroez <geusens@gmail.com>
2025-04-14 20:31:46 +02:00
Nhu DinhandNiels Lyngsø 3001e6dbff V15 Updated acceptance tests for unsupported invariant content item with variant blocks (#18919)
* Updated tests for invariant block grid with variant blocks

* Updated tests for invariant block list with variant blocks

* Updated tests for invariant document with variant blocks

* Bumped version

* Changed npm command

* Updated isValidationMessageVisible

* Fixed name

* Fixed comments

* Reverted npm command
2025-04-14 20:31:46 +02:00
Andy ButlandandNiels Lyngsø b917b61dac Ensure dates read from the database are treated as local when constructing entities (#18989)
* Ensure dates read from the database are treated as local when constructing entities.

* Fixed typos in comments.
2025-04-14 20:31:45 +02:00
Nhu DinhandNiels Lyngsø 74a517a2e1 V15 Added acceptance tests for the mandatory property editor in a content or a block (#18920)
* Added tests for mandatory checkboxlist in a content

* Added tests for mandatory dropdown in a content

* Added tests for mandatory media picker in a content

* Added tests for mandatory radiobox in a content

* Added tests for block grid with mandatory property editors

* Added tests for block list with mandatory property editors

* Bumped version

* Cleaned up

* Changed npm command

* Fixed comments

* Fixed comments

* Reverted
2025-04-14 20:31:45 +02:00
dependabot[bot]andNiels Lyngsø 706a0983df Bump vite from 6.2.5 to 6.2.6 in /src/Umbraco.Web.UI.Client
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.2.5 to 6.2.6.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v6.2.6/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.2.6/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 6.2.6
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-14 20:31:22 +02:00
dependabot[bot]andNiels Lyngsø bb419ec2c6 Bump vite from 6.2.5 to 6.2.6 in /src/Umbraco.Web.UI.Login
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.2.5 to 6.2.6.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v6.2.6/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.2.6/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 6.2.6
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-14 20:31:22 +02:00
kjacandNiels Lyngsø 018d49dda2 Only return the direct compositions of a content type - not its ancestor compositions. Effectively a revert of #15800 2025-04-14 20:31:22 +02:00
kjacandNiels Lyngsø 2fbdc291c9 Do not reject existing compositions when updating content types 2025-04-14 20:31:22 +02:00
Niels Lyngsø 9148a0f845 without UMB_ 2025-04-14 20:31:22 +02:00
leekelleherandNiels Lyngsø 2f7383a622 Implements "inheritance" composition 2025-04-14 20:31:22 +02:00
kjacandNiels Lyngsø b306c16d10 Accept parent key equal to inheritance composition key when creating document and media types 2025-04-14 20:30:05 +02:00
leekelleherandNiels Lyngsø 9288854d6b [WIP] Temp fix for circular reference 2025-04-14 20:30:04 +02:00
leekelleherandNiels Lyngsø 1565665a40 Nested document types (client) 2025-04-14 20:28:55 +02:00
797db55f73 Content client package (#18978)
* scaffold content package

* move content module files

* move content type module files

* update module paths

* fix imports and registration

* import package

* move content collection condition to content module

* align naming

* use consts

* fix imports

* fix import

* change circular threshold

* adjust threshold

* build the correct modules for content package

* Update package-lock.json

* Update index.js

* Update package-lock.json

* Update index.js

* move UmbPropertyStructureWorkspaceContext token and interface

* move UmbWorkspaceContentTypeAliasConditionConfig to content-type module

* fix self import

* fix self imports

* Update content-workspace-context.interface.ts

* remove type from import

* add readOnlyGuard to interface

* remove dependency on content

* move property type module into content package

* update package.json + tsconfig

* import manifests

* move build config

* Update index.js

* lint corrections

---------

Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
2025-04-14 14:25:03 +00:00
8604163c91 Fix dropzone style circular imports (#19024)
* implement standalone

* remove unused style export

* Update src/Umbraco.Web.UI.Client/src/packages/media/dropzone/components/input-dropzone/input-dropzone.element.ts

---------

Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
2025-04-14 09:22:29 +00:00
Jacob OvergaardandGitHub 3939742917 V16: Replace legacy/fetch with @hey-api/client-fetch (#19002)
* feat: adds new backend-api and http-client packages and generates the api with @hey-api/client-fetch

* feat: maps generic T back to promise to avoid usage of 'any'

* feat: sets up baseUrl and auth for the new client

* feat: gets the api base url from server context instead of the http client

* feat: gets the api base url from server context instead of the http client

* feat: allows undefined token for xhr requests

* feat: changes the response object to be either type T directly (to support @hey-api/client-fetch) or the given type if the response does not contain a 'data' object

* revert interface

* feat: creates an api return type to comply with @hey-api/client-fetch

* feat: maps T back to the data model for non-api types

* feat: simplify api response to return the promise you sent to it with an optional error object

* feat: moves http related modules to the core package

* feat: updates the required type of the client for the api interceptors

* docs: removes invalid property

* feat: adds request parameters to documents

* feat: adds request parameters to imaging

* feat: adds return type to item-server-data-source-base

* feat: adds request parameters to webhooks

* feat: adds request parameters to users

* feat: renames all `requestBody` to `body` to conform with new client-fetch

* feat: uses query to take parameters in

* feat: adds data source response to tree types

* feat: adds request parameters to templating

* feat: adds request parameters to templating

* feat: adds request parameters to telemetry

* feat: adds request parameters to tags

* feat: adds request parameters to examine management

* feat: adds request parameters to relations

* feat: adds request parameters to packages

* feat: catches new api errors that are direct problem details objects

* feat: adds default interceptor to handle Umb-Generated-Resource headers

* feat: uses an error interceptor specifically to catch errors to avoid overhead

* feat: adds request parameters to members

* Revert "feat: uses an error interceptor specifically to catch errors to avoid overhead"

This reverts commit 7ffb7b29bf.

* feat: adds request parameters to media

* feat: adds request parameters to log viewer

* feat: adds request parameters to languages

* feat: adds request parameters to health check

* feat: adds request parameters to oembed

* feat: adds request parameters to documents

* feat: adds request parameters to redirect management

* feat: adds request parameters to blueprints

* feat: adds request parameters to dictionary

* feat: adds request parameters to data types

* feat: adds request parameters to temporary file

* feat: instructs delete methods to return an unknown value

* feat: allows default value to be unknown

* feat: adds request parameters to culture

* chore: import path

* feat: adds correct models to mocks

* feat: adds correct models to installer and upgrader

* feat: adds correct models to mocks

* chore: forgot to move ignore line

* chore: ignores generated files in eslint

* chore: removes old generated files

* feat: moves network connection status manager back into the main app to avoid imports from core

* chore: update imports

* feat: generate API for login screen without relying on the backoffice

* feat: uses the generated models on the login screen

* feat: sets 'credentials' to 'include' and adds it back to openapiconfiguration to avoid a breaking change

* adds back in commands moved to a workspace

* chore: vscode workspace settings formatted and useFlatConfig added for better compatibility
2025-04-14 10:21:42 +02:00
684790df70 Chore: Add script to check for "illegal" imports (#18992)
* stop webhook module from importing itself

* wip script to list all module imports from a folder

* Update package.json

* fix ufm

* fix tip tap

* order by name

* fix stylesheet module

* fix self import

* fix self import

* pass folder as a variable

* implement folder variable

* allow to pass module name + prettify log output

* check for imports from core to packages and report error

* add comments

* run as part of test

* Update package.json

* add threshold

* Update index.js

* add report of module self imports

* Update index.js

* Update index.js

* Update src/Umbraco.Web.UI.Client/devops/module-dependencies/index.js

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* remove self imports in /extension-api

* fix order

* fix self imports

* fix self import

* fix self imports

* fix self imports

* fix collection self import

* fix self imports

* fix self import

* Update collection-pagination.element.ts

* Update entity-action.extension.ts

* fix self imports

* lower threshold

* fix self imports

* fix self imports

* fix self imports

* fix merge

* fix tree self imports

* Update sort-children-of-modal.element.ts

* Update section.context.ts

* change threshold

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-04-14 07:55:20 +00:00
16ee7227ae Feature: Document Property Value Permission (#18997)
* add property visibility state manager

* implement in structure manager

* filter properties based on visibility

* wip document type structure permissions

* rename

* register entity permission for document type property

* add entity permission for media type property

* pass fallback permissions to document granular permissions

* set as preset

* clean up

* wip document type property picker

* add preset value

* Update input-document-type-structure-granular-user-permission.element.ts

* move files

* rename

* Update input-document-value-granular-user-permission.element.ts

* remove temp test

* Update manifests.ts

* remove unused

* Update input-document-value-granular-user-permission.element.ts

* rename see permission + add write permission

* fix missing type

* require property type unique

* add unique to property type

* rename to property type

* map to unique

* deprecate id on property type

* return unique from property picker

* more explicit naming

* use type

* render detail

* Update input-document-value-granular-user-permission.element.ts

* wip modal flow

* clean up

* add headlines

* hide actions

* pass preset value

* add edit permission method

* include property in permission name

* add read and write managers

* implement read and write state managers

* Update content-type-structure-manager.class.ts

* enforce property permissions

* Storage for granular permissions at property type level

* add guards

* make variant property version

* Rename server models to include "property"

* generate server types

* add permissionType to model

* add mappers to user group permission data

* add mapper to current user permission data

* destroy

* clear state

* use permission type for guard check

* add permission type

* require specific permission type

* use correct schema type

* add mappings

* clean up

* log errors

* fix mapping

* null check for icon

* use fallback if there is no forDataModel

* add translations

* sort group alphabetically

* add empty state for no verbs

* organize folders

* always require unique and variant id

* Allow storing empty lists of verbs

* pass variant id to all states

* Remove empty verbs

* add alias to name

* prevent picking the same property type multiple times

* fix lint errors

* fix create state by observing variant options

* move to workspace context

* Update document-property-value-user-permission.workspace-context.ts

* Update content-editor-properties.element.ts

* clean up

* Rename models (last time, promise!)

* Add migration for default document property value permissions

* generate new server models

* update after model changes

* Correct the default permission identifiers

* Add default permissions to newly created DBs

* Add validation and clean-up

* rename to visibility state

* rename to view

* add helpers

* apply to blocks

* Update document-property-value-user-permission.workspace-context.ts

* disable view and write state by default

* add tests for start and stopping a state

* throw errors if adding to a state that is not running

* export consts

* export consts

* fix circular

* fix circular

* set the entity type when setting values

* only apply for block in document values

* split logic

* start states for document blocks

* only apply states when state is running

* Fixed typos in test method names.

* add readonly type

* Enforce: AllowEditInvariantFromNonDefault configuration (#18758)

* add read only state

* handle read only property state in properties element

* prevent editing shared props on non default

* enforce configuration

* clean up

* set variant id

* move to property module

---------

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>

* remove unnecessary messages

* make sure to destroy consumer

* Thoughts as TODO

* use Entry type

* use Entry type

* get rid of things not yet released

* clean up

* use generic methods

* TODO comment

* use generic observable

* catch if not found

* move variant id out of property type

* mega refactor temp commit

* Guard Manager

* set readOnly as a property on property editors

* further rename

* remove property state managers

* revert state manager

* fix sorting rule

* mega rename and correction

* refactor properties elements

* todo note

* clean up

* impl

* mega refactor moving permission guards to workspace

* rename

* type change

* rearrange

* correct import

* fix tests

* correct tests

* reset viewGuards block

* type correction

* refactor read only for user permissions setting

* todo note

* align property element

* await promise

* impl view guard property filtering

* correct const name

* fix fallback user permissions in mock data

* correct property type id mock data

* toggle permissions example

* complex permission

* Move migration to 16.0.

* rename fallBackToDisallowed to fallbackToNotPermitted

* clean up setReadOnlyStateForUserPermission

* capital o

* align read only naming

* rename method

* add js docs

* remove unused

* correct method name

* add js docs

* add js docs

* camel case function

* fix eslint problems

* camelcase const

* align method names

* remove unused

* fix host

* fix spelling mistake

* align naming

* fix spelling mistake

* add alias

* use read only state methods

* camel case function

* correct method name

* add js docs

* camelcase function

* camel case function

* align method names

* change method name wording

* Include document property value permissions in the current user's aggregated permissions.

* use is read only

* delete unused

* fix implementation of AllowEditInvariantFromNonDefault

* don't know what is happening here. Local is it lower on github it is higher

* Update document-workspace.context.ts

* revert to v16 dev

* simplify if statement

* make it explicit that these are ui only permissions

* add action label for read

* remove duplicates

* use read instead of browse

* align description

* use document instead of node

* make the base class abstract

* extend in test

* Update guard.manager.base.test.ts

* fix example

* style adjustment

* group styling

* refactor guard rule resolving

* remove imports

* remove console.log

* improve disconnected context consumer rejection message

* fix publishableVariantsFilter

* Update document-workspace.context.ts

---------

Co-authored-by: Mads Rasmussen <madsr@hey.com>
Co-authored-by: kjac <kja@umbraco.dk>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2025-04-11 14:16:59 +02:00
Niels LyngsøandGitHub 9e9c8c986c set working directory (#18995) 2025-04-11 09:09:45 +00:00
Niels LyngsøandGitHub 3210c304fe fix appending to a froozen object (#19003) 2025-04-11 10:33:21 +02:00
Niels LyngsøandGitHub 63f2fabb5f clean up unnessecary redirect code (#19007) 2025-04-11 07:44:39 +00:00
Andy ButlandandGitHub 21283245f1 Merge pull request #18993 from umbraco/v16/merge-from-15
Merges v15/dev to v16/dev.
2025-04-10 10:28:50 +02:00
Andy Butland b02b201cab Re-applied obsoletions to tracked references repository.
Re-applied modal handling for rollback.
2025-04-10 09:52:48 +02:00
Andy Butland 0c2485adf9 Post-merge fixes. 2025-04-10 07:16:00 +02:00
Andy Butland 1bb2837254 Post-merge fixes. 2025-04-10 07:12:34 +02:00
Andy Butland 0281d800d0 Post-merge fixes. 2025-04-10 07:04:29 +02:00
Andy Butland ecbfc72323 Merge branch 'v15/dev' into v16/merge-from-15
# Conflicts:
#	src/Umbraco.Cms.Api.Management/Controllers/PublishedCache/RebuildPublishedCacheController.cs
#	src/Umbraco.Cms.Api.Management/Factories/UserPresentationFactory.cs
#	src/Umbraco.Core/Persistence/Repositories/ITrackedReferencesRepository.cs
#	src/Umbraco.Core/Services/ContentEditingService.cs
#	src/Umbraco.Core/Services/DataTypeService.cs
#	src/Umbraco.Core/Services/IContentEditingService.cs
#	src/Umbraco.Core/Services/IDataTypeService.cs
#	src/Umbraco.Core/Services/ITrackedReferencesService.cs
#	src/Umbraco.Core/Services/RelationService.cs
#	src/Umbraco.Core/Services/TrackedReferencesService.cs
#	src/Umbraco.Infrastructure/Examine/Deferred/DeliveryApiContentIndexHandleContentTypeChanges.cs
#	src/Umbraco.Infrastructure/Examine/DeliveryApiIndexingHandler.cs
#	src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TrackedReferencesRepository.cs
#	src/Umbraco.Web.UI.Client/src/external/backend-api/src/sdk.gen.ts
#	src/Umbraco.Web.UI.Client/src/mocks/data/document-blueprint/document-blueprint.data.ts
#	src/Umbraco.Web.UI.Client/src/mocks/data/document/document.db.ts
#	src/Umbraco.Web.UI.Client/src/packages/core/router/modal-registration/modal-route-registration.controller.ts
#	src/Umbraco.Web.UI.Client/src/packages/core/router/route/route.context.ts
#	src/Umbraco.Web.UI.Client/src/packages/core/router/route/route.interface.ts
#	src/Umbraco.Web.UI.Client/src/packages/core/router/route/router-slot.element.ts
#	src/Umbraco.Web.UI.Client/src/packages/core/router/router-slot/model.ts
#	src/Umbraco.Web.UI.Client/src/packages/data-type/reference/repository/data-type-reference.server.data.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/repository/document-publishing.server.data-source.ts
#	src/Umbraco.Web.UI.Client/src/packages/documents/documents/rollback/entity-action/rollback.action.ts
#	tests/Umbraco.Tests.AcceptanceTest/package-lock.json
#	tests/Umbraco.Tests.AcceptanceTest/package.json
#	tests/Umbraco.Tests.Common/Builders/UserGroupBuilder.cs
#	tests/Umbraco.Tests.Integration/Umbraco.Core/Services/TemporaryFileServiceTests.cs
2025-04-09 22:45:56 +02:00
Kenn JacobsenandGitHub ff58fbd2b1 Make it possible to disable Examine indexes by composition (#18988) 2025-04-09 18:13:18 +02:00
Jacob OvergaardandGitHub 4778501a6e V16: Installer does not proceed from last step (#18981)
* fix: moves logic from installation step to context in order not to destroy the host for the request

* chore: removes console.warn
2025-04-09 16:40:54 +01:00
10e56a52f3 V16: Removes TinyMCE (server-side) (#18913)
* Create new migration

* Migrate UI to tiptap

* remember to overwrite toolbar

* Add setting to disable migration

* Add default extensions when migrating

* Remove places where editorUI alias is used

* Remove more tinyMCE stuff

* Make sure that blocks also works

* Reverted files from bad merge

* bring back value converters

* Class name casing

---------

Co-authored-by: leekelleher <leekelleher@gmail.com>
2025-04-09 10:00:59 +00:00
+8 3bd66b89e1 Merge branch 'v15/dev' into v16/dev (#18971)
* Only prevent the unpublish or delete of a related item when configured to do so if it is related as a child, not as a parent (#18886)

* Only prevent the unpubkish or delete of a related item when configured to do so if it is related as a child, not as a parent.

* Fixed incorect parameter names.

* Fixed failing integration tests.

* Use using variable instead to reduce nesting

* Applied suggestions from code review.

* Used simple using statement throughout RelationService for consistency.

* Applied XML header comments consistently.

---------

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

* Feature: highlight invariant doc with variant blocks is unsupported (#18806)

* mark variant blocks in invariant docs as invalid

* implement RTE Blocks

* Fix pagination for users restricted by start nodes (#18907)

* Fix pagination for users restricted by start nodes

* Default implementation to avoid breakage

* Review comments

* Fix failing test

* Add media start node tests

* Fix issue preventing blueprint derived values from being scaffolded (#18917)

* Fix issue preventing blueprint derived values from being scaffolded.

* fix manipulating frooen array

* compare with variantId as well

---------

Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>

* ci: add Azure Static Web Apps workflow file
on-behalf-of: @Azure opensource@microsoft.com

* ci: add Azure Static Web Apps workflow file
on-behalf-of: @Azure opensource@microsoft.com

* ci: add Azure Static Web Apps workflow file
on-behalf-of: @Azure opensource@microsoft.com

* Remove admin permission on user configuration, allowing users with user section access only to manaage users and groups. (#18848)

* Tiptap RTE: Style Menu extension kind (#18918)

* Adds 'styleMenu' Tiptap toolbar extension kind

* Adds icons for `<h4>` and `<p>` tags

* Adds commands to HTML Global Attributes extension

for setting the `class` and `id` attributes.

* Renamed "default-tiptap-toolbar-element.api.ts" file

The "element" part was confusing.

* Toolbar Menu: uses correct `item` value

* Cascading Menu: adds localization for the label

* Adds `label` attribute to UUI components

for accessibility.

* Toolbar Menu: uses correct `appearance` value

* Removed unrequired `api` from Style Select

* Destructs the `item.data` object

* Ensure has children reflects only items with folder children when folders only are queried. (#18790)

* Ensure has children reflects only items with folder children when folders only are queried.

* Added supression for change to integration test public code.

---------

Co-authored-by: Migaroez <geusens@gmail.com>

* Only apply validation on content update to variant cultures where the editor has permission for the culture (#18778)

* Only apply validation on content update to variant cultures where the editor has permission for the culture.

* Remove inadvertent comment updates.

* Fixed failing integration test.

* Adds ancestor ID details on document tree and collection responses (#18909)

* Populate ancestor keys on document tree response items.

* Populate ancestor keys on document collection response items.

* Update OpenApi.json

* Use array of objects rather than Ids for the ancestor collection.

* Update OpenApi.json.

* Move publish with descendants to a background task with polling (#18497)

* Use background queue for database cache rebuild and track rebuilding status.

* Updated OpenApi.json and client-side types.

* Updated client to poll for completion of database rebuild.

* Move IBackgroundTaskQueue to core and prepare publish branch to run as background task.

* Endpoints for retrieval of status and result from branch publish operations.

* Poll and retrieve result for publish with descendants.

* Handled issues from testing.

* Rework to single controller for status and result.

* Updated client side sdk.

* OpenApi post dev merge gen

---------

Co-authored-by: Migaroez <geusens@gmail.com>

* Clear roots before rebuilding navigation dictionary (#18766)

* Clear roots before rebuilding navigation dictionary.

* Added tests to verify fix.

* Correct test implementation.

* Convert integration tests with method overloads into test cases.

* Integration test compatibility supressions.

* Fixes save of empty, invariant block list on variant content. (#18932)

* remove unnecessary code (#18927)

* V15/bugfix/fix route issue from 18859 (#18931)

* unique check

* unique for workspace empty path

* more unique routes

* Bump vite from 6.2.3 to 6.2.4 in /src/Umbraco.Web.UI.Client

Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.2.3 to 6.2.4.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v6.2.4/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.2.4/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 6.2.4
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>

* removes autogenerated workflows

* make getHasUnpersistedChanges public (#18929)

* Added management API endpoint, service and repository for retrieval of references from the recycle bin (#18882)

* Added management API endpoint, service and repository for retrieval of references from the recycle bin.

* Update src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/ReferencedByDocumentRecycleBinController.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Removed unused code.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Updated management API endpoint and model for data type references to align with that used for documents, media etc. (#18905)

* Updated management API endpoint and model for data type references to align with that used for documents, media etc.

* Refactoring.

* Update src/Umbraco.Core/Constants-ReferenceTypes.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fixed typos.

* Added id to tracked reference content type response.

* Updated OpenApi.json.

* Added missing updates.

* Renamed model and constants from code review feedback.

* Fix typo

* Fix multiple enumeration

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: mole <nikolajlauridsen@protonmail.ch>

* Skip lock tests

* Look-up redirect in content finder for multi-lingual sites using path and legacy route prefixed with the integer ID of the node with domains defined (#18763)

* Look-up redirect in content finder for multi-lingual sites using path and legacy route prefixed with the integer ID of the node with domains defined.

* Added tests to verify functionality.

* Added reference to previous PR.

* Referenced second PR.

* Assemble URLs for all cultures, not just the default.

* Revert previous update.

* Display an original URL if we have one.

* Bump vite from 6.2.4 to 6.2.5 in /src/Umbraco.Web.UI.Client

Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.2.4 to 6.2.5.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v6.2.5/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.2.5/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 6.2.5
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>

* Add raw value validation to multiple text strings property editor (#18936)

* Add raw value validation to multiple text strings property editor

* Added additional assert on unit test and comment on validation logic.

* Don't remove items to obtain a valid value

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Integration tests for content publishing with ancestor unpublished (#18941)

* Resolved warnings in test class.

* Refactor regions into partial classes.

* Aligned test names.

* Variable name refactoring.

* Added tests for unpublished paths.

* Adjust tests to verify current behaviour.

* Cleaned up project file.

* fix circular icon import (#18952)

* remove segment toggle for elements (#18949)

* Fix modal route registration circular import (#18953)

* fix modal route registration circular import

* Update modal-route-registration.controller.ts

* V15/fix/18595 (#18925)

* fix for #18595

* updates the en.ts

* Avoid unneeded Dictionary operations (#18890)

* Avoid some heap allocations

* Remove unneeded double seek

* Avoid allocating new empty arrays, reuse existing empty array

* Avoid allocating strings for parsing comma separated int values (#18199)

* Data type References UI: Workspace + Delete (#18914)

* Updated management API endpoint and model for data type references to align with that used for documents, media etc.

* Refactoring.

* Update src/Umbraco.Core/Constants-ReferenceTypes.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fixed typos.

* generate server models

* add extension slot

* register data type reference info app

* add reference data mappers

* Added id to tracked reference content type response.

* Updated OpenApi.json.

* Added missing updates.

* generate new models

* update models

* register ref item

* remove debugger

* render types

* register member type property type ref

* register media type property type ref

* Renamed model and constants from code review feedback.

* register reference workspace info app kind

* use kind for document references

* use kind for media references

* use kind for member references

* use deleteWithRelation kind when deleting data types

* fix manifest types

* fix types

* Update types.gen.ts

* update code to fit new server models

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Feature: discard changes for block workspace (#18930)

* make getHasUnpersistedChanges public

* Discard changes impl for Block Workspace

* fix 18367 (#18956)

* Merge commit from fork

* Prevent path traveral vulnerability with upload of temporary files.

* Used BadRequest instead of NotFound for invalid file name response.

* V15 QA Fixing the failing media acceptance tests (#18881)

* Fixed the function name due to test helper changes

* Updated assertion steps due to UI changes

* Added more waits

* Bumped version

* Increase timeout

* Reverted

---------

Co-authored-by: Andreas Zerbst <73799582+andr317c@users.noreply.github.com>

* V15 QA added clipboard test for not being able to copy to root when block is not allowed at root (#18937)

* Added clipboard test

* Bumped version

* Updated to use the name

* Run all tests on the pipeline

* Reverted command

* build: adjusts circular ref number to 4

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
Co-authored-by: mole <nikolajlauridsen@protonmail.ch>
Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
Co-authored-by: Lee Kelleher <leekelleher@users.noreply.github.com>
Co-authored-by: Migaroez <geusens@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>
Co-authored-by: Mads Rasmussen <madsr@hey.com>
Co-authored-by: Jacob Welander Jensen <64834767+Welander1994@users.noreply.github.com>
Co-authored-by: Henrik <hg@impact.dk>
Co-authored-by: Sebastiaan Janssen <sebastiaan@umbraco.com>
Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>
Co-authored-by: Andreas Zerbst <73799582+andr317c@users.noreply.github.com>
2025-04-09 09:58:01 +02:00
Mads RasmussenandGitHub 10a70a8397 Move router-slot exports to @umbraco-cms/backoffice/router (#18962)
* move router-slot files to core/router

* remove external module

* generate tsconfig

* fix imports

* ignore lint errors

* ignore diff package
2025-04-09 08:45:20 +02:00
Mads RasmussenandGitHub af07c42120 Remove external base64-js module (#18969)
* move base64 folder into openid

* remove from package.json and tsconfig

* import from local module
2025-04-08 12:47:39 +00:00
64e8f34f0f V16: Adds server context to store information about paths (#18967)
* fix: straightens out unnecessary imports of components and re-exports them appropriately

* fix: imports repository from file directly

* feat: introduces a "server" package and moves UmbAppContext logic to UmbServerContext

* feat: updates all cases of `UmbAppContext` -> `UmbServerContext`

* build: adjusts MAX_CIRCULAR_DEPENDENCIES from 6 to 3

* Update src/Umbraco.Web.UI.Client/devops/circular/index.js

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* feat: removes unused interface

* build: adds server bundle to vite

* build: vite should build index barrel

* build: readjust to 5 to account for previous failed build

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-04-08 11:20:03 +00:00
Mads RasmussenandGitHub 6aa471479e Internalize uuid package (#18955)
* move uuid to core package package.json

* install

* remove external + generate tsconfig

* import from local node_modules

* temp accept uuid as import
2025-04-08 10:44:10 +00:00
Jacob Overgaard 8178dba674 build: set MAX_CIRCULAR_DEPENDENCIES to 6 2025-04-08 10:16:09 +02:00
Jacob Overgaard 385a8fecba build: adds another fail scenario to the circular checker if it encounters fewer dependencies than anticipated 2025-04-08 10:16:09 +02:00
Jacob Overgaard 84d8736b90 fix: removes circular dependency by stopping module from importing from itself 2025-04-08 10:16:09 +02:00
Jacob OvergaardandGitHub fd1761dcc1 V16: API error interceptor should return early if it will not execute (#18963)
* fix: resolves an unintended circular reference based on files being moved around

introduced in #18939

* fix: improves error handling to return early if interceptor does not catch a 500

* fix: adds try/catch around json parsing
2025-04-08 09:12:52 +01:00
Jacob Overgaard 6630220961 build: adjust number of max circulars to 7 2025-04-08 09:11:10 +02:00
Jacob OvergaardandGitHub e1f9219b93 V16: Updates openapi-ts client and deprecates tryExecuteAndNotify (#18939)
* build(deps-dev): bump @hey-api/openapi-ts from 0.61.3 to 0.66.1

* docs: adds information on how to configure new fetch-client

* feat: adds preliminary umb-prefixed error types

* fix: uses correct import path

* docs: jsdocs

* feat: optimises error reporting

* feat: maps functions into separate controllers

* feat: adds color to peek notification

* feat: moves the internal api interceptors controller and adds more interceptors

* feat: adds host to params

* feat: marks certain functions as deprecated

* feat: maps api errors to UmbErrors

* chore: removes deprecation console logs

* chore: allows any

* feat: maps xhr errors to umb errors

* feat: adds host to tryExecute

* feat: adjusts deprecation notifices and checks

* chore: adjusts deprecation notices

* chore: add .warn() to deprecation

* feat: updates login app repository

* feat: changes all `tryExecuteAndNotify` calls to `tryExecute`

* feat: copies helper functions to resources package and deprecates in notification package

* chore: removes unused imports

* feat: adds exports

* chore: removes controller that is no longer useful

* feat: marks _peekError as protected

* feat: adds support for error notifications (and to ignore them) and to cancel an ongoing request

* feat: eliminates duplicated logic in xhr controller

* feat: touches only the cloned response to allow interceptors downstream to unwrap the body

* feat: stores the host for async context

* feat: disables automatic notifications for validation data source

* feat: disables notifications where they are otherwise handled or ignored

* feat: removes deprecated code

* feat: eliminates a controller that only had a static method

* docs: adds jsdocs

* docs: adds jsdocs

* docs: adds jsdocs

* feat: returns umb-notifications response without modifying it

* feat: eliminates dependency on generated `ProblemDetails` type

* feat: eliminates dependence on generated `ApiError` type

* feat: eliminates dependence on generated `CancelError` type

* fix: removes dependency on CancelablePromise
2025-04-07 22:54:51 +01:00
Mads RasmussenandGitHub 6a36a797ad Fix confirm modal circular import (#18951)
* fix circular import for confirm modal

* Update open-modal.controller.ts
2025-04-07 11:40:57 +02:00
Lee KelleherandGitHub dc87cf800f Reverts removal of RTE Block Type Configuration property-editor (#18933)
I'd accidentally removed this in PR #18889.
Adding it back in to the "block-rte" package.
2025-04-04 14:04:45 +02:00
e0341f9d10 V16: Migrate TinyMCE data type configuration to Tiptap (#18843)
* Create new migration

* Migrate UI to tiptap

* remember to overwrite toolbar

* Add setting to disable migration

* Add default extensions when migrating

* Make sure that blocks also works

* Renamed classes to reference TinyMCE migration

* Defaults TinyMCE toolbar mapping to `null`

if we can't map to a known Tiptap toolbar extension (manifest alias),
then it may cause an issue with the toolbar rendering.

---------

Co-authored-by: leekelleher <leekelleher@gmail.com>
2025-04-03 18:52:30 +00:00
Lee KelleherandGitHub 8754caa06f V16: Stylesheet Create Options (#18911)
* Adds `entityCreateOptionAction` extensions for Stylesheets

* Deprecates `umb-stylesheet-create-options-modal` and token.

* Corrected localization labels

to resolve failing acceptance test.

* Updated @umbraco/playwright-testhelpers to 16.0.0

* Removed redundant RTE Stylesheet acceptance tests
2025-04-03 16:30:21 +00:00
Jacob OvergaardandGitHub 7d7db6bb2b V16: Vite development optimizations (#18915)
* feat: resolve TODO by removing quiet option

* feat: exclude ./src/mocks from production build

* feat: load only msw when running through vite

* feat: optimise load order

* feat: handles mocked logos with virtual path

* feat: loads mocked service worker from virtual path

* feat: loads assets from virtual path

* feat: forces MSW=on for the static build

* build: adds storybook workflow copied over from the old backoffice repository

* build: limits where the build runs

* build: adds workflow to build a static version of the backoffice upon request

* build: excludes the `/umbraco/backoffice/assets` folder from navigation fallback just in case

* build: triggers run when the workflow file itself changes

* build: triggers run when package.json changes

* build: marks the 'contrib' branch as production

* build: activates static builds on preview/* labels

* build: bumps github checkout version

* build: updates key for backoffice web app

* build: updates key for storybook

* build: disables build for release branches to preseve on preview environments
2025-04-03 15:15:04 +01:00
Lee KelleherandGitHub c3709de1d3 V16: Removes RTE Stylesheets (client-side) (#18908)
* Removed Stylesheet RTE workspace view

* Removed Stylesheet RTE Rule components

* Removed Stylesheet RTE Rule Manager

* Removed Stylesheet RTE localizations

* Removed Stylesheet RTE mock data

* Aligns the Stylesheet code editor height

with the Scripts code editor.
2025-04-02 17:02:46 +02:00
7e46a1c148 V16: Removes TinyMCE (client-side) (#18889)
* Removed TinyMCE client-side code

* Replaces "MaxImageSizeConfiguration" with "Integer" property-editor

* Adds "Dimensions" property-editor

Promoted from TinyMCE package code.

* Updated Tiptap property-editor label

to remove the "[Tiptap]" suffix.

* Corrected Tiptap config localization keys

* Removed TinyMCE acceptance test

* Reverted Tiptap property-editor label

to add the "[Tiptap]" suffix back in.

---------

Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
2025-04-01 17:00:27 +02:00
Jacob Overgaard dbd9218c75 Merge branch 'v15/dev' into v16/dev 2025-04-01 14:03:40 +02:00
Jacob Overgaard d1ee95c7b1 Merge branch 'v15/dev' into v16/dev 2025-04-01 10:38:34 +02:00
Jacob Overgaard 7b4bfbb28e Merge branch 'v15/dev' into v16/dev 2025-04-01 10:31:59 +02:00
00ec63a966 Todo cleanup of abstract service being aware of implementation types (#18832)
Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>
2025-03-31 09:52:34 +00:00
Lee KelleherandGitHub 19123b4799 Removed deprecated methods from ITwoFactorLoginService (#18880) 2025-03-31 11:03:01 +02:00
Niels LyngsøandGitHub 3446b77d7d Feature: context consumer auto destroys if no callback + getContext options (#18835)
* consumer destroys when no callback

* getContext can be simplification

* JSDocs

* implement options to skipHost and pass context alias matches
2025-03-31 10:32:36 +02:00
Niels Lyngsø 1e5d29e667 Merge remote-tracking branch 'origin/v15/dev' into v16/dev
# Conflicts:
#	src/Umbraco.Core/Services/ITwoFactorLoginService.cs
#	src/Umbraco.Web.UI.Client/src/packages/media/dropzone/components/input-dropzone/input-dropzone.element.ts
#	src/Umbraco.Web.UI.Client/src/packages/media/dropzone/dropzone-manager.class.ts
2025-03-28 13:00:56 +01:00
Niels Lyngsø fdef134c3b lint fixes 2025-03-27 11:08:35 +01:00
Nhu DinhandNiels Lyngsø bcaaf5a1f4 V15 Added acceptance tests for data type default configuration (#18740)
* Added tests for Approved Color default configuration

* Updated tests for Approved Color configuration

* Added tests for ChecklboxList configuration

* Added tests for Data type default configuration - part 1

* Added tests for data type configuration and updated tests due to test helper changes

* Added more steps to verify the default configuration

* Added tests for the default configuration and refactoring code

* Added steps to verify the TinyMCE default configuration

* Bumped version

* Fixed tests due to test helper changes

* Make all Data Type tests run in the pipeline

* Updated assertion steps

* Fixed format

* Bumped version

* Bumped version

* Comment failing tests

* Reverted npm command
2025-03-27 10:58:58 +01:00
Niels LyngsøandNiels Lyngsø d438d79b8c lint corrections (#18833) 2025-03-27 10:58:58 +01:00
0c7202c6d9 Fix bug uploading an image via the Media Picker is no longer automatically selected (#18667)
* Fix bug uploading an image via the Media Picker is no longer automatically selected

* Update src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts

Co-authored-by: Bjarne Fyrstenborg <bjarne_fyrstenborg@hotmail.com>

* Update src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts

Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>

* remove submit modal

* fix: avoids overriding the dropzone manager as that does not work with inheritance

* fix: set disabling of folders correctly

---------

Co-authored-by: Lan Nguyen Thuy <lnt@umbraco.dk>
Co-authored-by: Bjarne Fyrstenborg <bjarne_fyrstenborg@hotmail.com>
Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com>
2025-03-27 10:58:58 +01:00
Nhu DinhandNiels Lyngsø 361c9d9f97 V15 QA Added acceptance tests for user group default configuration (#18800)
* Updated userGroup tests due to test helper changes

* Added tests for user group default configuration

* Bumped version

* Fixed due to test helper changes

* Reverted npm command
2025-03-27 10:58:58 +01:00
Mads RasmussenandNiels Lyngsø 678bce697b fix preset logic (#18815) 2025-03-27 10:58:58 +01:00
Kenn JacobsenandNiels Lyngsø b008afbb27 Obsolete a few unused things. (#18814) 2025-03-27 10:58:57 +01:00
Niels LyngsøandNiels Lyngsø 11479b22b3 implement validation context (#18808) 2025-03-27 10:58:57 +01:00
Andy ButlandandNiels Lyngsø 1c6b7698c8 Fixed issue where siblings of type at route are omitted from the result. (#18796) 2025-03-27 10:58:57 +01:00
Sven GeusensandGitHub 8c5fe3d52b removed syslib003 & syslib0051 obsoleted code dependencies (#18827)
Followed guidance in https://learn.microsoft.com/en-us/dotnet/fundamentals/syslib-diagnostics/syslibxxxx
2025-03-27 10:47:07 +01:00
Mads RasmussenandGitHub 26d66a815a Move public access files to member-public-access module (#18793)
* move to member package

* fix imports

* add module to build

* split types and consts

* export types

* add export type

* add import type
2025-03-26 08:26:18 +00:00
Niels LyngsøandGitHub d93b0002ba avoid destroying before promise has resolved. (#18811) 2025-03-26 09:25:04 +01:00
Niels Lyngsø 12f4c17f85 fix failing e2e test 2025-03-26 08:46:43 +01:00
Niels Lyngsø fd4585fba7 fix ts merge conflict 2025-03-26 08:24:52 +01:00
Andy Butland 7dc9cbd9b1 Merge branch 'v15/dev' into v16/dev
# Conflicts:
#	src/Umbraco.Cms.Api.Management/Factories/RelationTypePresentationFactory.cs
#	src/Umbraco.Core/Services/PropertyValidationService.cs
#	src/Umbraco.Web.UI.Client/utils/all-umb-consts/imports.ts
2025-03-25 17:56:50 +01:00
Mads RasmussenandGitHub f5c307b8f1 remove duplicate keys (#18787) 2025-03-25 09:41:50 +01:00
0b0a2dc251 Added v16 to run at midnight (#18785)
Co-authored-by: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com>
2025-03-25 11:06:33 +07:00
Niels LyngsøandGitHub 780f16e79b UX: Make discard changes button red (#18767)
* make discard button red

* change headline
2025-03-24 22:10:57 +01:00
Andy ButlandandGitHub fdea721a8e Move registration of delivery API component to infrastructure to resolve issue resolve it from controller. (#18777) 2025-03-24 13:25:06 +01:00
Niels Lyngsø 2fe83b5637 Merge branch 'v15/dev' into v16/dev
# Conflicts:
#	src/Umbraco.Core/Web/ICookieManager.cs
2025-03-21 19:42:15 +01:00
Lee KelleherandGitHub 9ee31367df V16: Removed deprecated client-side code (#18662)
* Removed duplicated "document-is-not-trashed.condition" code

* Removed deprecated code, marked for removal in Umbraco 15

(that we forgot about)

* Removed deprecated code, marked for removal in Umbraco 16

* Regenerated constants

* Reverted deletion
2025-03-21 18:56:52 +01:00
Andy ButlandandGitHub 825f791d01 Remove the non-controversial, straightforward obsoleted constructs for Umbraco 16 (#18661)
* Removed obsoletes from IConfigManipulator.

* Removed obsolete models builder extensions.

* Removed the obsolete ContentDashboardSettings.

* Removed the obsolete InstallMissingDatabase setting on GlobalSettings.

* Removed obsolete NuCache settings.

* Removed obsolete RuntimeMinificationSettings.

* Removed obsolete health check constant.

* Removed obsolete icon constant.

* Removed obsolete telemetry constant.

* Removed obsolete property and constructor on UmbracoBuilder.

* Removed obsolete constructor on AuditNotificationsHandler.

* Removed obsolete constructor on HTTP header health checks.

* Removed obsolete constructor on MediaFileManager.

* Removed obsolete GetDefaultFileContent on ViewHelper.

* Remove obsoleted methods on embed providers.

* Fix tests.

* Removed obsolete constructors on BlockEditorDataConverter.

* Removed obsolete SeedCacheDuration property on CacheSettings.

* Removed obsolete PublishCulture on ContentRepositoryExtensions.

* Removed obsolete MonitorLock.

* Removed obsolete synchronous HasSavedValues from IDataTypeUsageService and IDataTypeUsageRepository.

* Removed obsolete HasSavedPropertyValues from IPropertyTypeUsageService and IPropertyTypeUsageRepository.

* Removed obsolete methods in ITrackedReferencesService and ITrackedReferencesRepository.

* Removed obsolete DateValueEditor constructors.

* Removed obsolete GetAutomaticRelationTypesAliases.

* Removed obsolete constructor on TextOnlyValueEditor.

* Removed obsolete constructors on RegexValidator and RequiredValidator.

* Removed obsolete constructs on SliderValueConverter and TagsValueConverter.

* Removed obsolete GetContentType methods from IPublishedCache.

* Removed ContentFinderByIdPath.

* Removed obsolete constructor on DefaultMediaUrlProvider.

* Removed obsolete constructor on Domain.

* Removed obsolete constructor on PublishedRequest.

* Removed obsolete methods on CheckPermissions.

* Removed obsolete GetUserId from IBackOfficeSecurity.

* Removed obsolete methods on LegacyPasswordSecurity.

* Removed obsolete constructors on AuditService.

* Removed obsolete methods on IContentEditingService.

* Remove obsolete constructors and methods on ContentService/IContentService.

* Removed obsolete constructor in ContentTypeEditingService.

* Removed obsolete constructor in MediaTypeEditingService.

* Removed obsolete constructor in MemberTypeEditingService.

* Removed obsolete constructor in ContentTypeService.

* Removed obsolete constructors in ContentTypeServiceBase.

* Removed obsolete constructors and methods in ContentVersionService.

* Removed obsolete constructor in DataTypeUsageService.

* Removed obsolete constructor in DomainService.

* Removed obsolete constructor in FileService.

* Removes obsolete AttemptMove from IContentService.

* Removes obsolete SetPreventCleanup from IContentVersionService.

* Removes obsolete GetReferences from IDataTypeService.

* Removed obsolete SetConsentLevel from IMetricsConsentService.

* Removed obsolete methods from IPackageDataInstallation.

* Removed obsolete methods from IPackagingService.

* Removed obsolete methods on ITwoFactorLoginService.
Removed obsolete ITemporaryMediaService.

* Removed obsolete constructor from MediaService, MemberTypeService and MediaTypeService.

* More obsolete constructors.

* Removed obsoleted overloads on IPropertyValidationService.

* Fixed build for tests.

* Removed obsolete constructor for PublicAccessService, UserService and RelationService.

* Removed GetDefaultMemberType.

* Removed obsolete user group functionality from IUserService.

* Removed obsolete extension methods on IUserService.

* Removed obsolete method from ITelemetryService.

* Removed obsolete UdiParserServiceConnectors.

* Removed obsolete method on ICookieManager.

* Removed obsolete DynamicContext.

* Removed obsolete XmlHelper.

* Fixed failing integration tests.

* Removed obsoletes in Umbraco.Cms.Api.Common

* Removed obsoletes in Umbraco.Cms.Api.Delivery

* Removed obsoletes in Umbraco.Cms.Api.Management

* Removed obsoletes in Umbraco.Examine.Lucene

* Removed obsoletes in Umbraco.Infrastructure

* Fix failing delivery API contract integration test.

* Made integration tests internal.

* Removed obsoletes from web projects.

* Fix build.

* Removed Twitter OEmbed provider

* Removed obsolete constructor on PublishedDataType.

* Removed obsolete constructors on PublishedCacheBase.

* Removed the obsolete PropertyEditorTagsExtensions.

* Removed obsoletion properties on configuration response  models (#18697)

* Removed obsolete methods from server-side models.

* Update client-side types and sdk.

* Update client-side files.

* Removed obsoletion of Utf8ToAsciiConverter.ToAsciiString overload. (#18694)

* Removed obsolete method in UserService. (#18710)

* Removed obsoleted group alias keys from being publicly available. (#18682)

* Removed unneceessary ApiVersion attribute.

* Clean-up obsoletions on MemberService (#18703)

* Removed obsoleted method on MemberService, added future obsoletion to interface and updated all callers.

* Removed obsoletion on member service method that's not obsolete on the interface.
2025-03-21 17:02:31 +00:00
Jacob Overgaard fb3a56a240 Merge branch 'v15/dev' into v16/dev 2025-03-21 12:25:41 +01:00
Jacob Overgaard 0d1afcf3c7 Merge branch 'v15/dev' into v16/dev 2025-03-21 11:08:31 +01:00
Jacob Overgaard a82e0ca23a fix: add nullability check to modalManager 2025-03-21 11:07:59 +01:00
Andy Butland 663be397dc Merge branch 'v15/dev' into v16/dev 2025-03-21 09:11:06 +01:00
kjac 83aca5aa6e Merge branch 'v15/dev' into v16/dev 2025-03-20 14:52:35 +01:00
Niels Lyngsø 991b8bfb37 Merge branch 'v15/dev' into v16/dev 2025-03-18 14:42:44 +01:00
Niels Lyngsø 6c9ff96972 fix UmbContextConsumer 2025-03-18 14:41:01 +01:00
Niels Lyngsø 0d4acb440d fix context consumer test 2025-03-18 10:54:07 +01:00
Andy Butland 3f5898ba95 Merge branch 'v15/dev' into v16/dev 2025-03-17 15:49:20 +01:00
Niels Lyngsø 939552e9f1 Merge branch 'v15/dev' into v16/dev 2025-03-17 11:09:30 +01:00
Niels Lyngsø 0a7d0a8f8b Merge branch 'v15/dev' into v16/dev
# Conflicts:
#	src/Umbraco.Web.UI.Client/package-lock.json
#	src/Umbraco.Web.UI.Client/package.json
#	version.json
2025-03-17 11:08:27 +01:00
Niels LyngsøandGitHub b9eb988d29 V16/feature: get context resolves in undefined if not found (#18611)
* implement getContext rejecter + allow for resolving in undefined

* fix test

* timeout concept

* adjustments

* adapt implementation

* ability to set timeoutFrame for faster test

* update

* make sure provider only provides when connected

* make sure action apis can fail without resolving

* make sure to await the arrival of the UMB_AUTH_CONTEXT

* no need to be async

* consume to stay up to date

* one rendering cycle approach

* adjusting context consumption part 1

* implementation adjustments

* correction patch 2

* correction patch 3

* correction batch 4

* correction batch 5

* correction batch 6
2025-03-14 14:06:45 +00:00
Andy Butland 9beb679dbf Merge branch 'v15/dev' into v16/dev 2025-03-13 10:43:42 +01:00
Andy Butland 9b3da86192 Merge branch 'v15/dev' into v16/dev 2025-03-12 12:29:09 +01:00
1d5a4dfa3a Chore: deprecate UmbPropertyValueChangeEvent for v.16 (#18455)
* deprecate

* fix import

---------

Co-authored-by: Mads Rasmussen <madsr@hey.com>
2025-03-11 13:51:49 +01:00
mole 9d7c2d4a82 add async keyword 2025-03-11 12:46:21 +01:00
Mads Rasmussen 0e561da146 Merge branch 'v15/dev' into v16/dev 2025-03-11 11:43:07 +01:00
Niels Lyngsø c8eb4f1d53 Merge branch 'v15/dev' into v16/dev 2025-03-10 16:54:38 +01:00
Niels Lyngsø 98bf623721 Merge branch 'v15/dev' into v16/dev
# Conflicts:
#	src/Umbraco.Cms.Api.Management/Controllers/PublishedCache/RebuildPublishedCacheController.cs
#	src/Umbraco.Core/Configuration/Models/ContentSettings.cs
2025-03-09 21:28:23 +01:00
13c788d6ec Add AsyncMigrationBase, update base classes and call async methods (#17057)
* Add AsyncMigrationBase, update base classes and call async methods

* Restored and obsoleted synchronous execution on IMigrationPlanExecutor.

* Resolved breaking changes.

* Fixed build.

* Further obsoletes.

* Fix build against v16/dev.

* Removed and obsolete code related to post-migrations.

* Removed service registration of unused interface.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2025-03-03 11:54:22 +01:00
780184e553 Remove UmbracoPath setting (#16037)
* Use require modifier instead of setting null-suppressed default values

* Only remove read-only properties when IgnoreReadOnlyProperties is set

* Obsolete UmbracoPath property and remove work-around for obsolete setter

* Remove UmbracoPath setting and use constant instead

* Remove usage of GetBackOfficePath

* Add IHostingEnvironment.GetBackOfficePath() extension method

* Add Constants.System.UmbracoPathSegment constant

* Update Constants.System XML docs

* Replace StringBuilder with string interpolation

Co-authored-by: Nuklon <Nuklon@users.noreply.github.com>

* Fix syntax error

* Removed uses of obsoletes.

* Further obsolete messages.

* Cleaned up usings.

* Update src/Umbraco.Infrastructure/Install/FilePermissionHelper.cs

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

---------

Co-authored-by: Nuklon <Nuklon@users.noreply.github.com>
Co-authored-by: Andy Butland <abutland73@gmail.com>
2025-03-03 07:38:30 +01:00
561d871677 Remove await Task.FromResult() and unnecessary async modifiers (#16535)
* Remove await Task.FromResult and unnecessary async modifiers

* Remove usage of await Task.WhenAll() to avoid deadlocks

* Fix code formatting

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2025-03-03 06:47:37 +01:00
Andy Butland 064a71240e Merge branch 'v15/dev' into v16/dev 2025-03-03 06:43:17 +01:00
Andy Butland 678e942a2e Merge branch 'v15/dev' into v16/dev 2025-02-21 10:01:15 +01:00
Andy Butland a76344ec4c Merge branch 'v15/dev' into v16/dev
# Conflicts:
#	src/Umbraco.Core/Configuration/Models/RuntimeSettings.cs
2025-02-20 09:33:29 +01:00
Jacob OvergaardandGitHub e77bac3088 V16: Allow MaxRequestLength to be specified as a long (#18141)
* feat: allows MaxFileSize to be specified as 64-bit rather than 32-bit to be able to accept larger files

the underlying kestrel architecture already accepts a `long` in ConfigureKestrelServerOptions.cs

* chore: removes unused configuration option

* chore: generate OpenApi.json
2025-01-29 06:31:24 +01:00
Jacob Overgaard 27afb3f0f3 Merge branch 'v15/dev' into v16/dev 2025-01-28 10:29:30 +01:00
822a8cc2f1 v16: Start removing scope references (#18074)
* Start removing scope references

* Update src/Umbraco.Infrastructure/Examine/UmbracoIndexConfig.cs

Co-authored-by: Andy Butland <abutland73@gmail.com>

* Make test-only ctor internal

* Fix tests

* Dont treat warnings as errors

* Disable package validation, as this is a major

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
2025-01-22 21:19:12 +01:00
Jacob Overgaard 32792b4ba4 feat: removes deprecated setting HideBackOfficeLogo 2025-01-22 14:21:54 +01:00
Jacob Overgaard 849b98cbaf bump version to 16.0.0-rc 2025-01-22 14:21:19 +01:00
Jacob Overgaard 0b3836456e Merge branch 'v15/dev' into v16/dev 2025-01-22 14:20:34 +01:00
0d1cdd1bb4 Refactor setting arrays to sets (#16058)
Co-authored-by: Bjarke Berg <mail@bergmania.dk>
2024-12-02 15:50:23 +01:00
2060 changed files with 37915 additions and 53291 deletions
+1 -1
View File
@@ -61,7 +61,7 @@ This guide describes each step to make your first contribution:
## Further contribution guides
- [Before you start](contributing-before-you-start.md)
- [Finding your first issue: Up for grabs](contributing-first-issue.md)
- [Finding your first issue: Up for grabs](contributing-before-you-start.md)
- [Contributing to the new backoffice](https://docs.umbraco.com/umbraco-backoffice/)
- [Unwanted changes](contributing-unwanted-changes.md)
- [Other ways to contribute](contributing-other-ways-to-contribute.md)
+2 -2
View File
@@ -4,11 +4,11 @@ contact_links:
url: https://github.com/umbraco/Umbraco-CMS/discussions/new?category=features-and-ideas
about: Start a new discussion when you have ideas or feature requests, eventually discussions can turn into plans
- name: ⁉️ Support Question
url: https://forum.umbraco.com
url: https://our.umbraco.com
about: This issue tracker is NOT meant for support questions. If you have a question, please join us on the forum.
- name: 📖 Documentation Issue
url: https://github.com/umbraco/UmbracoDocs/issues
about: Documentation issues should be reported on the Umbraco documentation repository.
- name: 🔐 Security Issue
url: https://umbraco.com/trust-center/security-and-umbraco/how-to-report-a-vulnerability-in-umbraco/
url: https://umbraco.com/about-us/trust-center/security-and-umbraco/how-to-report-a-vulnerability-in-umbraco/
about: Discovered a Security Issue in Umbraco?
+1 -1
View File
@@ -4,8 +4,8 @@
[![NuGet Version](https://img.shields.io/nuget/v/Umbraco.Cms)](https://www.nuget.org/packages/Umbraco.Cms)
[![Build status](https://img.shields.io/azure-devops/build/umbraco/Umbraco%2520Cms/301?logo=azurepipelines&label=Azure%20Pipelines)](https://umbraco.visualstudio.com/Umbraco%20Cms/_build?definitionId=301)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md)
[![Forum](https://img.shields.io/badge/help-forum-blue)](https://forum.umbraco.com)
[![Chat about Umbraco on Discord](https://img.shields.io/discord/869656431308189746?logo=discord&logoColor=fff)](https://discord.gg/umbraco)
[![Read what's going on in the Umbraco Discord chat now](https://img.shields.io/badge/read-discord-blue)](https://discord-chats.umbraco.com)
![Mastodon Follow](https://img.shields.io/mastodon/follow/110661369750014952?domain=https%3A%2F%2Fumbracocommunity.social)
+55
View File
@@ -0,0 +1,55 @@
name: Backoffice Static Web Apps CI/CD
on:
push:
branches:
- contrib
- v*/dev
paths:
- src/Umbraco.Web.UI.Client/package.json
- src/Umbraco.Web.UI.Client/package-lock.json
- src/Umbraco.Web.UI.Client/src/**
- .github/workflows/azure-backoffice.yml
pull_request:
types: [opened, synchronize, reopened, closed]
branches:
- contrib
- v*/dev
jobs:
build_and_deploy_job:
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed' && (contains(github.event.pull_request.labels.*.name, 'preview/backoffice')))
runs-on: ubuntu-latest
name: Build and Deploy Job
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Build And Deploy
id: builddeploy
uses: Azure/static-web-apps-deploy@v1
with:
production_branch: contrib
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_VICTORIOUS_GROUND_017B08103 }}
repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
action: "upload"
###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
# For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
app_location: "src/Umbraco.Web.UI.Client" # App source code path
app_build_command: "npm run build:for:static"
output_location: "dist" # Built app content directory - optional
skip_api_build: true # Set to true if you do not have an Azure Functions API in your repo
###### End of Repository/Build Configurations ######
close_pull_request_job:
if: github.event_name == 'pull_request' && github.event.action == 'closed'
runs-on: ubuntu-latest
name: Close Pull Request Job
steps:
- name: Close Pull Request
id: closepullrequest
uses: Azure/static-web-apps-deploy@v1
with:
app_location: "src/Umbraco.Web.UI.Client"
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_VICTORIOUS_GROUND_017B08103 }}
action: "close"
+56
View File
@@ -0,0 +1,56 @@
name: Storybook CI/CD
on:
push:
branches:
- contrib
- v*/dev
paths:
- src/Umbraco.Web.UI.Client/package.json
- src/Umbraco.Web.UI.Client/package-lock.json
- src/Umbraco.Web.UI.Client/src/**
- .github/workflows/azure-storybook.yml
pull_request:
types: [opened, synchronize, reopened, closed]
branches:
- contrib
- v*/dev
env:
NODE_OPTIONS: --max_old_space_size=16384
jobs:
build_and_deploy_job:
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed' && (contains(github.event.pull_request.labels.*.name, 'preview/storybook')))
runs-on: ubuntu-latest
name: Build and Deploy Job
steps:
- uses: actions/checkout@v4
- name: Build And Deploy
id: builddeploy
uses: Azure/static-web-apps-deploy@v1
with:
production_branch: contrib
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_ORANGE_SEA_0C7411A03 }}
repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
action: "upload"
###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
# For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
app_location: "src/Umbraco.Web.UI.Client" # App source code path
app_build_command: "npm run storybook:build"
output_location: "/storybook-static" # Built app content directory - optional
skip_api_build: true # Set to true if you do not have an Azure Functions API in your repo
###### End of Repository/Build Configurations ######
close_pull_request_job:
if: github.event_name == 'pull_request' && github.event.action == 'closed'
runs-on: ubuntu-latest
name: Close Pull Request Job
steps:
- name: Close Pull Request
id: closepullrequest
uses: Azure/static-web-apps-deploy@v1
with:
app_location: "src/Umbraco.Web.UI.Client"
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_ORANGE_SEA_0C7411A03 }}
action: "close"
+6 -3
View File
@@ -1,5 +1,8 @@
{
"cSpell.words": [
"unprovide"
]
"cSpell.words": ["unprovide"],
"eslint.useFlatConfig": true,
"eslint.workingDirectories": [
"./src/Umbraco.Web.UI.Client/",
"./src/Umbraco.Web.UI.Login/"
]
}
+2 -1
View File
@@ -20,6 +20,7 @@
<WarnOnPackingNonPackableProject>false</WarnOnPackingNonPackableProject>
</PropertyGroup>
<PropertyGroup>
<!--
TODO: Fix and remove overrides:
@@ -39,7 +40,7 @@
<!-- Package Validation -->
<PropertyGroup>
<GenerateCompatibilitySuppressionFile>false</GenerateCompatibilitySuppressionFile>
<EnablePackageValidation>true</EnablePackageValidation>
<EnablePackageValidation>false</EnablePackageValidation>
<PackageValidationBaselineVersion>15.0.0</PackageValidationBaselineVersion>
<EnableStrictModeForCompatibleFrameworksInPackage>true</EnableStrictModeForCompatibleFrameworksInPackage>
<EnableStrictModeForCompatibleTfms>true</EnableStrictModeForCompatibleTfms>
+3 -3
View File
@@ -45,8 +45,8 @@
<PackageVersion Include="Asp.Versioning.Mvc" Version="8.1.0" />
<PackageVersion Include="Asp.Versioning.Mvc.ApiExplorer" Version="8.1.0" />
<PackageVersion Include="Dazinator.Extensions.FileProviders" Version="2.0.0" />
<PackageVersion Include="Examine" Version="3.7.1" />
<PackageVersion Include="Examine.Core" Version="3.7.1" />
<PackageVersion Include="Examine" Version="3.7.0" />
<PackageVersion Include="Examine.Core" Version="3.7.0" />
<PackageVersion Include="HtmlAgilityPack" Version="1.11.74" />
<PackageVersion Include="JsonPatch.Net" Version="3.1.1" />
<PackageVersion Include="K4os.Compression.LZ4" Version="1.3.8" />
@@ -100,4 +100,4 @@
<!-- Examine.Lucene brings in a vulnerable version of Lucene.Net.Replicator -->
<PackageVersion Include="Lucene.Net.Replicator" Version="4.8.0-beta00017" />
</ItemGroup>
</Project>
</Project>
-579
View File
@@ -1,579 +0,0 @@
Third-Party Notices
===================
This file contains notices and attributions for third-party software used in the Umbraco CMS project.
It is not a license and does not grant any rights to use the third-party software.
Umbraco CMS is licensed under the MIT License, which can be found in the LICENSE file.
---
@openid/AppAuth-JS: An OpenID Connect and OAuth 2.0 client library for JavaScript
URL: https://github.com/openid/AppAuth-JS
License: Apache License, Version 2.0
Copyright: 2017 Google Inc.
---
AutoFixture: Write maintainable unit tests, faster
URL: https://github.com/AutoFixture/AutoFixture
License: MIT License
Copyright: 2013 Mark Seemann
---
Asp.Versioning.Mvc: A library for ASP.NET Core versioning
URL: https://github.com/dotnet/aspnet-api-versioning
License: MIT License
Copyright: .NET Foundation and contributors
---
Babel: A JavaScript compiler
URL: https://babeljs.io/
License: MIT License
Copyright: 2014-present Sebastian McKenzie and other contributors
---
BenchmarkDotNet: Powerful .NET library for benchmarking
URL: https://github.com/dotnet/BenchmarkDotNet
License: MIT License
Copyright: .NET Foundation and Contributors
---
Bogus: A simple and sane data generator for populating objects that supports different locales.
URL: https://github.com/bchavez/Bogus
License: MIT License
Copyright: 2015 Brian Chavez
---
CommandLineParser: Terse syntax C# command line parser for .NET
URL: https://github.com/commandlineparser/commandline
License: MIT License
Copyright: 2005-2015 Giacomo Stelluti Scala & Contributors
---
cross-env: A CLI tool to set environment variables across platforms
URL: https://github.com/kentcdodds/cross-env
License: MIT License
Copyright: 2017 Kent C. Dodds
---
Dazinator.Extensions.FileProviders: A library for file provider extensions
URL: https://github.com/dazinator/Dazinator.Extensions.FileProviders
License: MIT License
Copyright: 2016 Darrell
---
DOMPurify: A DOM-only XSS sanitizer for HTML, MathML and SVG
URL: https://github.com/cure53/DOMPurify
License: Apache License, Version 2.0
Copyright: 2025 Dr.-Ing. Mario Heiderich, Cure53
---
Element Internals Polyfill: A polyfill for the Element Internals API
URL: https://github.com/calebdwilliams/element-internals-polyfill
License: MIT License
Copyright: 2021 Caleb Williams
---
Eslint: A tool for identifying and reporting on patterns in JavaScript
URL: https://eslint.org/
License: MIT License
Copyright: OpenJS Foundation and other contributors
---
Examine: A search and indexing library for .NET
URL: https://github.com/Shazwazza/Examine
License: Microsoft Public License (Ms-PL)
Copyright: 2023 Shannon Deminick
---
Glob: A library for matching file paths using glob patterns
URL: https://github.com/isaacs/node-glob
License: ISC License
Copyright: 2009-2023 Isaac Z. Schlueter and Contributors
---
Globals: A library for managing global variables in JavaScript
URL: https://github.com/sindresorhus/globals
License: MIT License
Copyright: Sindre Sorhus
---
Html Agility Pack: An HTML parser for .NET
URL: https://html-agility-pack.net/
License: MIT License
Copyright: ZZZ Projects Inc.
---
ImageSharp: A cross-platform library for processing images in .NET
URL: https://github.com/SixLabors/ImageSharp
License: Apache License, Version 2.0 under the Six Labors Split License
Copyright: Six Labors
---
jsdiff: A JavaScript text differencing implementation
URL: https://github.com/kpdecker/jsdiff
License: BSD 3-Clause License
Copyright: 2009-2015 Kevin Decker <kpdecker@gmail.com>
---
JsonPatch.Net: A library for JSON Patch (RFC 6902) in .NET
URL: https://github.com/json-everything/json-everything
License: MIT License
Copyright: .NET Foundation and Contributors
---
K4os.Compression.LZ4: A fast LZ4 compression library for .NET
URL: https://github.com/MiloszKrajewski/K4os.Compression.LZ4
License: MIT License
Copyright: 2017 Milosz Krajewski
---
Lit: A simple library for building fast, lightweight web components
URL: https://lit.dev
License: BSD 3-Clause License
Copyright: 2020 Google LLC. All rights reserved.
---
Lucide: Beautiful & consistent icons for the web
URL: https://lucide.dev/
License: ISC License
Copyright: 2013-2022 Cole Bemis
Copyright: 2022 Lucide Contributors
---
Madge: A dependency graph generator for JavaScript
URL: https://github.com/pahen/madge
License: MIT License
Copyright: 2017 Patrik Henningsson
---
MailKit: A library for sending email in .NET
URL: https://github.com/jstedfast/MailKit
License: MIT License
Copyright: 2013-2024 .NET Foundation and Contributors
---
Markdown: A library for parsing and compiling Markdown
URL: https://github.com/hey-red/Markdown
License: MIT License
Copyright: 2018 red
---
marked: A markdown parser and compiler
URL: https://marked.js.org/
License: MIT License
Copyright: 2011-2018, Christopher Jeffrey (https://github.com/chjj/)
Copyright: 2018+, MarkedJS (https://github.com/markedjs/)
---
Message Pack: The extremely fast MessagePack serializer for C#
URL: https://github.com/MessagePack-CSharp/MessagePack-CSharp
License: MIT License
Copyright: 2017 Yoshifumi Kawai and contributors
---
Miniprofiler: A mini profiler for .NET
URL: https://github.com/MiniProfiler/dotnet
License: MIT License
Copyright: .NET MiniProfiler Contributors
---
Monaco Editor: A browser-based code editor
URL: https://microsoft.github.io/monaco-editor/
License: MIT License
Copyright: 2016-present Microsoft Corporation
---
Moq: A mocking library for .NET
URL: https://github.com/moq/moq
License: BSD 3-Clause License
Copyright: 2007 Clarius Consulting, Manas Technology Solutions, InSTEDD, and Contributors.
---
Mock Service Worker (MSW): A library for mocking API requests in JavaScript
URL: https://mswjs.io/
License: MIT License
Copyright: 2018present Artem Zakharchenko
---
NCrontab: A cron schedule parser for .NET
URL: https://github.com/atifaziz/NCrontab
License: Apache License, Version 2.0
Copyright: 2001 The OpenSymphony Group
Copyright: 2008 Atif Aziz
---
Nerdbank.GitVersioning: A library for versioning .NET projects
URL: https://github.com/dotnet/Nerdbank.GitVersioning
License: MIT License
Copyright: .NET Foundation and Contributors
---
NJsonSchema: A JSON schema validator for .NET
URL: https://github.com/RicoSuter/NJsonSchema
License: MIT License
Copyright: 2022 Rico Suter
---
NPoco: A micro ORM for .NET
URL: https://github.com/schotime/NPoco
License: Apache License, Version 2.0
Copyright: Schotime
---
NUnit: A unit testing framework for .NET
URL: https://github.com/nunit/nunit
License: MIT License
Copyright: Charlie Poole, Rob Prouse and Contributors
---
Open Web Components: A set of standards and libraries for building web components
URL: https://open-wc.org/
License: MIT License
Copyright: 2018 open-wc
---
Openapi-ts: The OpenAPI to TypeScript codegen
URL: https://github.com/hey-api/openapi-ts
License: MIT License
Copyright: Hey API
---
OpenIddict: A simple and flexible OpenID Connect server for ASP.NET Core
URL: https://github.com/openiddict/openiddict-core
License: Apache License, Version 2.0
Copyright: Kévin Chalet
---
Playwright: A Node.js library to automate browser testing
URL: https://playwright.dev/
License: Apache License, Version 2.0
Copyright: 2025 Microsoft Corporation
---
Playwright-msw: A library to wrap Mock Service Worker with Playwright
URL: https://github.com/valendres/playwright-msw
License: MIT License
Copyright: 2022 Peter Weller
---
Prettier: An opinionated code formatter
URL: https://prettier.io/
License: MIT License
Copyright: James Long and contributors
---
Remark-gfm: A GitHub Flavored Markdown plugin for Remark
URL: https://github.com/remarkjs/remark-gfm
License: MIT License
Copyright: Titus Wormer
---
Rollup: A module bundler for JavaScript
URL: https://rollupjs.org/
License: MIT License
Copyright: 2015-present Rollup contributors
---
Rollup Plugins: A collection of Rollup plugins
URL: https://github.com/rollup/plugins
License: MIT License
Copyright: 2019-present Rollup Plugins contributors
---
Rollup-plugin-esbuild: A Rollup plugin for using esbuild
URL: https://github.com/egoist/rollup-plugin-esbuild
License: MIT License
Copyright: 2020 EGOIST
---
Rollup-plugin-import-css: A Rollup plugin for importing CSS files
URL: https://github.com/jleeson/rollup-plugin-import-css
License: MIT License
Copyright: 2020 Jacob Leeson
---
rxjs: Reactive Extensions for JavaScript
URL: https://rxjs.dev/
License: Apache License, Version 2.0
Copyright: 2015-present Ben Lesh <ben@benlesh.com>, Google, Inc., Netflix, Inc., Microsoft Corp., and contributors
---
Serilog: A diagnostic logging library for .NET
URL: https://github.com/serilog/serilog
License: Apache License, Version 2.0
Copyright: Serilog Contributors
---
Simple Icons: A set of SVG icons for popular brands
URL: https://simpleicons.org/
License: CC0 1.0 Universal License
Copyright: Simple Icons Contributors
---
Storybook: A UI component explorer for Web Components
URL: https://storybook.js.org/
License: MIT License
Copyright: 2024 Storybook
---
StyleCop.Analyzers: Analyzers for StyleCop
URL: https://github.com/DotNetAnalyzers/StyleCopAnalyzers
License: MIT License
Copyright: Tunnel Vision Laboratories, LLC
---
SVGO: A tool for optimizing SVG files
URL: https://svgo.dev/
License: MIT License
Copyright: Kir Belevich
---
Swashbuckle.AspNetCore: A library for generating Swagger documentation for ASP.NET Core APIs
URL: https://github.com/domaindrivendev/Swashbuckle.AspNetCore
License: MIT License
Copyright: 2016 Richard Morris
---
Tiny Glob: A tiny globbing library for Node.js
URL: https://github.com/terkelg/tiny-glob
License: MIT License
Copyright: 2018 Terkel
---
TinyMCE, version 6.x: A rich text editor for the web
URL: https://www.tiny.cloud/
License: MIT License
Copyright: 2022 Ephox Corporation DBA Tiny Technologies, Inc.
---
Tiptap: A renderless rich-text editor for the web
URL: https://tiptap.dev/
License: MIT License
Copyright: 2025 Tiptap GmbH
---
Tsc-alias: A TypeScript compiler plugin for aliasing module paths
URL: https://github.com/justkey007/tsc-alias
License: MIT License
Copyright: 2018 Justkey
---
Typedoc: A documentation generator for TypeScript projects
URL: https://typedoc.org/
License: Apache License, Version 2.0
Copyright: Gerrit Birkeland and Contributors
---
Typescript: A typed superset of JavaScript that compiles to plain JavaScript
URL: https://www.typescriptlang.org/
License: Apache License, Version 2.0
Copyright: 2012-present Microsoft Corporation
---
Typescript-eslint: A set of tools for linting TypeScript code
URL: https://github.com/typescript-eslint/typescript-eslint
License: MIT License
Copyright: 2019 typescript-eslint and other contributors
---
Typescript-json-schema: A library for generating JSON schema from TypeScript types
URL: https://github.com/YousefED/typescript-json-schema
License: BSD 3-Clause License
Copyright: 2016 typescript-json-schema contributors
---
Umbraco.Code: Provides code-level tools for Umbraco
URL: https://github.com/umbraco/Umbraco-Code
License: MIT License
Copyright: 2005-present Umbraco A/S
---
Umbraco.GitVersioning.Extensions: Utilities for Nerdbank.GitVersioning
URL: https://github.com/umbraco/Umbraco.GitVersioning.Extensions
License: MIT License
Copyright: 2005-present Umbraco A/S
---
Umbraco.JsonSchema.Extensions: Utilities for JSON schema generation
URL: https://github.com/umbraco/Umbraco.JsonSchema.Extensions
License: MIT License
Copyright: 2005-present Umbraco A/S
---
Umbraco UI Library: A set of UI components for building web applications
URL: https://uui.umbraco.com/
License: MIT License
Copyright: 2005-present Umbraco A/S
---
uuid: A library for generating unique identifiers
URL: https://github.com/uuidjs/uuid
License: MIT License
Copyright: 2010-2020 Robert Kieffer and other contributors
---
Vite: A fast build tool and development server for modern web projects
URL: https://vite.dev/
License: MIT License
Copyright: 2019-present VoidZero Inc. and Vite contributors
---
Vite-plugin-static-copy: A Vite plugin for copying static files
URL: https://github.com/sapphi-red/vite-plugin-static-copy
License: MIT License
Copyright: 2021 sapphi-red
---
Vite-tsconfig-paths: A Vite plugin for resolving TypeScript paths
URL: https://github.com/aleclarson/vite-tsconfig-paths
License: MIT License
Copyright: Alec Larson
---
Web Component Analyzer: A tool for analyzing web components
URL: https://github.com/runem/web-component-analyzer
License: MIT License
Copyright: 2019 Rune Mehlsen
+254 -105
View File
@@ -313,8 +313,8 @@ stages:
testFilter: "(FullyQualifiedName~Umbraco.Infrastructure.Service)"
LinuxPart3Of3:
vmImage: "ubuntu-latest"
# Filter tests that are not part of the Umbraco.Infrastructure and ManagementApi namespace. So this will run all tests that are not part of the Umbraco.Infrastructure namespace
testFilter: "(FullyQualifiedName!~Umbraco.Infrastructure) & (FullyQualifiedName!~ManagementApi)"
# Filter tests that are not part of the Umbraco.Infrastructure namespace. So this will run all tests that are not part of the Umbraco.Infrastructure namespace
testFilter: "(FullyQualifiedName!~Umbraco.Infrastructure)"
macOSPart1Of3:
vmImage: "macOS-latest"
# Filter tests that are part of the Umbraco.Infrastructure namespace but not part of the Umbraco.Infrastructure.Service namespace
@@ -325,8 +325,8 @@ stages:
testFilter: "(FullyQualifiedName~Umbraco.Infrastructure.Service)"
macOSPart3Of3:
vmImage: "macOS-latest"
# Filter tests that are not part of the Umbraco.Infrastructure and ManagementApi namespace. So this will run all tests that are not part of the Umbraco.Infrastructure namespace
testFilter: "(FullyQualifiedName!~Umbraco.Infrastructure) & (FullyQualifiedName!~ManagementApi)"
# Filter tests that are not part of the Umbraco.Infrastructure namespace.
testFilter: "(FullyQualifiedName!~Umbraco.Infrastructure)"
pool:
vmImage: $(vmImage)
variables:
@@ -389,8 +389,8 @@ stages:
vmImage: "windows-latest"
Tests__Database__DatabaseType: LocalDb
Tests__Database__SQLServerMasterConnectionString: N/A
# Filter tests that are not part of the Umbraco.Infrastructure and ManagementApi namespace. So this will run all tests that are not part of the Umbraco.Infrastructure namespace
testFilter: "(FullyQualifiedName!~Umbraco.Infrastructure) & (FullyQualifiedName!~ManagementApi)"
# Filter tests that are not part of the Umbraco.Infrastructure namespace. So this will run all tests that are not part of the Umbraco.Infrastructure namespace
testFilter: "(FullyQualifiedName!~Umbraco.Infrastructure)"
LinuxPart1Of3:
vmImage: "ubuntu-latest"
SA_PASSWORD: UmbracoIntegration123!
@@ -410,8 +410,8 @@ stages:
SA_PASSWORD: UmbracoIntegration123!
Tests__Database__DatabaseType: SqlServer
Tests__Database__SQLServerMasterConnectionString: "Server=(local);User Id=sa;Password=$(SA_PASSWORD);TrustServerCertificate=True"
# Filter tests that are not part of the Umbraco.Infrastructure and ManagementApi namespace. So this will run all tests that are not part of the Umbraco.Infrastructure namespace
testFilter: "(FullyQualifiedName!~Umbraco.Infrastructure) & (FullyQualifiedName!~ManagementApi)"
# Filter tests that are not part of the Umbraco.Infrastructure namespace. So this will run all tests that are not part of the Umbraco.Infrastructure namespace
testFilter: "(FullyQualifiedName!~Umbraco.Infrastructure)"
pool:
vmImage: $(vmImage)
steps:
@@ -432,33 +432,6 @@ stages:
displayName: Start SQL Server Docker image (Linux)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
- powershell: |
$maxAttempts = 12
$attempt = 0
$status = ""
while (($status -ne 'running') -and ($attempt -lt $maxAttempts)) {
Start-Sleep -Seconds 5
# We use the docker inspect command to check the status of the container. If the container is not running, we wait 5 seconds and try again. And if reaches 12 attempts, we fail the build.
$status = docker inspect -f '{{.State.Status}}' mssql
if ($status -ne 'running') {
Write-Host "Waiting for SQL Server to be ready... Attempt $($attempt + 1)"
$attempt++
}
}
if ($status -eq 'running') {
Write-Host "SQL Server container is running"
docker ps -a
} else {
Write-Host "SQL Server did not become ready in time. Last known status: $status"
docker logs mssql
exit 1
}
displayName: Wait for SQL Server to be ready (Linux)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
- pwsh: SqlLocalDB start MSSQLLocalDB
displayName: Start SQL Server LocalDB (Windows)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
@@ -522,70 +495,151 @@ stages:
# Connection string
CONNECTIONSTRINGS__UMBRACODBDSN: Data Source=Umbraco;Mode=Memory;Cache=Shared;Foreign Keys=True;Pooling=True
CONNECTIONSTRINGS__UMBRACODBDSN_PROVIDERNAME: Microsoft.Data.Sqlite
DatabaseType: SQLite
strategy:
matrix:
LinuxPart1Of3:
vmImage: "ubuntu-latest"
testFolder: "DefaultConfig"
testCommand: "npm run smokeTestSqlite -- --shard=1/3"
LinuxPart2Of3:
vmImage: "ubuntu-latest"
testFolder: "DefaultConfig"
testCommand: "npm run smokeTestSqlite -- --shard=2/3"
LinuxPart3Of3:
vmImage: "ubuntu-latest"
testFolder: "DefaultConfig"
testCommand: "npm run smokeTestSqlite -- --shard=3/3"
WindowsPart1Of3:
vmImage: "windows-latest"
testFolder: "DefaultConfig"
testCommand: "npm run smokeTestSqlite -- --shard=1/3"
WindowsPart2Of3:
vmImage: "windows-latest"
testFolder: "DefaultConfig"
testCommand: "npm run smokeTestSqlite -- --shard=2/3"
WindowsPart3Of3:
vmImage: "windows-latest"
testFolder: "DefaultConfig"
testCommand: "npm run smokeTestSqlite -- --shard=3/3"
pool:
vmImage: $(vmImage)
steps:
# Setup test environment Template
- template: nightly-E2E-setup-template.yml
parameters:
nodeVersion: ${{ variables.nodeVersion }}
PlaywrightUserEmail: ${{ variables.UMBRACO__CMS__UNATTENDED__UNATTENDEDUSEREMAIL }}
PlaywrightPassword: ${{ variables.UMBRACO__CMS__UNATTENDED__UNATTENDEDUSERPASSWORD }}
ASPNETCORE_URLS: ${{ variables.ASPNETCORE_URLS }}
npm_config_cache: ${{ variables.npm_config_cache }}
# Setup test environment
- task: DownloadPipelineArtifact@2
displayName: Download NuGet artifacts
inputs:
artifact: nupkg
path: $(Agent.BuildDirectory)/app/nupkg
- task: NodeTool@0
displayName: Use Node.js $(nodeVersion)
retryCountOnTaskFailure: 3
inputs:
versionSpec: $(nodeVersion)
- task: UseDotNet@2
displayName: Use .NET SDK from global.json
inputs:
useGlobalJson: true
- pwsh: |
"UMBRACO_USER_LOGIN=$(UMBRACO__CMS__UNATTENDED__UNATTENDEDUSEREMAIL)
UMBRACO_USER_PASSWORD=$(UMBRACO__CMS__UNATTENDED__UNATTENDEDUSERPASSWORD)
URL=$(ASPNETCORE_URLS)
STORAGE_STAGE_PATH=$(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest/playwright/.auth/user.json" | Out-File .env
displayName: Generate .env
workingDirectory: $(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest
# Cache and restore NPM packages
- task: Cache@2
displayName: Cache NPM packages
inputs:
key: 'npm_e2e | "$(Agent.OS)" | $(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest/package-lock.json'
restoreKeys: |
npm_e2e | "$(Agent.OS)"
npm_e2e
path: $(npm_config_cache)
- script: npm ci --no-fund --no-audit --prefer-offline
workingDirectory: $(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest
displayName: Restore NPM packages
# Build application
- pwsh: |
$cmsVersion = "$(Build.BuildNumber)" -replace "\+",".g"
dotnet new nugetconfig
dotnet nuget add source ./nupkg --name Local
dotnet new install Umbraco.Templates::$cmsVersion
dotnet new umbraco --name UmbracoProject --version $cmsVersion --exclude-gitignore --no-restore --no-update-check
dotnet restore UmbracoProject
cp $(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest.UmbracoProject/*.cs UmbracoProject
displayName: Restore project
workingDirectory: $(Agent.BuildDirectory)/app
- pwsh: |
dotnet build UmbracoProject --configuration ${{ variables.buildConfiguration }} --no-restore
dotnet build UmbracoProject --configuration $(buildConfiguration) --no-restore
dotnet dev-certs https
displayName: Build application
workingDirectory: $(Agent.BuildDirectory)/app
condition: succeeded()
# Run application Template
- template: nightly-E2E-run-application-template.yml
parameters:
DatabaseType: ${{ variables.DatabaseType }}
buildConfiguration: ${{ variables.buildConfiguration }}
# Run application
- bash: |
nohup dotnet run --project UmbracoProject --configuration $(buildConfiguration) --no-build --no-launch-profile > $(Build.ArtifactStagingDirectory)/playwright.log 2>&1 &
echo "##vso[task.setvariable variable=AcceptanceTestProcessId]$!"
displayName: Run application (Linux)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
workingDirectory: $(Agent.BuildDirectory)/app
# Run tests Template
- template: nightly-E2E-run-tests-template.yml
parameters:
testCommand: $(testCommand)
ASPNETCORE_URLS: ${{ variables.ASPNETCORE_URLS }}
DatabaseType: ${{ variables.DatabaseType }}
- pwsh: |
$process = Start-Process dotnet "run --project UmbracoProject --configuration $(buildConfiguration) --no-build --no-launch-profile 2>&1" -PassThru -NoNewWindow -RedirectStandardOutput $(Build.ArtifactStagingDirectory)/playwright.log
Write-Host "##vso[task.setvariable variable=AcceptanceTestProcessId]$($process.Id)"
displayName: Run application (Windows)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
workingDirectory: $(Agent.BuildDirectory)/app
# Wait for application to start responding to requests
- pwsh: npx wait-on -v --interval 1000 --timeout 120000 $(ASPNETCORE_URLS)
displayName: Wait for application
workingDirectory: tests/Umbraco.Tests.AcceptanceTest
# Install Playwright and dependencies
- pwsh: npx playwright install chromium
displayName: Install Playwright only with Chromium browser
workingDirectory: tests/Umbraco.Tests.AcceptanceTest
# Test
- pwsh: $(testCommand)
displayName: Run Playwright tests
workingDirectory: tests/Umbraco.Tests.AcceptanceTest
env:
CI: true
CommitId: $(Build.SourceVersion)
AgentOs: $(Agent.OS)
# Stop application
- bash: kill -15 $(AcceptanceTestProcessId)
displayName: Stop application (Linux)
condition: and(ne(variables.AcceptanceTestProcessId, ''), eq(variables['Agent.OS'], 'Linux'))
- pwsh: Stop-Process -Id $(AcceptanceTestProcessId)
displayName: Stop application (Windows)
condition: and(ne(variables.AcceptanceTestProcessId, ''), eq(variables['Agent.OS'], 'Windows_NT'))
# Copy artifacts
- pwsh: |
if (Test-Path tests/Umbraco.Tests.AcceptanceTest/results/*) {
Copy-Item tests/Umbraco.Tests.AcceptanceTest/results/* $(Build.ArtifactStagingDirectory) -Recurse
}
displayName: Copy Playwright results
condition: succeededOrFailed()
# Publish test artifacts
- task: PublishPipelineArtifact@1
displayName: Publish test artifacts
condition: succeededOrFailed()
inputs:
targetPath: $(Build.ArtifactStagingDirectory)
artifact: "Acceptance Test Results - $(Agent.JobName) - Attempt #$(System.JobAttempt)"
# Publish test results
- task: PublishTestResults@2
displayName: "Publish test results"
condition: succeededOrFailed()
inputs:
testResultsFormat: 'JUnit'
testResultsFiles: '*.xml'
searchFolder: "tests/Umbraco.Tests.AcceptanceTest/results"
testRunTitle: "$(Agent.JobName)"
- job:
displayName: E2E Tests (SQL Server)
@@ -593,76 +647,175 @@ stages:
# Connection string
CONNECTIONSTRINGS__UMBRACODBDSN: Data Source=(localdb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\Umbraco.mdf;Integrated Security=True
CONNECTIONSTRINGS__UMBRACODBDSN_PROVIDERNAME: Microsoft.Data.SqlClient
SA_PASSWORD: $(UMBRACO__CMS__UNATTENDED__UNATTENDEDUSERPASSWORD)
DatabaseType: SQLServer
strategy:
matrix:
${{ if eq(parameters.sqlServerLinuxAcceptanceTests, True) }}:
LinuxPart1Of3:
testCommand: "npm run smokeTest -- --shard=1/3"
vmImage: "ubuntu-latest"
testFolder: "DefaultConfig"
SA_PASSWORD: $(UMBRACO__CMS__UNATTENDED__UNATTENDEDUSERPASSWORD)
CONNECTIONSTRINGS__UMBRACODBDSN: "Server=(local);Database=Umbraco;User Id=sa;Password=$(SA_PASSWORD);TrustServerCertificate=True"
LinuxPart2Of3:
testCommand: "npm run smokeTest -- --shard=2/3"
vmImage: "ubuntu-latest"
testFolder: "DefaultConfig"
SA_PASSWORD: $(UMBRACO__CMS__UNATTENDED__UNATTENDEDUSERPASSWORD)
CONNECTIONSTRINGS__UMBRACODBDSN: "Server=(local);Database=Umbraco;User Id=sa;Password=$(SA_PASSWORD);TrustServerCertificate=True"
LinuxPart3Of3:
testCommand: "npm run smokeTest -- --shard=3/3"
vmImage: "ubuntu-latest"
testFolder: "DefaultConfig"
SA_PASSWORD: $(UMBRACO__CMS__UNATTENDED__UNATTENDEDUSERPASSWORD)
CONNECTIONSTRINGS__UMBRACODBDSN: "Server=(local);Database=Umbraco;User Id=sa;Password=$(SA_PASSWORD);TrustServerCertificate=True"
WindowsPart1Of3:
vmImage: "windows-latest"
testFolder: "DefaultConfig"
testCommand: "npm run smokeTest -- --shard=1/3"
WindowsPart2Of3:
vmImage: "windows-latest"
testFolder: "DefaultConfig"
testCommand: "npm run smokeTest -- --shard=2/3"
WindowsPart3Of3:
vmImage: "windows-latest"
testFolder: "DefaultConfig"
testCommand: "npm run smokeTest -- --shard=3/3"
pool:
vmImage: $(vmImage)
steps:
# Setup test environment Template
- template: nightly-E2E-setup-template.yml
parameters:
nodeVersion: ${{ variables.nodeVersion }}
PlaywrightUserEmail: ${{ variables.UMBRACO__CMS__UNATTENDED__UNATTENDEDUSEREMAIL }}
PlaywrightPassword: ${{ variables.UMBRACO__CMS__UNATTENDED__UNATTENDEDUSERPASSWORD }}
ASPNETCORE_URLS: ${{ variables.ASPNETCORE_URLS }}
npm_config_cache: ${{ variables.npm_config_cache }}
# Setup test environment
- task: DownloadPipelineArtifact@2
displayName: Download NuGet artifacts
inputs:
artifact: nupkg
path: $(Agent.BuildDirectory)/app/nupkg
- task: NodeTool@0
displayName: Use Node.js $(nodeVersion)
inputs:
versionSpec: $(nodeVersion)
- task: UseDotNet@2
displayName: Use .NET SDK from global.json
inputs:
useGlobalJson: true
- pwsh: |
"UMBRACO_USER_LOGIN=$(UMBRACO__CMS__UNATTENDED__UNATTENDEDUSEREMAIL)
UMBRACO_USER_PASSWORD=$(UMBRACO__CMS__UNATTENDED__UNATTENDEDUSERPASSWORD)
URL=$(ASPNETCORE_URLS)
STORAGE_STAGE_PATH=$(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest/playwright/.auth/user.json" | Out-File .env
displayName: Generate .env
workingDirectory: $(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest
# Cache and restore NPM packages
- task: Cache@2
displayName: Cache NPM packages
inputs:
key: 'npm_e2e | "$(Agent.OS)" | $(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest/package-lock.json'
restoreKeys: |
npm_e2e | "$(Agent.OS)"
npm_e2e
path: $(npm_config_cache)
- script: npm ci --no-fund --no-audit --prefer-offline
workingDirectory: $(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest
displayName: Restore NPM packages
# Build application
- pwsh: |
$cmsVersion = "$(Build.BuildNumber)" -replace "\+",".g"
dotnet new nugetconfig
dotnet nuget add source ./nupkg --name Local
dotnet new install Umbraco.Templates::$cmsVersion
dotnet new umbraco --name UmbracoProject --version $cmsVersion --exclude-gitignore --no-restore --no-update-check
dotnet restore UmbracoProject
cp $(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest.UmbracoProject/*.cs UmbracoProject
displayName: Restore project
workingDirectory: $(Agent.BuildDirectory)/app
- pwsh: |
dotnet build UmbracoProject --configuration ${{ variables.buildConfiguration }} --no-restore
dotnet build UmbracoProject --configuration $(buildConfiguration) --no-restore
dotnet dev-certs https
displayName: Build application
workingDirectory: $(Agent.BuildDirectory)/app
condition: succeeded()
# Run application Template
- template: nightly-E2E-run-application-template.yml
parameters:
SA_PASSWORD: ${{ variables.SA_PASSWORD }}
buildConfiguration: ${{ variables.buildConfiguration }}
DatabaseType: ${{ variables.DatabaseType }}
# Start SQL Server
- powershell: docker run --name mssql -d -p 1433:1433 -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=$(SA_PASSWORD)" mcr.microsoft.com/mssql/server:2022-latest
displayName: Start SQL Server Docker image (Linux)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
# Run tests Template
- template: nightly-E2E-run-tests-template.yml
parameters:
testCommand: $(testCommand)
ASPNETCORE_URLS: ${{ variables.ASPNETCORE_URLS }}
DatabaseType: ${{ variables.DatabaseType }}
- pwsh: SqlLocalDB start MSSQLLocalDB
displayName: Start SQL Server LocalDB (Windows)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
# Run application
- bash: |
nohup dotnet run --project UmbracoProject --configuration $(buildConfiguration) --no-build --no-launch-profile > $(Build.ArtifactStagingDirectory)/playwright.log 2>&1 &
echo "##vso[task.setvariable variable=AcceptanceTestProcessId]$!"
displayName: Run application (Linux)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
workingDirectory: $(Agent.BuildDirectory)/app
- pwsh: |
$process = Start-Process dotnet "run --project UmbracoProject --configuration $(buildConfiguration) --no-build --no-launch-profile 2>&1" -PassThru -NoNewWindow -RedirectStandardOutput $(Build.ArtifactStagingDirectory)/playwright.log
Write-Host "##vso[task.setvariable variable=AcceptanceTestProcessId]$($process.Id)"
displayName: Run application (Windows)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
workingDirectory: $(Agent.BuildDirectory)/app
# Wait for application to start responding to requests
- pwsh: npx wait-on -v --interval 1000 --timeout 120000 $(ASPNETCORE_URLS)
displayName: Wait for application
workingDirectory: tests/Umbraco.Tests.AcceptanceTest
# Install Playwright and dependencies
- pwsh: npx playwright install chromium
displayName: Install Playwright only with Chromium browser
workingDirectory: tests/Umbraco.Tests.AcceptanceTest
# Test
- pwsh: $(testCommand)
displayName: Run Playwright tests
workingDirectory: tests/Umbraco.Tests.AcceptanceTest
env:
CI: true
CommitId: $(Build.SourceVersion)
AgentOs: $(Agent.OS)
# Stop application
- bash: kill -15 $(AcceptanceTestProcessId)
displayName: Stop application (Linux)
condition: and(ne(variables.AcceptanceTestProcessId, ''), eq(variables['Agent.OS'], 'Linux'))
- pwsh: Stop-Process -Id $(AcceptanceTestProcessId)
displayName: Stop application (Windows)
condition: and(ne(variables.AcceptanceTestProcessId, ''), eq(variables['Agent.OS'], 'Windows_NT'))
# Stop SQL Server
- pwsh: docker stop mssql
displayName: Stop SQL Server Docker image (Linux)
condition: eq(variables['Agent.OS'], 'Linux')
- pwsh: SqlLocalDB stop MSSQLLocalDB
displayName: Stop SQL Server LocalDB (Windows)
condition: eq(variables['Agent.OS'], 'Windows_NT')
# Copy artifacts
- pwsh: |
if (Test-Path tests/Umbraco.Tests.AcceptanceTest/results/*) {
Copy-Item tests/Umbraco.Tests.AcceptanceTest/results/* $(Build.ArtifactStagingDirectory) -Recurse
}
displayName: Copy Playwright results
condition: succeededOrFailed()
# Publish test artifacts
- task: PublishPipelineArtifact@1
displayName: Publish test artifacts
condition: succeededOrFailed()
inputs:
targetPath: $(Build.ArtifactStagingDirectory)
artifact: "Acceptance Test Results - $(Agent.JobName) - Attempt #$(System.JobAttempt)"
# Publish test results
- task: PublishTestResults@2
displayName: "Publish test results"
condition: succeededOrFailed()
inputs:
testResultsFormat: 'JUnit'
testResultsFiles: '*.xml'
searchFolder: "tests/Umbraco.Tests.AcceptanceTest/results"
testRunTitle: "$(Agent.JobName)"
###############################################
## Release
@@ -676,8 +829,6 @@ stages:
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
@@ -739,8 +890,6 @@ stages:
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
-75
View File
@@ -1,75 +0,0 @@
parameters:
- name: testFolder
type: string
default: ''
- name: buildConfiguration
type: string
default: ''
- name: additionalEnvironmentVariables
type: boolean
default: False
steps:
- pwsh: |
dotnet restore UmbracoProject
cp $(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest.UmbracoProject/*.cs UmbracoProject
displayName: Restore project
workingDirectory: $(Agent.BuildDirectory)/app
# Update application to use necessary app settings
- pwsh: |
$sourcePath = "$(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest/tests/${{ parameters.testFolder }}/AdditionalSetup"
$destinationPath = "UmbracoProject"
$jsonFiles = Get-ChildItem -Path $sourcePath -Filter "*.json"
if ($jsonFiles) {
$jsonFiles | ForEach-Object {
Write-Host "Copying: $($_.FullName)"
Copy-Item -Path $_.FullName -Destination $destinationPath -Force
}
} else {
Write-Host "No JSON files found."
}
displayName: Update application to use necessary app settings
workingDirectory: $(Agent.BuildDirectory)/app
# Update application to use necessary App_Plugins
- pwsh: |
$sourcePath = "$(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest/tests/${{ parameters.testFolder }}/AdditionalSetup"
$destinationPath = "UmbracoProject"
$appPluginsFolders = Get-ChildItem -Path $sourcePath -Directory -Filter "App_Plugins"
if ($appPluginsFolders) {
foreach ($folder in $appPluginsFolders) {
Write-Host "Copying folder: $($folder.FullName)"
Copy-Item -Path $folder.FullName -Destination $destinationPath -Recurse -Force
}
} else {
Write-Host "No App_Plugins found."
}
displayName: Update application to use necessary app plugins
workingDirectory: $(Agent.BuildDirectory)/app
# Update application to use necessary classes
- pwsh: |
$sourcePath = "$(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest/tests/${{ parameters.testFolder }}/AdditionalSetup"
$destinationPath = "UmbracoProject"
$csharpFiles = Get-ChildItem -Path $sourcePath -Filter "*.cs"
if ($csharpFiles) {
$csharpFiles | ForEach-Object {
Write-Host "Copying: $($_.FullName)"
Copy-Item -Path $_.FullName -Destination $destinationPath -Force
}
} else {
Write-Host "No C# files found."
}
displayName: Update application to use necessary classes
workingDirectory: $(Agent.BuildDirectory)/app
- ${{ if eq(parameters.additionalEnvironmentVariables, False) }}:
- pwsh: |
dotnet build UmbracoProject --configuration ${{ parameters.buildConfiguration }} --no-restore
dotnet dev-certs https
displayName: Build application
workingDirectory: $(Agent.BuildDirectory)/app
condition: succeeded()
@@ -1,47 +0,0 @@
parameters:
- name: SA_PASSWORD
type: string
default: ''
- name: buildConfiguration
type: string
default: ''
- name: additionalEnvironmentVariables
type: boolean
default: False
- name: DatabaseType
type: string
default: ''
steps:
# Skips the SQLServer setup if the databaseType does not match
- ${{ if eq(parameters.DatabaseType, 'SQLServer') }}:
# Start SQL Server Linux
- powershell: docker run --name mssql -d -p 1433:1433 -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=${{ parameters.SA_PASSWORD }}" mcr.microsoft.com/mssql/server:2022-latest
displayName: Start SQL Server Docker image (Linux)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
# Start SQL Server LocalDB Windows
- pwsh: SqlLocalDB start MSSQLLocalDB
displayName: Start SQL Server LocalDB (Windows)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
# If we want to add additional environment variables to the run step, then we will skip these
- ${{ if eq(parameters.additionalEnvironmentVariables, False) }}:
# Run application for Linux
- bash: |
nohup dotnet run --project UmbracoProject --configuration ${{ parameters.buildConfiguration }} --no-build --no-launch-profile > $(Build.ArtifactStagingDirectory)/playwright.log 2>&1 &
echo "##vso[task.setvariable variable=AcceptanceTestProcessId]$!"
displayName: Run application (Linux)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
workingDirectory: $(Agent.BuildDirectory)/app
# Run application for Windows
- pwsh: |
$process = Start-Process dotnet "run --project UmbracoProject --configuration ${{ parameters.buildConfiguration }} --no-build --no-launch-profile 2>&1" -PassThru -NoNewWindow -RedirectStandardOutput $(Build.ArtifactStagingDirectory)/playwright.log
Write-Host "##vso[task.setvariable variable=AcceptanceTestProcessId]$($process.Id)"
displayName: Run application (Windows)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
workingDirectory: $(Agent.BuildDirectory)/app
-105
View File
@@ -1,105 +0,0 @@
parameters:
- name: ASPNETCORE_URLS
type: string
default: ''
- name: testCommand
type: string
default: ''
- name: port
type: string
default: ''
- name: AZUREB2CTESTUSEREMAIL
type: string
default: ''
- name: AZUREB2CTESTUSERPASSWORD
type: string
default: ''
- name: DatabaseType
type: string
default: ''
steps:
# Ensures we have the package wait-on installed
- pwsh: npm install wait-on
displayName: Install wait-on package
# Wait for either the port of the aspnetcore url
- pwsh: |
$Port = "${{ parameters.port }}"
$Url = "${{ parameters.ASPNETCORE_URLS }}"
if ($Port -ne "") {
Write-Host "Waiting on TCP port $Port"
npx wait-on -v --interval 1000 --timeout 120000 "tcp:$Port"
} else {
Write-Host "Waiting on URL $Url"
npx wait-on -v --interval 1000 --timeout 120000 "$Url"
}
displayName: Wait for application
workingDirectory: tests/Umbraco.Tests.AcceptanceTest
# Install Playwright and dependencies
- pwsh: npx playwright install chromium
displayName: Install Playwright only with Chromium browser
workingDirectory: tests/Umbraco.Tests.AcceptanceTest
# Test
- pwsh: ${{ parameters.testCommand }}
displayName: Run Playwright tests
workingDirectory: tests/Umbraco.Tests.AcceptanceTest
env:
CI: true
CommitId: $(Build.SourceVersion)
AgentOs: $(Agent.OS)
AZUREADB2CTESTUSEREMAIL: ${{ parameters.AZUREB2CTESTUSEREMAIL }}
AZUREADB2CTESTUSERPASSWORD: ${{ parameters.AZUREB2CTESTUSERPASSWORD }}
# Stop application
- bash: kill -15 $(AcceptanceTestProcessId)
displayName: Stop application (Linux)
condition: and(succeededOrFailed(), ne(variables.AcceptanceTestProcessId, ''), eq(variables['Agent.OS'], 'Linux'))
- pwsh: Stop-Process -Id $(AcceptanceTestProcessId)
displayName: Stop application (Windows)
condition: and(succeededOrFailed(), ne(variables.AcceptanceTestProcessId, ''), eq(variables['Agent.OS'], 'Windows_NT'))
- ${{ if eq(parameters.DatabaseType, 'SQLServer') }}:
# Stop SQL Server
- pwsh: docker stop mssql
displayName: Stop SQL Server Docker image (Linux)
condition: and(succeededOrFailed(), eq(variables['Agent.OS'], 'Linux'))
- pwsh: SqlLocalDB stop MSSQLLocalDB
displayName: Stop SQL Server LocalDB (Windows)
condition: and(succeededOrFailed(), eq(variables['Agent.OS'], 'Windows_NT'))
# Copy artifacts
- pwsh: |
if (Test-Path tests/Umbraco.Tests.AcceptanceTest/results/*) {
Copy-Item tests/Umbraco.Tests.AcceptanceTest/results/* $(Build.ArtifactStagingDirectory) -Recurse
}
displayName: Copy Playwright results
condition: succeededOrFailed()
# Publish
- task: PublishPipelineArtifact@1
displayName: Publish test artifacts
condition: succeededOrFailed()
inputs:
targetPath: $(Build.ArtifactStagingDirectory)
artifact: "Acceptance Test Results - $(Agent.JobName) - Attempt #$(System.JobAttempt)"
# Publish test results
- task: PublishTestResults@2
displayName: "Publish test results"
condition: succeededOrFailed()
inputs:
testResultsFormat: 'JUnit'
testResultsFiles: '*.xml'
searchFolder: "tests/Umbraco.Tests.AcceptanceTest/results"
testRunTitle: "$(Agent.JobName)"
-69
View File
@@ -1,69 +0,0 @@
parameters:
- name: nodeVersion
type: string
default: ''
- name: PlaywrightUserEmail
type: string
default: ''
- name: PlaywrightPassword
type: string
default: ''
- name: ASPNETCORE_URLS
type: string
default: ''
- name: npm_config_cache
type: string
default: ''
steps:
- task: DownloadPipelineArtifact@2
displayName: Download NuGet artifacts
inputs:
artifact: nupkg
path: $(Agent.BuildDirectory)/app/nupkg
- task: NodeTool@0
displayName: Use Node.js $(nodeVersion)
inputs:
versionSpec: $(nodeVersion)
- task: UseDotNet@2
displayName: Use .NET SDK from global.json
inputs:
useGlobalJson: true
- pwsh: |
"UMBRACO_USER_LOGIN=${{ parameters.PlaywrightUserEmail }}
UMBRACO_USER_PASSWORD=${{ parameters.PlaywrightPassword }}
URL=${{ parameters.ASPNETCORE_URLS }}
STORAGE_STAGE_PATH=$(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest/playwright/.auth/user.json" | Out-File .env
displayName: Generate .env
workingDirectory: $(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest
# Cache and restore NPM packages
- task: Cache@2
displayName: Cache NPM packages
inputs:
key: 'npm_e2e | "$(Agent.OS)" | $(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest/package-lock.json'
restoreKeys: |
npm_e2e | "$(Agent.OS)"
npm_e2e
path: ${{ parameters.npm_config_cache }}
- script: npm ci --no-fund --no-audit --prefer-offline
workingDirectory: $(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest
displayName: Restore NPM packages
# Install Template
- pwsh: |
$cmsVersion = "$(Build.BuildNumber)" -replace "\+",".g"
dotnet new nugetconfig
dotnet nuget add source ./nupkg --name Local
dotnet new install Umbraco.Templates::$cmsVersion
dotnet new umbraco --name UmbracoProject --version $cmsVersion --exclude-gitignore --no-restore --no-update-check
displayName: Install Template
workingDirectory: $(Agent.BuildDirectory)/app
+284 -472
View File
@@ -3,29 +3,14 @@ name: Nightly_E2E_Test_$(TeamProject)_$(Build.DefinitionName)_$(SourceBranchName
pr: none
trigger: none
# schedules:
# - cron: '0 0 * * *'
# displayName: Daily midnight build
# branches:
# include:
# - v14/dev
# - v15/dev
parameters:
- name: differentAppSettingsAcceptanceTests
displayName: Run acceptance tests with different app settings
type: boolean
default: false
- name: skipDefaultConfigAcceptanceTests
displayName: Skip tests with DefaultConfig
type: boolean
default: false
- name: skipIntegrationTests
displayName: Skip integration tests
type: boolean
default: false
schedules:
- cron: '0 0 * * *'
displayName: Daily midnight build
branches:
include:
- v14/dev
- v15/dev
- v16/dev
variables:
nodeVersion: 20
@@ -48,17 +33,25 @@ stages:
- job: A
displayName: Build Umbraco CMS
pool:
vmImage: "windows-latest"
vmImage: 'ubuntu-latest'
steps:
- checkout: self
submodules: false
lfs: false,
fetchDepth: 500
- template: templates/backoffice-install.yml
fetchDepth: 0
submodules: true
- task: UseDotNet@2
displayName: Use .NET SDK from global.json
inputs:
useGlobalJson: true
- template: templates/backoffice-install.yml
- script: npm run build:for:cms
displayName: Run build (Bellissima)
workingDirectory: src/Umbraco.Web.UI.Client
- script: npm ci --no-fund --no-audit --prefer-offline
displayName: Run npm ci (Login)
workingDirectory: src/Umbraco.Web.UI.Login
- script: npm run build
displayName: Run npm build (Login)
workingDirectory: src/Umbraco.Web.UI.Login
- task: DotNetCoreCLI@2
displayName: Run dotnet restore
inputs:
@@ -70,7 +63,7 @@ stages:
inputs:
command: build
projects: $(solution)
arguments: "--configuration $(buildConfiguration) --no-restore --property:ContinuousIntegrationBuild=true --property:GeneratePackageOnBuild=true --property:PackageOutputPath=$(Build.ArtifactStagingDirectory)/nupkg"
arguments: '--configuration $(buildConfiguration) --no-restore --property:ContinuousIntegrationBuild=true --property:GeneratePackageOnBuild=true --property:PackageOutputPath=$(Build.ArtifactStagingDirectory)/nupkg'
- task: PublishPipelineArtifact@1
displayName: Publish nupkg
inputs:
@@ -82,237 +75,8 @@ stages:
targetPath: $(Build.SourcesDirectory)
artifactName: build_output
- job: B
displayName: Build Bellissima Package
pool:
vmImage: "ubuntu-latest"
steps:
- checkout: self
submodules: false
lfs: false,
fetchDepth: 500
- template: templates/backoffice-install.yml
- script: npm run build:for:npm
displayName: Run build:for:npm
workingDirectory: src/Umbraco.Web.UI.Client
- bash: |
echo "##[command]Running npm pack"
echo "##[debug]Output directory: $(Build.ArtifactStagingDirectory)"
mkdir $(Build.ArtifactStagingDirectory)/npm
npm pack --pack-destination $(Build.ArtifactStagingDirectory)/npm
mv .npmrc $(Build.ArtifactStagingDirectory)/npm/
displayName: Run npm pack
workingDirectory: src/Umbraco.Web.UI.Client
- task: PublishPipelineArtifact@1
displayName: Publish Bellissima npm artifact
inputs:
targetPath: $(Build.ArtifactStagingDirectory)/npm
artifactName: npm
- stage: Integration
displayName: Integration Tests
dependsOn: Build
condition: ${{ eq(parameters.skipIntegrationTests, false) }}
jobs:
# Integration Tests (SQLite)
- job:
timeoutInMinutes: 180
displayName: Integration Tests (SQLite)
strategy:
matrix:
# Windows:
# vmImage: 'windows-latest'
# We split the tests into 4 parts for each OS to reduce the time it takes to run them on the pipeline
LinuxPart1Of4:
vmImage: "ubuntu-latest"
# Filter tests that are part of the Umbraco.Infrastructure namespace but not part of the Umbraco.Infrastructure.Service namespace
testFilter: "(FullyQualifiedName~Umbraco.Infrastructure) & (FullyQualifiedName!~Umbraco.Infrastructure.Service)"
LinuxPart2Of4:
vmImage: "ubuntu-latest"
# Filter tests that are part of the Umbraco.Infrastructure.Service namespace
testFilter: "(FullyQualifiedName~Umbraco.Infrastructure.Service)"
LinuxPart3Of4:
vmImage: "ubuntu-latest"
# Filter tests that are not part of the Umbraco.Infrastructure and ManagementApi namespace. So this will run all tests that are not part of the Umbraco.Infrastructure namespace
testFilter: "(FullyQualifiedName!~Umbraco.Infrastructure) & (FullyQualifiedName!~ManagementApi)"
LinuxPart4Of4:
vmImage: "ubuntu-latest"
# Filter tests that are part of the ManagementApi namespace
testFilter: "(FullyQualifiedName~ManagementApi)"
macOSPart1Of4:
vmImage: "macOS-latest"
# Filter tests that are part of the Umbraco.Infrastructure namespace but not part of the Umbraco.Infrastructure.Service namespace
testFilter: "(FullyQualifiedName~Umbraco.Infrastructure) & (FullyQualifiedName!~Umbraco.Infrastructure.Service)"
macOSPart2Of4:
vmImage: "macOS-latest"
# Filter tests that are part of the Umbraco.Infrastructure.Service namespace
testFilter: "(FullyQualifiedName~Umbraco.Infrastructure.Service)"
macOSPart3Of4:
vmImage: "macOS-latest"
# Filter tests that are not part of the Umbraco.Infrastructure and ManagementApi namespace.
testFilter: "(FullyQualifiedName!~Umbraco.Infrastructure) & (FullyQualifiedName!~ManagementApi)"
macOSPart4Of4:
vmImage: "macOS-latest"
# Filter tests that are part of the ManagementApi namespace.
testFilter: "(FullyQualifiedName~ManagementApi)"
pool:
vmImage: $(vmImage)
variables:
Tests__Database__DatabaseType: "Sqlite"
steps:
- checkout: self
submodules: false
lfs: false,
fetchDepth: 1
fetchFilter: tree:0
# Setup test environment
- task: DownloadPipelineArtifact@2
displayName: Download build artifacts
inputs:
artifact: build_output
path: $(Build.SourcesDirectory)
- task: UseDotNet@2
displayName: Use .NET SDK from global.json
inputs:
useGlobalJson: true
# Test
- task: DotNetCoreCLI@2
displayName: Run dotnet test
inputs:
command: test
projects: "tests/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj"
testRunTitle: Integration Tests SQLite - $(Agent.OS)
arguments: '--filter "$(testFilter)" --configuration $(buildConfiguration) --no-build'
# Integration Tests (SQL Server)
- job:
timeoutInMinutes: 180
displayName: Integration Tests (SQL Server)
variables:
SA_PASSWORD: UmbracoAcceptance123!
strategy:
matrix:
# We split the tests into 4 parts for each OS to reduce the time it takes to run them on the pipeline
WindowsPart1Of4:
vmImage: "windows-latest"
Tests__Database__DatabaseType: LocalDb
Tests__Database__SQLServerMasterConnectionString: N/A
# Filter tests that are part of the Umbraco.Infrastructure namespace but not part of the Umbraco.Infrastructure.Service namespace
testFilter: "(FullyQualifiedName~Umbraco.Infrastructure) & (FullyQualifiedName!~Umbraco.Infrastructure.Service)"
WindowsPart2Of4:
vmImage: "windows-latest"
Tests__Database__DatabaseType: LocalDb
Tests__Database__SQLServerMasterConnectionString: N/A
# Filter tests that are part of the Umbraco.Infrastructure.Service namespace
testFilter: "(FullyQualifiedName~Umbraco.Infrastructure.Service)"
WindowsPart3Of4:
vmImage: "windows-latest"
Tests__Database__DatabaseType: LocalDb
Tests__Database__SQLServerMasterConnectionString: N/A
# Filter tests that are not part of the Umbraco.Infrastructure and ManagementApi namespace.
testFilter: "(FullyQualifiedName!~Umbraco.Infrastructure) & (FullyQualifiedName!~ManagementApi)"
WindowsPart4Of4:
vmImage: "windows-latest"
Tests__Database__DatabaseType: LocalDb
Tests__Database__SQLServerMasterConnectionString: N/A
# Filter tests that are part of the ManagementApi namespace.
testFilter: "(FullyQualifiedName~ManagementApi)"
LinuxPart1Of4:
vmImage: "ubuntu-latest"
Tests__Database__DatabaseType: SqlServer
Tests__Database__SQLServerMasterConnectionString: "Server=(local);User Id=sa;Password=$(SA_PASSWORD);Encrypt=True;TrustServerCertificate=True"
# Filter tests that are part of the Umbraco.Infrastructure namespace but not part of the Umbraco.Infrastructure.Service namespace
testFilter: "(FullyQualifiedName~Umbraco.Infrastructure) & (FullyQualifiedName!~Umbraco.Infrastructure.Service)"
LinuxPart2Of4:
vmImage: "ubuntu-latest"
Tests__Database__DatabaseType: SqlServer
Tests__Database__SQLServerMasterConnectionString: "Server=(local);User Id=sa;Password=$(SA_PASSWORD);Encrypt=True;TrustServerCertificate=True"
# Filter tests that are part of the Umbraco.Infrastructure.Service namespace
testFilter: "(FullyQualifiedName~Umbraco.Infrastructure.Service)"
LinuxPart3Of4:
vmImage: "ubuntu-latest"
Tests__Database__DatabaseType: SqlServer
Tests__Database__SQLServerMasterConnectionString: "Server=(local);User Id=sa;Password=$(SA_PASSWORD);Encrypt=True;TrustServerCertificate=True"
# Filter tests that are not part of the Umbraco.Infrastructure and ManagementApi namespace.
testFilter: "(FullyQualifiedName!~Umbraco.Infrastructure) & (FullyQualifiedName!~ManagementApi)"
LinuxPart4Of4:
vmImage: "ubuntu-latest"
Tests__Database__DatabaseType: SqlServer
Tests__Database__SQLServerMasterConnectionString: "Server=(local);User Id=sa;Password=$(SA_PASSWORD);Encrypt=True;TrustServerCertificate=True"
# Filter tests that are part of the ManagementApi namespace.
testFilter: "(FullyQualifiedName~ManagementApi)"
pool:
vmImage: $(vmImage)
steps:
# Setup test environment
- task: DownloadPipelineArtifact@2
displayName: Download build artifacts
inputs:
artifact: build_output
path: $(Build.SourcesDirectory)
- task: UseDotNet@2
displayName: Use .NET SDK from global.json
inputs:
useGlobalJson: true
# Start SQL Server
- powershell: docker run --name mssql -d -p 1433:1433 -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=$(SA_PASSWORD)" mcr.microsoft.com/mssql/server:2022-latest
displayName: Start SQL Server Docker image (Linux)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
- powershell: |
$maxAttempts = 12
$attempt = 0
$status = ""
while (($status -ne 'running') -and ($attempt -lt $maxAttempts)) {
Start-Sleep -Seconds 5
# We use the docker inspect command to check the status of the container. If the container is not running, we wait 5 seconds and try again. And if reaches 12 attempts, we fail the build.
$status = docker inspect -f '{{.State.Status}}' mssql
if ($status -ne 'running') {
Write-Host "Waiting for SQL Server to be ready... Attempt $($attempt + 1)"
$attempt++
}
}
if ($status -eq 'running') {
Write-Host "SQL Server container is running"
docker ps -a
} else {
Write-Host "SQL Server did not become ready in time. Last known status: $status"
docker logs mssql
exit 1
}
displayName: Wait for SQL Server to be ready (Linux)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
- pwsh: SqlLocalDB start MSSQLLocalDB
displayName: Start SQL Server LocalDB (Windows)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
# Test
- task: DotNetCoreCLI@2
displayName: Run dotnet test
inputs:
command: test
projects: "tests/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj"
testRunTitle: Integration Tests SQL Server - $(Agent.OS)
arguments: '--filter "$(testFilter)" --configuration $(buildConfiguration) --no-build'
# Stop SQL Server
- pwsh: docker stop mssql
displayName: Stop SQL Server Docker image (Linux)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
- pwsh: SqlLocalDB stop MSSQLLocalDB
displayName: Stop SQL Server LocalDB (Windows)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
- stage: DefaultConfigE2E
displayName: Default Config E2E Tests
- stage: E2E
displayName: E2E Tests
dependsOn: Build
variables:
npm_config_cache: $(Pipeline.Workspace)/.npm_e2e
@@ -340,290 +104,338 @@ stages:
- job:
displayName: E2E Tests (SQLite)
timeoutInMinutes: 180
condition: ${{ eq(parameters.skipDefaultConfigAcceptanceTests, false) }}
variables:
# Connection string
CONNECTIONSTRINGS__UMBRACODBDSN: Data Source=Umbraco;Mode=Memory;Cache=Shared;Foreign Keys=True;Pooling=True
CONNECTIONSTRINGS__UMBRACODBDSN_PROVIDERNAME: Microsoft.Data.Sqlite
DatabaseType: SQLite
strategy:
matrix:
LinuxPart1Of3:
vmImage: "ubuntu-latest"
testFolder: "DefaultConfig"
testCommand: "npm run testSqlite -- --shard=1/3"
testCommand: "npm run test -- --shard=1/3"
LinuxPart2Of3:
vmImage: "ubuntu-latest"
testFolder: "DefaultConfig"
testCommand: "npm run testSqlite -- --shard=2/3"
testCommand: "npm run test -- --shard=2/3"
LinuxPart3Of3:
vmImage: "ubuntu-latest"
testFolder: "DefaultConfig"
testCommand: "npm run testSqlite -- --shard=3/3"
testCommand: "npm run test -- --shard=3/3"
WindowsPart1Of3:
vmImage: "windows-latest"
testFolder: "DefaultConfig"
testCommand: "npm run testSqlite -- --shard=1/3"
testCommand: "npm run test -- --shard=1/3"
WindowsPart2Of3:
vmImage: "windows-latest"
testFolder: "DefaultConfig"
testCommand: "npm run testSqlite -- --shard=2/3"
testCommand: "npm run test -- --shard=2/3"
WindowsPart3Of3:
vmImage: "windows-latest"
testFolder: "DefaultConfig"
testCommand: "npm run testSqlite -- --shard=3/3"
testCommand: "npm run test -- --shard=3/3"
pool:
vmImage: $(vmImage)
steps:
# Setup test environment Template
- template: nightly-E2E-setup-template.yml
parameters:
nodeVersion: ${{ variables.nodeVersion }}
PlaywrightUserEmail: ${{ variables.UMBRACO__CMS__UNATTENDED__UNATTENDEDUSEREMAIL }}
PlaywrightPassword: ${{ variables.UMBRACO__CMS__UNATTENDED__UNATTENDEDUSERPASSWORD }}
ASPNETCORE_URLS: ${{ variables.ASPNETCORE_URLS }}
npm_config_cache: ${{ variables.npm_config_cache }}
# Setup test environment
- task: DownloadPipelineArtifact@2
displayName: Download NuGet artifacts
inputs:
artifact: nupkg
path: $(Agent.BuildDirectory)/app/nupkg
- task: NodeTool@0
displayName: Use Node.js $(nodeVersion)
retryCountOnTaskFailure: 3
inputs:
versionSpec: $(nodeVersion)
- task: UseDotNet@2
displayName: Use .NET SDK from global.json
inputs:
useGlobalJson: true
- pwsh: |
"UMBRACO_USER_LOGIN=$(UMBRACO__CMS__UNATTENDED__UNATTENDEDUSEREMAIL)
UMBRACO_USER_PASSWORD=$(UMBRACO__CMS__UNATTENDED__UNATTENDEDUSERPASSWORD)
URL=$(ASPNETCORE_URLS)
STORAGE_STAGE_PATH=$(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest/playwright/.auth/user.json" | Out-File .env
displayName: Generate .env
workingDirectory: $(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest
# Cache and restore NPM packages
- task: Cache@2
displayName: Cache NPM packages
inputs:
key: 'npm_e2e | "$(Agent.OS)" | $(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest/package-lock.json'
restoreKeys: |
npm_e2e | "$(Agent.OS)"
npm_e2e
path: $(npm_config_cache)
- script: npm ci --no-fund --no-audit --prefer-offline
workingDirectory: $(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest
displayName: Restore NPM packages
# Build application
- pwsh: |
$cmsVersion = "$(Build.BuildNumber)" -replace "\+",".g"
dotnet new nugetconfig
dotnet nuget add source ./nupkg --name Local
dotnet new install Umbraco.Templates::$cmsVersion
dotnet new umbraco --name UmbracoProject --version $cmsVersion --exclude-gitignore --no-restore --no-update-check
dotnet restore UmbracoProject
cp $(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest.UmbracoProject/*.cs UmbracoProject
displayName: Restore project
workingDirectory: $(Agent.BuildDirectory)/app
- pwsh: |
dotnet build UmbracoProject --configuration ${{ variables.buildConfiguration }} --no-restore
dotnet build UmbracoProject --configuration $(buildConfiguration) --no-restore
dotnet dev-certs https
displayName: Build application
workingDirectory: $(Agent.BuildDirectory)/app
condition: succeeded()
# Run application Template
- template: nightly-E2E-run-application-template.yml
parameters:
DatabaseType: ${{ variables.DatabaseType }}
buildConfiguration: ${{ variables.buildConfiguration }}
# Run application
- bash: |
nohup dotnet run --project UmbracoProject --configuration $(buildConfiguration) --no-build --no-launch-profile > $(Build.ArtifactStagingDirectory)/playwright.log 2>&1 &
echo "##vso[task.setvariable variable=AcceptanceTestProcessId]$!"
displayName: Run application (Linux)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
workingDirectory: $(Agent.BuildDirectory)/app
# Run tests Template
- template: nightly-E2E-run-tests-template.yml
parameters:
testCommand: $(testCommand)
ASPNETCORE_URLS: ${{ variables.ASPNETCORE_URLS }}
DatabaseType: ${{ variables.DatabaseType }}
- pwsh: |
$process = Start-Process dotnet "run --project UmbracoProject --configuration $(buildConfiguration) --no-build --no-launch-profile 2>&1" -PassThru -NoNewWindow -RedirectStandardOutput $(Build.ArtifactStagingDirectory)/playwright.log
Write-Host "##vso[task.setvariable variable=AcceptanceTestProcessId]$($process.Id)"
displayName: Run application (Windows)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
workingDirectory: $(Agent.BuildDirectory)/app
# Ensures we have the package wait-on installed
- pwsh: npm install wait-on
displayName: Install wait-on package
# Wait for application to start responding to requests
- pwsh: npx wait-on -v --interval 1000 --timeout 120000 $(ASPNETCORE_URLS)
displayName: Wait for application
workingDirectory: tests/Umbraco.Tests.AcceptanceTest
# Install Playwright and dependencies
- pwsh: npx playwright install --with-deps
displayName: Install Playwright
workingDirectory: tests/Umbraco.Tests.AcceptanceTest
# Test
- pwsh: $(testCommand)
displayName: Run Playwright tests
continueOnError: true
workingDirectory: tests/Umbraco.Tests.AcceptanceTest
env:
CI: true
CommitId: $(Build.SourceVersion)
AgentOs: $(Agent.OS)
# Stop application
- bash: kill -15 $(AcceptanceTestProcessId)
displayName: Stop application (Linux)
condition: and(succeeded(), ne(variables.AcceptanceTestProcessId, ''), eq(variables['Agent.OS'], 'Linux'))
- pwsh: Stop-Process -Id $(AcceptanceTestProcessId)
displayName: Stop application (Windows)
condition: and(succeeded(), ne(variables.AcceptanceTestProcessId, ''), eq(variables['Agent.OS'], 'Windows_NT'))
# Copy artifacts
- pwsh: |
if (Test-Path tests/Umbraco.Tests.AcceptanceTest/results/*) {
Copy-Item tests/Umbraco.Tests.AcceptanceTest/results/* $(Build.ArtifactStagingDirectory) -Recurse
}
displayName: Copy Playwright results
condition: succeededOrFailed()
# Publish
- task: PublishPipelineArtifact@1
displayName: Publish test artifacts
condition: succeededOrFailed()
inputs:
targetPath: $(Build.ArtifactStagingDirectory)
artifact: "Acceptance Test Results - $(Agent.JobName) - Attempt #$(System.JobAttempt)"
# Publish test results
- task: PublishTestResults@2
displayName: "Publish test results"
condition: succeededOrFailed()
inputs:
testResultsFormat: 'JUnit'
testResultsFiles: '*.xml'
searchFolder: "tests/Umbraco.Tests.AcceptanceTest/results"
testRunTitle: "$(Agent.JobName)"
- job:
displayName: E2E Tests (SQL Server)
timeoutInMinutes: 180
condition: ${{ eq(parameters.skipDefaultConfigAcceptanceTests, false) }}
variables:
# Connection string
CONNECTIONSTRINGS__UMBRACODBDSN: Data Source=(localdb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\Umbraco.mdf;Integrated Security=True
CONNECTIONSTRINGS__UMBRACODBDSN_PROVIDERNAME: Microsoft.Data.SqlClient
DatabaseType: SQLServer
SA_PASSWORD: UmbracoAcceptance123!
strategy:
matrix:
LinuxPart1Of3:
testCommand: "npm run test -- --shard=1/3"
testFolder: "DefaultConfig"
testCommand: "npm run testSqlite -- --shard=1/3"
vmImage: "ubuntu-latest"
CONNECTIONSTRINGS__UMBRACODBDSN: "Server=(local);Database=Umbraco;User Id=sa;Password=$(SA_PASSWORD);Encrypt=True;TrustServerCertificate=True"
SA_PASSWORD: $(UMBRACO__CMS__UNATTENDED__UNATTENDEDUSERPASSWORD)
CONNECTIONSTRINGS__UMBRACODBDSN: "Server=(local);Database=Umbraco;User Id=sa;Password=$(SA_PASSWORD);TrustServerCertificate=True"
LinuxPart2Of3:
testCommand: "npm run test -- --shard=2/3"
testFolder: "DefaultConfig"
testCommand: "npm run testSqlite -- --shard=2/3"
vmImage: "ubuntu-latest"
CONNECTIONSTRINGS__UMBRACODBDSN: "Server=(local);Database=Umbraco;User Id=sa;Password=$(SA_PASSWORD);Encrypt=True;TrustServerCertificate=True"
SA_PASSWORD: $(UMBRACO__CMS__UNATTENDED__UNATTENDEDUSERPASSWORD)
CONNECTIONSTRINGS__UMBRACODBDSN: "Server=(local);Database=Umbraco;User Id=sa;Password=$(SA_PASSWORD);TrustServerCertificate=True"
LinuxPart3Of3:
testCommand: "npm run test -- --shard=3/3"
testFolder: "DefaultConfig"
testCommand: "npm run testSqlite -- --shard=3/3"
vmImage: "ubuntu-latest"
CONNECTIONSTRINGS__UMBRACODBDSN: "Server=(local);Database=Umbraco;User Id=sa;Password=$(SA_PASSWORD);Encrypt=True;TrustServerCertificate=True"
SA_PASSWORD: $(UMBRACO__CMS__UNATTENDED__UNATTENDEDUSERPASSWORD)
CONNECTIONSTRINGS__UMBRACODBDSN: "Server=(local);Database=Umbraco;User Id=sa;Password=$(SA_PASSWORD);TrustServerCertificate=True"
WindowsPart1Of3:
testCommand: "npm run test -- --shard=1/3"
testFolder: "DefaultConfig"
vmImage: "windows-latest"
testCommand: "npm run testSqlite -- --shard=1/3"
WindowsPart2Of3:
testCommand: "npm run test -- --shard=2/3"
testFolder: "DefaultConfig"
vmImage: "windows-latest"
testCommand: "npm run testSqlite -- --shard=2/3"
WindowsPart3Of3:
testCommand: "npm run test -- --shard=3/3"
testFolder: "DefaultConfig"
vmImage: "windows-latest"
testCommand: "npm run testSqlite -- --shard=3/3"
pool:
vmImage: $(vmImage)
steps:
# Setup test environment Template
- template: nightly-E2E-setup-template.yml
parameters:
nodeVersion: ${{ variables.nodeVersion }}
PlaywrightUserEmail: ${{ variables.UMBRACO__CMS__UNATTENDED__UNATTENDEDUSEREMAIL }}
PlaywrightPassword: ${{ variables.UMBRACO__CMS__UNATTENDED__UNATTENDEDUSERPASSWORD }}
ASPNETCORE_URLS: ${{ variables.ASPNETCORE_URLS }}
npm_config_cache: ${{ variables.npm_config_cache }}
# Setup test environment
- task: DownloadPipelineArtifact@2
displayName: Download NuGet artifacts
inputs:
artifact: nupkg
path: $(Agent.BuildDirectory)/app/nupkg
- task: NodeTool@0
displayName: Use Node.js $(nodeVersion)
inputs:
versionSpec: $(nodeVersion)
- task: UseDotNet@2
displayName: Use .NET SDK from global.json
inputs:
useGlobalJson: true
- pwsh: |
"UMBRACO_USER_LOGIN=$(UMBRACO__CMS__UNATTENDED__UNATTENDEDUSEREMAIL)
UMBRACO_USER_PASSWORD=$(UMBRACO__CMS__UNATTENDED__UNATTENDEDUSERPASSWORD)
URL=$(ASPNETCORE_URLS)
STORAGE_STAGE_PATH=$(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest/playwright/.auth/user.json" | Out-File .env
displayName: Generate .env
workingDirectory: $(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest
# Cache and restore NPM packages
- task: Cache@2
displayName: Cache NPM packages
inputs:
key: 'npm_e2e | "$(Agent.OS)" | $(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest/package-lock.json'
restoreKeys: |
npm_e2e | "$(Agent.OS)"
npm_e2e
path: $(npm_config_cache)
- script: npm ci --no-fund --no-audit --prefer-offline
workingDirectory: $(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest
displayName: Restore NPM packages
# Build application
- pwsh: |
$cmsVersion = "$(Build.BuildNumber)" -replace "\+",".g"
dotnet new nugetconfig
dotnet nuget add source ./nupkg --name Local
dotnet new install Umbraco.Templates::$cmsVersion
dotnet new umbraco --name UmbracoProject --version $cmsVersion --exclude-gitignore --no-restore --no-update-check
dotnet restore UmbracoProject
cp $(Build.SourcesDirectory)/tests/Umbraco.Tests.AcceptanceTest.UmbracoProject/*.cs UmbracoProject
displayName: Restore project
workingDirectory: $(Agent.BuildDirectory)/app
- pwsh: |
dotnet build UmbracoProject --configuration ${{ variables.buildConfiguration }} --no-restore
dotnet build UmbracoProject --configuration $(buildConfiguration) --no-restore
dotnet dev-certs https
displayName: Build application
workingDirectory: $(Agent.BuildDirectory)/app
condition: succeeded()
# Run application Template
- template: nightly-E2E-run-application-template.yml
parameters:
SA_PASSWORD: ${{ variables.SA_PASSWORD }}
buildConfiguration: ${{ variables.buildConfiguration }}
DatabaseType: ${{ variables.DatabaseType }}
# Start SQL Server
- powershell: docker run --name mssql -d -p 1433:1433 -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=$(SA_PASSWORD)" mcr.microsoft.com/mssql/server:2022-latest
displayName: Start SQL Server Docker image (Linux)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
# Run tests Template
- template: nightly-E2E-run-tests-template.yml
parameters:
testCommand: $(testCommand)
ASPNETCORE_URLS: ${{ variables.ASPNETCORE_URLS }}
DatabaseType: ${{ variables.DatabaseType }}
- pwsh: SqlLocalDB start MSSQLLocalDB
displayName: Start SQL Server LocalDB (Windows)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
- stage: AdditionalConfigE2E
displayName: Additional Config E2E Tests
dependsOn: Build
variables:
npm_config_cache: $(Pipeline.Workspace)/.npm_e2e
ASPNETCORE_URLS: https://localhost:44331
PlaywrightPassword: UmbracoAcceptance123!
PlaywrightUserEmail: playwright@umbraco.com
jobs:
- job:
displayName: E2E Tests with Different App settings (SQL Server)
condition: ${{ eq(parameters.differentAppSettingsAcceptanceTests, true) }}
timeoutInMinutes: 180
variables:
SA_PASSWORD: UmbracoAcceptance123!
DatabaseType: SQLServer
strategy:
matrix:
# UnattendedInstallConfig
WindowsUnattendedInstallConfig:
vmImage: "windows-latest"
testFolder: "UnattendedInstallConfig"
testCommand: "npx playwright test --project=unattendedInstallConfig --grep=InstallSQLServer"
port: 44331
additionalEnvironmentVariables: false
# DeliveryApiConfig
WindowsDeliveryApiConfig:
vmImage: "windows-latest"
testFolder: "DeliveryApi"
port: ''
testCommand: "npx playwright test --project=deliveryApi"
CONNECTIONSTRINGS__UMBRACODBDSN: Data Source=(localdb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\Umbraco.mdf;Integrated Security=True
CONNECTIONSTRINGS__UMBRACODBDSN_PROVIDERNAME: Microsoft.Data.SqlClient
additionalEnvironmentVariables: false
LinuxDeliveryApiConfig:
vmImage: "ubuntu-latest"
testFolder: "DeliveryApi"
port: ''
testCommand: "npx playwright test --project=deliveryApi"
CONNECTIONSTRINGS__UMBRACODBDSN: Server=(local);Database=Umbraco;User Id=sa;Password=$(SA_PASSWORD);Encrypt=True;TrustServerCertificate=True
CONNECTIONSTRINGS__UMBRACODBDSN_PROVIDERNAME: Microsoft.Data.SqlClient
additionalEnvironmentVariables: false
# ExternalLogin AzureADB2C
WindowsExternalLoginAzureADB2C:
vmImage: "windows-latest"
testFolder: "ExternalLogin\\AzureADB2C"
testCommand: "npx playwright test --project=externalLoginAzureADB2C"
port: 44331
packageName: "Microsoft.AspNetCore.Authentication.OpenIdConnect"
packageVersion: "9.0.8"
CONNECTIONSTRINGS__UMBRACODBDSN: Data Source=(localdb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\Umbraco.mdf;Integrated Security=True
CONNECTIONSTRINGS__UMBRACODBDSN_PROVIDERNAME: Microsoft.Data.SqlClient
additionalEnvironmentVariables: true
pool:
vmImage: $(vmImage)
steps:
# Setup test environment Template
- template: nightly-E2E-setup-template.yml
parameters:
nodeVersion: ${{ variables.nodeVersion }}
PlaywrightUserEmail: ${{ variables.PlaywrightUserEmail }}
PlaywrightPassword: ${{ variables.PlaywrightPassword }}
ASPNETCORE_URLS: ${{ variables.ASPNETCORE_URLS }}
npm_config_cache: ${{ variables.npm_config_cache }}
# Install NuGet package if specified in the matrix
- pwsh: |
Write-Host "Installing package $(packageName) version $(packageVersion)"
dotnet add package $(packageName) --version $(packageVersion)
displayName: "Install NuGet package: $(packageName)"
workingDirectory: $(Agent.BuildDirectory)/app/UmbracoProject
condition: and(succeeded(), ne(variables['packageName'], ''), ne(variables['packageVersion'], ''))
# Build application Template
- template: nightly-E2E-build-template.yml
parameters:
testFolder: $(testFolder)
buildConfiguration: ${{ variables.buildConfiguration }}
additionalEnvironmentVariables: ${{ eq(variables['additionalEnvironmentVariables'], true) }}
# Build application for AzureADB2C
- pwsh: |
dotnet build UmbracoProject --configuration ${{ variables.buildConfiguration }} --no-restore
dotnet dev-certs https
displayName: Build application for AzureADB2C
workingDirectory: $(Agent.BuildDirectory)/app
env:
AZUREADB2CDOMAIN: $(AZUREB2CDOMAIN)
AZUREADB2CTENANT: $(AZUREB2CTENANT)
AZUREADB2CPOLICY: $(AZUREB2CPOLICY)
AZUREADB2CCLIENTID: $(AZUREB2CCLIENTID)
AZUREADB2CCLIENTSECRET: $(AZUREB2CCLIENTSECRET)
condition: and(succeeded(), eq(variables['testFolder'], 'ExternalLogin\AzureADB2C'))
# Run application Template
- template: nightly-E2E-run-application-template.yml
parameters:
SA_PASSWORD: ${{ variables.SA_PASSWORD }}
additionalEnvironmentVariables: ${{ eq(variables['additionalEnvironmentVariables'], true ) }}
buildConfiguration: ${{ variables.buildConfiguration }}
DatabaseType: ${{ variables.DatabaseType }}
# Run application for Linux with additional Environment Variables for Azure AD
# Run application
- bash: |
nohup dotnet run --project UmbracoProject --configuration ${{ variables.buildConfiguration }} --no-build --no-launch-profile > $(Build.ArtifactStagingDirectory)/playwright.log 2>&1 &
nohup dotnet run --project UmbracoProject --configuration $(buildConfiguration) --no-build --no-launch-profile > $(Build.ArtifactStagingDirectory)/playwright.log 2>&1 &
echo "##vso[task.setvariable variable=AcceptanceTestProcessId]$!"
displayName: Run application (Linux)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'), eq(variables['testFolder'], 'ExternalLogin\AzureADB2C'))
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
workingDirectory: $(Agent.BuildDirectory)/app
env:
AZUREADB2CDOMAIN: $(AZUREB2CDOMAIN)
AZUREADB2CTENANT: $(AZUREB2CTENANT)
AZUREADB2CPOLICY: $(AZUREB2CPOLICY)
AZUREADB2CCLIENTID: $(AZUREB2CCLIENTID)
AZUREADB2CCLIENTSECRET: $(AZUREB2CCLIENTSECRET)
# Run application for Windows with additional Environment Variables for Azure AD
- pwsh: |
$process = Start-Process dotnet "run --project UmbracoProject --configuration ${{ variables.buildConfiguration }} --no-build --no-launch-profile 2>&1" -PassThru -NoNewWindow -RedirectStandardOutput $(Build.ArtifactStagingDirectory)/playwright.log
$process = Start-Process dotnet "run --project UmbracoProject --configuration $(buildConfiguration) --no-build --no-launch-profile 2>&1" -PassThru -NoNewWindow -RedirectStandardOutput $(Build.ArtifactStagingDirectory)/playwright.log
Write-Host "##vso[task.setvariable variable=AcceptanceTestProcessId]$($process.Id)"
displayName: Run application (Windows)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['testFolder'], 'ExternalLogin\AzureADB2C'))
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
workingDirectory: $(Agent.BuildDirectory)/app
env:
AZUREADB2CDOMAIN: $(AZUREB2CDOMAIN)
AZUREADB2CTENANT: $(AZUREB2CTENANT)
AZUREADB2CPOLICY: $(AZUREB2CPOLICY)
AZUREADB2CCLIENTID: $(AZUREB2CCLIENTID)
AZUREADB2CCLIENTSECRET: $(AZUREB2CCLIENTSECRET)
# Run tests Template
- template: nightly-E2E-run-tests-template.yml
parameters:
testCommand: $(testCommand)
ASPNETCORE_URLS: ${{ variables.ASPNETCORE_URLS }}
port: $(port)
AZUREB2CTESTUSEREMAIL: $(AZUREB2CTESTUSEREMAIL)
AZUREB2CTESTUSERPASSWORD: $(AZUREB2CTESTUSERPASSWORD)
DatabaseType: ${{ variables.DatabaseType }}
# Ensures we have the package wait-on installed
- pwsh: npm install wait-on
displayName: Install wait-on package
# Wait for application to start responding to requests
- pwsh: npx wait-on -v --interval 1000 --timeout 120000 $(ASPNETCORE_URLS)
displayName: Wait for application
workingDirectory: tests/Umbraco.Tests.AcceptanceTest
# Install Playwright and dependencies
- pwsh: npx playwright install --with-deps
displayName: Install Playwright
workingDirectory: tests/Umbraco.Tests.AcceptanceTest
# Test
- pwsh: $(testCommand)
displayName: Run Playwright tests
continueOnError: true
workingDirectory: tests/Umbraco.Tests.AcceptanceTest
env:
CI: true
CommitId: $(Build.SourceVersion)
AgentOs: $(Agent.OS)
# Stop application
- bash: kill -15 $(AcceptanceTestProcessId)
displayName: Stop application (Linux)
condition: and(succeeded(), ne(variables.AcceptanceTestProcessId, ''), eq(variables['Agent.OS'], 'Linux'))
- pwsh: Stop-Process -Id $(AcceptanceTestProcessId)
displayName: Stop application (Windows)
condition: and(succeeded(), ne(variables.AcceptanceTestProcessId, ''), eq(variables['Agent.OS'], 'Windows_NT'))
# Stop SQL Server
- pwsh: docker stop mssql
displayName: Stop SQL Server Docker image (Linux)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
- pwsh: SqlLocalDB stop MSSQLLocalDB
displayName: Stop SQL Server LocalDB (Windows)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
# Copy artifacts
- pwsh: |
if (Test-Path tests/Umbraco.Tests.AcceptanceTest/results/*) {
Copy-Item tests/Umbraco.Tests.AcceptanceTest/results/* $(Build.ArtifactStagingDirectory) -Recurse
}
displayName: Copy Playwright results
condition: succeededOrFailed()
# Publish
- task: PublishPipelineArtifact@1
displayName: Publish test artifacts
condition: succeededOrFailed()
inputs:
targetPath: $(Build.ArtifactStagingDirectory)
artifact: "Acceptance Test Results - $(Agent.JobName) - Attempt #$(System.JobAttempt)"
# Publish test results
- task: PublishTestResults@2
displayName: "Publish test results"
condition: succeededOrFailed()
inputs:
testResultsFormat: 'JUnit'
testResultsFiles: '*.xml'
searchFolder: "tests/Umbraco.Tests.AcceptanceTest/results"
testRunTitle: "$(Agent.JobName)"
@@ -7,7 +7,6 @@ using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using Umbraco.Cms.Api.Common.OpenApi;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Extensions;
namespace Umbraco.Cms.Api.Common.Configuration;
@@ -18,13 +17,6 @@ public class ConfigureUmbracoSwaggerGenOptions : IConfigureOptions<SwaggerGenOpt
private readonly ISchemaIdSelector _schemaIdSelector;
private readonly ISubTypesSelector _subTypesSelector;
[Obsolete("Use non-obsolete constructor. This will be removed in Umbraco 16.")]
public ConfigureUmbracoSwaggerGenOptions(
IOperationIdSelector operationIdSelector,
ISchemaIdSelector schemaIdSelector)
: this(operationIdSelector, schemaIdSelector, StaticServiceProvider.Instance.GetRequiredService<ISubTypesSelector>())
{ }
public ConfigureUmbracoSwaggerGenOptions(
IOperationIdSelector operationIdSelector,
ISchemaIdSelector schemaIdSelector,
@@ -5,8 +5,5 @@ namespace Umbraco.Cms.Api.Common.OpenApi;
public interface IOperationIdSelector
{
[Obsolete("Use overload that only takes ApiDescription instead. This will be removed in Umbraco 15.")]
string? OperationId(ApiDescription apiDescription, ApiVersioningOptions apiVersioningOptions);
string? OperationId(ApiDescription apiDescription);
}
@@ -16,9 +16,6 @@ public class OperationIdSelector : IOperationIdSelector
public OperationIdSelector(IEnumerable<IOperationIdHandler> operationIdHandlers)
=> _operationIdHandlers = operationIdHandlers;
[Obsolete("Use overload that only takes ApiDescription instead. This will be removed in Umbraco 15.")]
public virtual string? OperationId(ApiDescription apiDescription, ApiVersioningOptions apiVersioningOptions) => OperationId(apiDescription);
public virtual string? OperationId(ApiDescription apiDescription)
{
IOperationIdHandler? handler = _operationIdHandlers.FirstOrDefault(h => h.CanHandle(apiDescription));
@@ -10,12 +10,12 @@ namespace Umbraco.Cms.Api.Common.OpenApi;
public class SubTypesSelector : ISubTypesSelector
{
private readonly IOptions<GlobalSettings> _settings;
private readonly IHostingEnvironment _hostingEnvironment;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IEnumerable<ISubTypesHandler> _subTypeHandlers;
private readonly IUmbracoJsonTypeInfoResolver _umbracoJsonTypeInfoResolver;
[Obsolete("The settings parameter is not required anymore, use the other constructor instead. Scheduled for removal in Umbraco 17.")]
public SubTypesSelector(
IOptions<GlobalSettings> settings,
IHostingEnvironment hostingEnvironment,
@@ -23,7 +23,18 @@ public class SubTypesSelector : ISubTypesSelector
IEnumerable<ISubTypesHandler> subTypeHandlers,
IUmbracoJsonTypeInfoResolver umbracoJsonTypeInfoResolver)
{
_settings = settings;
_hostingEnvironment = hostingEnvironment;
_httpContextAccessor = httpContextAccessor;
_subTypeHandlers = subTypeHandlers;
_umbracoJsonTypeInfoResolver = umbracoJsonTypeInfoResolver;
}
public SubTypesSelector(
IHostingEnvironment hostingEnvironment,
IHttpContextAccessor httpContextAccessor,
IEnumerable<ISubTypesHandler> subTypeHandlers,
IUmbracoJsonTypeInfoResolver umbracoJsonTypeInfoResolver)
{
_hostingEnvironment = hostingEnvironment;
_httpContextAccessor = httpContextAccessor;
_subTypeHandlers = subTypeHandlers;
@@ -32,7 +43,7 @@ public class SubTypesSelector : ISubTypesSelector
public IEnumerable<Type> SubTypes(Type type)
{
var backOfficePath = _settings.Value.GetBackOfficePath(_hostingEnvironment);
var backOfficePath = _hostingEnvironment.GetBackOfficePath();
var swaggerPath = $"{backOfficePath}/swagger";
if (_httpContextAccessor.HttpContext?.Request.Path.StartsWithSegments(swaggerPath) ?? false)
@@ -7,7 +7,7 @@ using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using Swashbuckle.AspNetCore.SwaggerUI;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Hosting;
using Umbraco.Cms.Web.Common.ApplicationBuilder;
using Umbraco.Extensions;
using IHostingEnvironment = Umbraco.Cms.Core.Hosting.IHostingEnvironment;
@@ -30,24 +30,21 @@ public class SwaggerRouteTemplatePipelineFilter : UmbracoPipelineFilter
IOptions<SwaggerGenOptions> swaggerGenOptions = applicationBuilder.ApplicationServices.GetRequiredService<IOptions<SwaggerGenOptions>>();
applicationBuilder.UseSwagger(swaggerOptions =>
{
swaggerOptions.RouteTemplate = SwaggerRouteTemplate(applicationBuilder);
});
{
swaggerOptions.RouteTemplate = SwaggerRouteTemplate(applicationBuilder);
});
applicationBuilder.UseSwaggerUI(swaggerUiOptions => SwaggerUiConfiguration(swaggerUiOptions, swaggerGenOptions.Value, applicationBuilder));
}
protected virtual bool SwaggerIsEnabled(IApplicationBuilder applicationBuilder)
{
IWebHostEnvironment webHostEnvironment = applicationBuilder.ApplicationServices.GetRequiredService<IWebHostEnvironment>();
return webHostEnvironment.IsProduction() is false;
}
=> applicationBuilder.ApplicationServices.GetRequiredService<IWebHostEnvironment>().IsProduction() is false;
protected virtual string SwaggerRouteTemplate(IApplicationBuilder applicationBuilder)
=> $"{GetUmbracoPath(applicationBuilder).TrimStart(Constants.CharArrays.ForwardSlash)}/swagger/{{documentName}}/swagger.json";
=> $"{GetBackOfficePath(applicationBuilder).TrimStart(Constants.CharArrays.ForwardSlash)}/swagger/{{documentName}}/swagger.json";
protected virtual string SwaggerUiRoutePrefix(IApplicationBuilder applicationBuilder)
=> $"{GetUmbracoPath(applicationBuilder).TrimStart(Constants.CharArrays.ForwardSlash)}/swagger";
=> $"{GetBackOfficePath(applicationBuilder).TrimStart(Constants.CharArrays.ForwardSlash)}/swagger";
protected virtual void SwaggerUiConfiguration(
SwaggerUIOptions swaggerUiOptions,
@@ -56,8 +53,7 @@ public class SwaggerRouteTemplatePipelineFilter : UmbracoPipelineFilter
{
swaggerUiOptions.RoutePrefix = SwaggerUiRoutePrefix(applicationBuilder);
foreach ((var name, OpenApiInfo? apiInfo) in swaggerGenOptions.SwaggerGeneratorOptions.SwaggerDocs
.OrderBy(x => x.Value.Title))
foreach ((var name, OpenApiInfo? apiInfo) in swaggerGenOptions.SwaggerGeneratorOptions.SwaggerDocs.OrderBy(x => x.Value.Title))
{
swaggerUiOptions.SwaggerEndpoint($"{name}/swagger.json", $"{apiInfo.Title}");
}
@@ -70,11 +66,6 @@ public class SwaggerRouteTemplatePipelineFilter : UmbracoPipelineFilter
swaggerUiOptions.OAuthUsePkce();
}
private string GetUmbracoPath(IApplicationBuilder applicationBuilder)
{
GlobalSettings settings = applicationBuilder.ApplicationServices.GetRequiredService<IOptions<GlobalSettings>>().Value;
IHostingEnvironment hostingEnvironment = applicationBuilder.ApplicationServices.GetRequiredService<IHostingEnvironment>();
return settings.GetBackOfficePath(hostingEnvironment);
}
private string GetBackOfficePath(IApplicationBuilder applicationBuilder)
=> applicationBuilder.ApplicationServices.GetRequiredService<IHostingEnvironment>().GetBackOfficePath();
}
@@ -18,12 +18,7 @@ internal sealed class DeliveryApiOutputCachePolicy : IOutputCachePolicy
.RequestServices
.GetRequiredService<IRequestPreviewService>();
IApiAccessService apiAccessService = context
.HttpContext
.RequestServices
.GetRequiredService<IApiAccessService>();
context.EnableOutputCaching = requestPreviewService.IsPreview() is false && apiAccessService.HasPublicAccess();
context.EnableOutputCaching = requestPreviewService.IsPreview() is false;
context.ResponseExpirationTimeSpan = _duration;
return ValueTask.CompletedTask;
@@ -1,4 +1,3 @@
using System.Diagnostics;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
@@ -8,7 +7,6 @@ using Umbraco.Cms.Core.Models.PublishedContent;
namespace Umbraco.Cms.Api.Delivery.Controllers.Content;
[ApiVersion("1.0")]
[ApiVersion("2.0")]
public class ByIdContentApiController : ContentApiItemControllerBase
{
@@ -21,16 +19,6 @@ public class ByIdContentApiController : ContentApiItemControllerBase
: base(apiPublishedContentCache, apiContentResponseBuilder)
=> _requestMemberAccessService = requestMemberAccessService;
[HttpGet("item/{id:guid}")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(IApiContentResponse), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Obsolete("Please use version 2 of this API. Will be removed in V15.")]
public async Task<IActionResult> ById(Guid id)
=> await HandleRequest(id);
/// <summary>
/// Gets a content item by id.
/// </summary>
@@ -8,7 +8,6 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Api.Delivery.Controllers.Content;
[ApiVersion("1.0")]
[ApiVersion("2.0")]
public class ByIdsContentApiController : ContentApiItemControllerBase
{
@@ -21,15 +20,6 @@ public class ByIdsContentApiController : ContentApiItemControllerBase
: base(apiPublishedContentCache, apiContentResponseBuilder)
=> _requestMemberAccessService = requestMemberAccessService;
[HttpGet("item")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(IEnumerable<IApiContentResponse>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[Obsolete("Please use version 2 of this API. Will be removed in V15.")]
public async Task<IActionResult> Item([FromQuery(Name = "id")] HashSet<Guid> ids)
=> await HandleRequest(ids);
/// <summary>
/// Gets content items by ids.
/// </summary>
@@ -58,6 +48,6 @@ public class ByIdsContentApiController : ContentApiItemControllerBase
.WhereNotNull()
.ToArray();
return await Task.FromResult(Ok(apiContentItems));
return Ok(apiContentItems);
}
}
@@ -1,17 +1,13 @@
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.DeliveryApi;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Models.DeliveryApi;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Services;
namespace Umbraco.Cms.Api.Delivery.Controllers.Content;
[ApiVersion("1.0")]
[ApiVersion("2.0")]
public class ByRouteContentApiController : ContentApiItemControllerBase
{
@@ -21,45 +17,6 @@ public class ByRouteContentApiController : ContentApiItemControllerBase
private readonly IRequestMemberAccessService _requestMemberAccessService;
private const string PreviewContentRequestPathPrefix = $"/{Constants.DeliveryApi.Routing.PreviewContentPathPrefix}";
[Obsolete($"Please use the constructor that accepts {nameof(IApiContentPathResolver)}. Will be removed in V15.")]
public ByRouteContentApiController(
IApiPublishedContentCache apiPublishedContentCache,
IApiContentResponseBuilder apiContentResponseBuilder,
IRequestRoutingService requestRoutingService,
IRequestRedirectService requestRedirectService,
IRequestPreviewService requestPreviewService,
IRequestMemberAccessService requestMemberAccessService)
: this(
apiPublishedContentCache,
apiContentResponseBuilder,
requestRedirectService,
requestPreviewService,
requestMemberAccessService,
StaticServiceProvider.Instance.GetRequiredService<IApiContentPathResolver>())
{
}
[Obsolete($"Please use the non-obsolete constructor. Will be removed in V15.")]
public ByRouteContentApiController(
IApiPublishedContentCache apiPublishedContentCache,
IApiContentResponseBuilder apiContentResponseBuilder,
IPublicAccessService publicAccessService,
IRequestRoutingService requestRoutingService,
IRequestRedirectService requestRedirectService,
IRequestPreviewService requestPreviewService,
IRequestMemberAccessService requestMemberAccessService,
IApiContentPathResolver apiContentPathResolver)
: this(
apiPublishedContentCache,
apiContentResponseBuilder,
requestRedirectService,
requestPreviewService,
requestMemberAccessService,
apiContentPathResolver)
{
}
[ActivatorUtilitiesConstructor]
public ByRouteContentApiController(
IApiPublishedContentCache apiPublishedContentCache,
IApiContentResponseBuilder apiContentResponseBuilder,
@@ -75,16 +32,6 @@ public class ByRouteContentApiController : ContentApiItemControllerBase
_apiContentPathResolver = apiContentPathResolver;
}
[HttpGet("item/{*path}")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(IApiContentResponse), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Obsolete("Please use version 2 of this API. Will be removed in V15.")]
public async Task<IActionResult> ByRoute(string path = "")
=> await HandleRequest(path);
/// <summary>
/// Gets a content item by route.
/// </summary>
@@ -117,7 +64,7 @@ public class ByRouteContentApiController : ContentApiItemControllerBase
return deniedAccessResult;
}
return await Task.FromResult(Ok(ApiContentResponseBuilder.Build(contentItem)));
return Ok(ApiContentResponseBuilder.Build(contentItem));
}
IApiContentRoute? redirectRoute = _requestRedirectService.GetRedirectRoute(path);
@@ -12,7 +12,6 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Api.Delivery.Controllers.Content;
[ApiVersion("1.0")]
[ApiVersion("2.0")]
public class QueryContentApiController : ContentApiControllerBase
{
@@ -30,20 +29,6 @@ public class QueryContentApiController : ContentApiControllerBase
_requestMemberAccessService = requestMemberAccessService;
}
[HttpGet]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PagedViewModel<IApiContentResponse>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Obsolete("Please use version 2 of this API. Will be removed in V15.")]
public async Task<IActionResult> Query(
string? fetch,
[FromQuery] string[] filter,
[FromQuery] string[] sort,
int skip = 0,
int take = 10)
=> await HandleRequest(fetch, filter, sort, skip, take);
/// <summary>
/// Gets a paginated list of content item(s) from query.
/// </summary>
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Core.Models.DeliveryApi;
@@ -8,7 +8,6 @@ using Umbraco.Cms.Infrastructure.DeliveryApi;
namespace Umbraco.Cms.Api.Delivery.Controllers.Media;
[ApiVersion("1.0")]
[ApiVersion("2.0")]
public class ByIdMediaApiController : MediaApiControllerBase
{
@@ -19,14 +18,6 @@ public class ByIdMediaApiController : MediaApiControllerBase
{
}
[HttpGet("item/{id:guid}")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(IApiMediaWithCropsResponse), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Obsolete("Please use version 2 of this API. Will be removed in V15.")]
public async Task<IActionResult> ById(Guid id)
=> await HandleRequest(id);
/// <summary>
/// Gets a media item by id.
/// </summary>
@@ -36,16 +27,16 @@ public class ByIdMediaApiController : MediaApiControllerBase
[MapToApiVersion("2.0")]
[ProducesResponseType(typeof(IApiMediaWithCropsResponse), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> ByIdV20(Guid id)
=> await HandleRequest(id);
public Task<IActionResult> ByIdV20(Guid id)
=> Task.FromResult(HandleRequest(id));
private async Task<IActionResult> HandleRequest(Guid id)
private IActionResult HandleRequest(Guid id)
{
IPublishedContent? media = PublishedMediaCache.GetById(id);
if (media is null)
{
return await Task.FromResult(NotFound());
return NotFound();
}
return Ok(BuildApiMediaWithCrops(media));
@@ -9,7 +9,6 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Api.Delivery.Controllers.Media;
[ApiVersion("1.0")]
[ApiVersion("2.0")]
public class ByIdsMediaApiController : MediaApiControllerBase
{
@@ -18,13 +17,6 @@ public class ByIdsMediaApiController : MediaApiControllerBase
{
}
[HttpGet("item")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(IEnumerable<IApiMediaWithCropsResponse>), StatusCodes.Status200OK)]
[Obsolete("Please use version 2 of this API. Will be removed in V15.")]
public async Task<IActionResult> Item([FromQuery(Name = "id")] HashSet<Guid> ids)
=> await HandleRequest(ids);
/// <summary>
/// Gets media items by ids.
/// </summary>
@@ -33,10 +25,10 @@ public class ByIdsMediaApiController : MediaApiControllerBase
[HttpGet("items")]
[MapToApiVersion("2.0")]
[ProducesResponseType(typeof(IEnumerable<IApiMediaWithCropsResponse>), StatusCodes.Status200OK)]
public async Task<IActionResult> ItemsV20([FromQuery(Name = "id")] HashSet<Guid> ids)
=> await HandleRequest(ids);
public Task<IActionResult> ItemsV20([FromQuery(Name = "id")] HashSet<Guid> ids)
=> Task.FromResult(HandleRequest(ids));
private async Task<IActionResult> HandleRequest(HashSet<Guid> ids)
private IActionResult HandleRequest(HashSet<Guid> ids)
{
IPublishedContent[] mediaItems = ids
.Select(PublishedMediaCache.GetById)
@@ -47,6 +39,6 @@ public class ByIdsMediaApiController : MediaApiControllerBase
.Select(BuildApiMediaWithCrops)
.ToArray();
return await Task.FromResult(Ok(apiMediaItems));
return Ok(apiMediaItems);
}
}
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Core.DeliveryApi;
@@ -9,7 +9,6 @@ using Umbraco.Cms.Infrastructure.DeliveryApi;
namespace Umbraco.Cms.Api.Delivery.Controllers.Media;
[ApiVersion("1.0")]
[ApiVersion("2.0")]
public class ByPathMediaApiController : MediaApiControllerBase
{
@@ -22,14 +21,6 @@ public class ByPathMediaApiController : MediaApiControllerBase
: base(publishedMediaCache, apiMediaWithCropsResponseBuilder)
=> _apiMediaQueryService = apiMediaQueryService;
[HttpGet("item/{*path}")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(IApiMediaWithCropsResponse), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Obsolete("Please use version 2 of this API. Will be removed in V15.")]
public async Task<IActionResult> ByPath(string path)
=> await HandleRequest(path);
/// <summary>
/// Gets a media item by its path.
/// </summary>
@@ -39,17 +30,17 @@ public class ByPathMediaApiController : MediaApiControllerBase
[MapToApiVersion("2.0")]
[ProducesResponseType(typeof(IApiMediaWithCropsResponse), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> ByPathV20(string path)
=> await HandleRequest(path);
public Task<IActionResult> ByPathV20(string path)
=> Task.FromResult(HandleRequest(path));
private async Task<IActionResult> HandleRequest(string path)
private IActionResult HandleRequest(string path)
{
path = DecodePath(path);
IPublishedContent? media = _apiMediaQueryService.GetByPath(path);
if (media is null)
{
return await Task.FromResult(NotFound());
return NotFound();
}
return Ok(BuildApiMediaWithCrops(media));
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
@@ -14,7 +14,6 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Api.Delivery.Controllers.Media;
[ApiVersion("1.0")]
[ApiVersion("2.0")]
public class QueryMediaApiController : MediaApiControllerBase
{
@@ -27,19 +26,6 @@ public class QueryMediaApiController : MediaApiControllerBase
: base(publishedMediaCache, apiMediaWithCropsResponseBuilder)
=> _apiMediaQueryService = apiMediaQueryService;
[HttpGet]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PagedViewModel<IApiMediaWithCropsResponse>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
[Obsolete("Please use version 2 of this API. Will be removed in V15.")]
public async Task<IActionResult> Query(
string? fetch,
[FromQuery] string[] filter,
[FromQuery] string[] sort,
int skip = 0,
int take = 10)
=> await HandleRequest(fetch, filter, sort, skip, take);
/// <summary>
/// Gets a paginated list of media item(s) from query.
/// </summary>
@@ -53,15 +39,15 @@ public class QueryMediaApiController : MediaApiControllerBase
[MapToApiVersion("2.0")]
[ProducesResponseType(typeof(PagedViewModel<IApiMediaWithCropsResponse>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
public async Task<IActionResult> QueryV20(
public Task<IActionResult> QueryV20(
string? fetch,
[FromQuery] string[] filter,
[FromQuery] string[] sort,
int skip = 0,
int take = 10)
=> await HandleRequest(fetch, filter, sort, skip, take);
=> Task.FromResult(HandleRequest(fetch, filter, sort, skip, take));
private async Task<IActionResult> HandleRequest(string? fetch, string[] filter, string[] sort, int skip, int take)
private IActionResult HandleRequest(string? fetch, string[] filter, string[] sort, int skip, int take)
{
Attempt<PagedModel<Guid>, ApiMediaQueryOperationStatus> queryAttempt = _apiMediaQueryService.ExecuteQuery(fetch, filter, sort, skip, take);
@@ -79,6 +65,6 @@ public class QueryMediaApiController : MediaApiControllerBase
Items = mediaItems.Select(BuildApiMediaWithCrops)
};
return await Task.FromResult(Ok(model));
return Ok(model);
}
}
@@ -5,7 +5,6 @@ using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OpenIddict.Abstractions;
@@ -13,7 +12,6 @@ using OpenIddict.Server.AspNetCore;
using Umbraco.Cms.Api.Delivery.Routing;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Web.Common.Security;
using Umbraco.Extensions;
@@ -33,31 +31,6 @@ public class MemberController : DeliveryApiControllerBase
private readonly DeliveryApiSettings _deliveryApiSettings;
private readonly ILogger<MemberController> _logger;
[Obsolete("Please use the non-obsolete constructor. Will be removed in V16.")]
public MemberController(
IHttpContextAccessor httpContextAccessor,
IMemberSignInManager memberSignInManager,
IMemberManager memberManager,
IOptions<DeliveryApiSettings> deliveryApiSettings,
ILogger<MemberController> logger)
: this(memberSignInManager, memberManager, StaticServiceProvider.Instance.GetRequiredService<IMemberClientCredentialsManager>(), deliveryApiSettings, logger)
{
}
[Obsolete("Please use the non-obsolete constructor. Will be removed in V16.")]
public MemberController(
IHttpContextAccessor httpContextAccessor,
IMemberSignInManager memberSignInManager,
IMemberManager memberManager,
IMemberClientCredentialsManager memberClientCredentialsManager,
IOptions<DeliveryApiSettings> deliveryApiSettings,
ILogger<MemberController> logger)
: this(memberSignInManager, memberManager, memberClientCredentialsManager, deliveryApiSettings, logger)
{
}
[ActivatorUtilitiesConstructor]
public MemberController(
IMemberSignInManager memberSignInManager,
IMemberManager memberManager,
@@ -62,7 +62,6 @@ public static class UmbracoBuilderExtensions
builder.Services.AddTransient<IMemberApplicationManager, MemberApplicationManager>();
builder.Services.AddTransient<IRequestMemberAccessService, RequestMemberAccessService>();
builder.Services.AddTransient<ICurrentMemberClaimsProvider, CurrentMemberClaimsProvider>();
builder.Services.AddScoped<IMemberClientCredentialsManager, MemberClientCredentialsManager>();
builder.Services.ConfigureOptions<ConfigureUmbracoDeliveryApiSwaggerGenOptions>();
builder.AddUmbracoApiOpenApiUI();
@@ -91,7 +91,7 @@ internal sealed class InitializeMemberApplicationNotificationHandler : INotifica
}
}
private bool ValidateRedirectUrls(Uri[] redirectUrls)
private bool ValidateRedirectUrls(IEnumerable<Uri> redirectUrls)
{
if (redirectUrls.Any() is false)
{
@@ -24,7 +24,7 @@ public class BackOfficeLoginModel
public bool UserIsAlreadyLoggedIn { get; set; }
}
[ApiExplorerSettings(IgnoreApi=true)]
[ApiExplorerSettings(IgnoreApi = true)]
[Route(LoginPath)]
public class BackOfficeLoginController : Controller
{
@@ -51,7 +51,7 @@ public class BackOfficeLoginController : Controller
if (string.IsNullOrEmpty(model.UmbracoUrl))
{
model.UmbracoUrl = _hostingEnvironment.ToAbsolute(Constants.System.DefaultUmbracoPath);
model.UmbracoUrl = _hostingEnvironment.GetBackOfficePath();
}
if (string.IsNullOrEmpty(model.ReturnUrl))
@@ -1,4 +1,4 @@
using System.Globalization;
using System.Globalization;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
@@ -28,7 +28,7 @@ public class AllCultureController : CultureControllerBase
[HttpGet]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PagedViewModel<CultureReponseModel>), StatusCodes.Status200OK)]
public async Task<PagedViewModel<CultureReponseModel>> GetAll(CancellationToken cancellationToken, int skip = 0, int take = 100)
public Task<PagedViewModel<CultureReponseModel>> GetAll(CancellationToken cancellationToken, int skip = 0, int take = 100)
{
CultureInfo[] all = _cultureService.GetValidCultureInfos();
@@ -38,6 +38,6 @@ public class AllCultureController : CultureControllerBase
Total = all.Length
};
return await Task.FromResult(viewModel);
return Task.FromResult(viewModel);
}
}
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Core.Mapping;
@@ -38,6 +38,6 @@ public class AllDictionaryController : DictionaryControllerBase
Total = items.Length,
Items = _umbracoMapper.MapEnumerable<IDictionaryItem, DictionaryOverviewResponseModel>(items.Skip(skip).Take(take))
};
return await Task.FromResult(model);
return model;
}
}
@@ -28,7 +28,7 @@ public class DictionaryTreeControllerBase : NamedEntityTreeControllerBase<NamedE
protected IDictionaryItemService DictionaryItemService { get; }
protected async Task<IEnumerable<NamedEntityTreeItemResponseModel>> MapTreeItemViewModels(IEnumerable<IDictionaryItem> dictionaryItems)
=> await Task.WhenAll(dictionaryItems.Select(CreateEntityTreeItemViewModelAsync));
=> await MapTreeItemViewModelsAsync(dictionaryItems).ToArrayAsync();
protected override async Task<ActionResult<IEnumerable<NamedEntityTreeItemResponseModel>>> GetAncestors(Guid descendantKey, bool includeSelf = true)
{
@@ -54,10 +54,19 @@ public class DictionaryTreeControllerBase : NamedEntityTreeControllerBase<NamedE
}
}
NamedEntityTreeItemResponseModel[] viewModels = await Task.WhenAll(ancestors.Select(CreateEntityTreeItemViewModelAsync));
NamedEntityTreeItemResponseModel[] viewModels = await MapTreeItemViewModelsAsync(ancestors).ToArrayAsync();
return Ok(viewModels.Reverse());
}
private async IAsyncEnumerable<NamedEntityTreeItemResponseModel> MapTreeItemViewModelsAsync(IEnumerable<IDictionaryItem> dictionaryItems)
{
foreach (IDictionaryItem dictionaryItem in dictionaryItems)
{
yield return await CreateEntityTreeItemViewModelAsync(dictionaryItem);
}
}
private async Task<NamedEntityTreeItemResponseModel> CreateEntityTreeItemViewModelAsync(IDictionaryItem dictionaryItem)
{
var hasChildren = await DictionaryItemService.CountChildrenAsync(dictionaryItem.Key) > 0;
@@ -1,12 +1,10 @@
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
using Umbraco.Cms.Api.Management.Factories;
using Umbraco.Cms.Api.Management.ViewModels.Document.Collection;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Security;
@@ -22,20 +20,6 @@ public class ByKeyDocumentCollectionController : DocumentCollectionControllerBas
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
private readonly IDocumentCollectionPresentationFactory _documentCollectionPresentationFactory;
[Obsolete("Please use the constructor taking all parameters.")]
public ByKeyDocumentCollectionController(
IContentListViewService contentListViewService,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
IUmbracoMapper mapper)
: this(
contentListViewService,
backOfficeSecurityAccessor,
mapper,
StaticServiceProvider.Instance.GetRequiredService<IDocumentCollectionPresentationFactory>())
{
}
[ActivatorUtilitiesConstructor]
public ByKeyDocumentCollectionController(
IContentListViewService contentListViewService,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Factories;
@@ -24,13 +24,13 @@ public class ItemDocumentItemController : DocumentItemControllerBase
[HttpGet]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(IEnumerable<DocumentItemResponseModel>), StatusCodes.Status200OK)]
public async Task<IActionResult> Item(
public Task<IActionResult> Item(
CancellationToken cancellationToken,
[FromQuery(Name = "id")] HashSet<Guid> ids)
{
if (ids.Count is 0)
{
return Ok(Enumerable.Empty<DocumentItemResponseModel>());
return Task.FromResult<IActionResult>(Ok(Enumerable.Empty<DocumentItemResponseModel>()));
}
IEnumerable<IDocumentEntitySlim> documents = _entityService
@@ -38,6 +38,6 @@ public class ItemDocumentItemController : DocumentItemControllerBase
.OfType<IDocumentEntitySlim>();
IEnumerable<DocumentItemResponseModel> documentItemResponseModels = documents.Select(_documentPresentationFactory.CreateItemResponseModel);
return await Task.FromResult(Ok(documentItemResponseModels));
return Task.FromResult<IActionResult>(Ok(documentItemResponseModels));
}
}
@@ -1,4 +1,3 @@
using System.Text.Json.Serialization;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
@@ -22,32 +21,10 @@ public class SearchDocumentItemController : DocumentItemControllerBase
_documentPresentationFactory = documentPresentationFactory;
}
[NonAction]
[Obsolete("Scheduled to be removed in v16, use the non obsoleted method instead")]
public async Task<IActionResult> Search(CancellationToken cancellationToken, string query, int skip = 0, int take = 100)
=> await SearchFromParent(cancellationToken, query, skip, take);
[NonAction]
[Obsolete("Scheduled to be removed in v16, use the non obsoleted method instead")]
public async Task<IActionResult> SearchFromParent(CancellationToken cancellationToken, string query, int skip = 0, int take = 100, Guid? parentId = null)
=> await SearchWithTrashed(cancellationToken, query, null, skip, take, parentId);
[NonAction]
[Obsolete("Scheduled to be removed in v16, use the non obsoleted method instead")]
[ProducesResponseType(typeof(PagedModel<DocumentItemResponseModel>), StatusCodes.Status200OK)]
public async Task<IActionResult> SearchFromParentWithAllowedTypes(
CancellationToken cancellationToken,
string query,
int skip = 0,
int take = 100,
Guid? parentId = null,
[FromQuery] IEnumerable<Guid>? allowedDocumentTypes = null) =>
await SearchWithTrashed(cancellationToken, query, null, skip, take, parentId, allowedDocumentTypes);
[HttpGet("search")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PagedModel<DocumentItemResponseModel>), StatusCodes.Status200OK)]
public async Task<IActionResult> SearchWithTrashed(
public Task<IActionResult> SearchWithTrashed(
CancellationToken cancellationToken,
string query,
bool? trashed = null,
@@ -63,6 +40,6 @@ public class SearchDocumentItemController : DocumentItemControllerBase
Total = searchResult.Total,
};
return await Task.FromResult(Ok(result));
return Task.FromResult<IActionResult>(Ok(result));
}
}
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.Document;
@@ -35,6 +35,6 @@ public class UpdateNotificationsController : DocumentControllerBase
}
_notificationService.SetNotifications(_backOfficeSecurityAccessor.BackOfficeSecurity?.CurrentUser, content, updateModel.SubscribedActionIds);
return await Task.FromResult(Ok());
return Ok();
}
}
@@ -14,7 +14,6 @@ using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Api.Management.Controllers.Document;
[ApiVersion("1.0")]
[ApiVersion("1.1")]
public class ValidateUpdateDocumentController : UpdateDocumentControllerBase
{
@@ -48,31 +47,6 @@ public class ValidateUpdateDocumentController : UpdateDocumentControllerBase
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
}
[HttpPut("{id:guid}/validate")]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
[Obsolete("Please use version 1.1 of this API. Will be removed in V16.")]
public async Task<IActionResult> Validate(CancellationToken cancellationToken, Guid id, UpdateDocumentRequestModel requestModel)
=> await HandleRequest(id, requestModel, async () =>
{
var validateUpdateDocumentRequestModel = new ValidateUpdateDocumentRequestModel
{
Values = requestModel.Values,
Variants = requestModel.Variants,
Template = requestModel.Template,
Cultures = null
};
ValidateContentUpdateModel model = _documentEditingPresentationFactory.MapValidateUpdateModel(validateUpdateDocumentRequestModel);
Attempt<ContentValidationResult, ContentEditingOperationStatus> result = await _contentEditingService.ValidateUpdateAsync(id, model);
return result.Success
? Ok()
: DocumentEditingOperationStatusResult(result.Status, requestModel, result.Result);
});
[HttpPut("{id:guid}/validate")]
[MapToApiVersion("1.1")]
[ProducesResponseType(StatusCodes.Status200OK)]
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Factories;
@@ -25,13 +25,13 @@ public class ItemDocumentBlueprintController : DocumentBlueprintItemControllerBa
[HttpGet]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(IEnumerable<DocumentBlueprintItemResponseModel>), StatusCodes.Status200OK)]
public async Task<IActionResult> Item(
public Task<IActionResult> Item(
CancellationToken cancellationToken,
[FromQuery(Name = "id")] HashSet<Guid> ids)
{
if (ids.Count is 0)
{
return Ok(Enumerable.Empty<DocumentBlueprintItemResponseModel>());
return Task.FromResult<IActionResult>(Ok(Enumerable.Empty<DocumentBlueprintItemResponseModel>()));
}
IEnumerable<IDocumentEntitySlim> documents = _entityService
@@ -39,6 +39,6 @@ public class ItemDocumentBlueprintController : DocumentBlueprintItemControllerBa
.Select(x => x as IDocumentEntitySlim)
.WhereNotNull();
IEnumerable<DocumentBlueprintItemResponseModel> responseModels = documents.Select(x => _documentPresentationFactory.CreateBlueprintItemResponseModel(x));
return await Task.FromResult(Ok(responseModels));
return Task.FromResult<IActionResult>(Ok(responseModels));
}
}
@@ -1,37 +0,0 @@
using Asp.Versioning;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.DocumentBlueprint;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Web.Common.Authorization;
namespace Umbraco.Cms.Api.Management.Controllers.DocumentBlueprint;
[ApiVersion("1.0")]
[Authorize(Policy = AuthorizationPolicies.TreeAccessDocuments)]
public class ScaffoldDocumentBlueprintController : DocumentBlueprintControllerBase
{
private readonly IContentBlueprintEditingService _contentBlueprintEditingService;
private readonly IUmbracoMapper _umbracoMapper;
public ScaffoldDocumentBlueprintController(IContentBlueprintEditingService contentBlueprintEditingService, IUmbracoMapper umbracoMapper)
{
_contentBlueprintEditingService = contentBlueprintEditingService;
_umbracoMapper = umbracoMapper;
}
[HttpGet("{id:guid}/scaffold")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(DocumentBlueprintResponseModel), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
public async Task<IActionResult> Scaffold(CancellationToken cancellationToken, Guid id)
{
IContent? blueprint = await _contentBlueprintEditingService.GetScaffoldedAsync(id);
return blueprint is not null
? Ok(_umbracoMapper.Map<DocumentBlueprintResponseModel>(blueprint))
: DocumentBlueprintNotFound();
}
}
@@ -23,15 +23,6 @@ public class AllowedChildrenDocumentTypeController : DocumentTypeControllerBase
_umbracoMapper = umbracoMapper;
}
[NonAction]
[Obsolete("Use the non obsoleted method instead. Scheduled to be removed in v16")]
public async Task<IActionResult> AllowedChildrenByKey(
CancellationToken cancellationToken,
Guid id,
int skip = 0,
int take = 100)
=> await AllowedChildrenByKey(cancellationToken, id, null, skip, take);
[HttpGet("{id:guid}/allowed-children")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PagedViewModel<AllowedDocumentType>), StatusCodes.Status200OK)]
@@ -1,14 +1,9 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Api.Management.Factories;
using Umbraco.Cms.Api.Management.ViewModels.DocumentType;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Features;
using Umbraco.Cms.Web.Common.Authorization;
namespace Umbraco.Cms.Api.Management.Controllers.DocumentType;
@@ -19,30 +14,8 @@ public class ConfigurationDocumentTypeController : DocumentTypeControllerBase
{
private readonly IConfigurationPresentationFactory _configurationPresentationFactory;
[ActivatorUtilitiesConstructor]
public ConfigurationDocumentTypeController(IConfigurationPresentationFactory configurationPresentationFactory)
{
_configurationPresentationFactory = configurationPresentationFactory;
}
[Obsolete("Use the constructor that only accepts IConfigurationPresentationFactory, scheduled for removal in V16")]
public ConfigurationDocumentTypeController(
UmbracoFeatures umbracoFeatures,
IOptionsSnapshot<DataTypesSettings> dataTypesSettings,
IOptionsSnapshot<SegmentSettings> segmentSettings,
IConfigurationPresentationFactory configurationPresentationFactory)
: this(configurationPresentationFactory)
{
}
[Obsolete("Use the constructor that only accepts IConfigurationPresentationFactory, scheduled for removal in V16")]
public ConfigurationDocumentTypeController(
UmbracoFeatures umbracoFeatures,
IOptionsSnapshot<DataTypesSettings> dataTypesSettings,
IOptionsSnapshot<SegmentSettings> segmentSettings)
: this(StaticServiceProvider.Instance.GetRequiredService<IConfigurationPresentationFactory>())
{
}
=> _configurationPresentationFactory = configurationPresentationFactory;
[HttpGet("configuration")]
[MapToApiVersion("1.0")]
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.DocumentType.Item;
@@ -23,17 +23,17 @@ public class ItemDocumentTypeItemController : DocumentTypeItemControllerBase
[HttpGet]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(IEnumerable<DocumentTypeItemResponseModel>), StatusCodes.Status200OK)]
public async Task<IActionResult> Item(
public Task<IActionResult> Item(
CancellationToken cancellationToken,
[FromQuery(Name = "id")] HashSet<Guid> ids)
{
if (ids.Count is 0)
{
return Ok(Enumerable.Empty<DocumentTypeItemResponseModel>());
return Task.FromResult<IActionResult>(Ok(Enumerable.Empty<DocumentTypeItemResponseModel>()));
}
IEnumerable<IContentType> contentTypes = _contentTypeService.GetMany(ids);
List<DocumentTypeItemResponseModel> responseModels = _mapper.MapEnumerable<IContentType, DocumentTypeItemResponseModel>(contentTypes);
return await Task.FromResult(Ok(responseModels));
return Task.FromResult<IActionResult>(Ok(responseModels));
}
}
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
@@ -2,10 +2,8 @@ using Asp.Versioning;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Actions;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Security.Authorization;
@@ -23,7 +21,6 @@ public class RollbackDocumentVersionController : DocumentVersionControllerBase
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
private readonly IAuthorizationService _authorizationService;
[ActivatorUtilitiesConstructor]
public RollbackDocumentVersionController(
IContentVersionService contentVersionService,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
@@ -34,18 +31,6 @@ public class RollbackDocumentVersionController : DocumentVersionControllerBase
_authorizationService = authorizationService;
}
// TODO (V16): Remove this constructor.
[Obsolete("Please use the constructor taking all parameters. This constructor will be removed in V16.")]
public RollbackDocumentVersionController(
IContentVersionService contentVersionService,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
: this(
contentVersionService,
backOfficeSecurityAccessor,
StaticServiceProvider.Instance.GetRequiredService<IAuthorizationService>())
{
}
[MapToApiVersion("1.0")]
[HttpPost("{id:guid}/rollback")]
[ProducesResponseType(StatusCodes.Status200OK)]
@@ -21,10 +21,10 @@ public class GetQueryStepsController : DynamicRootControllerBase
[HttpGet($"steps")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(IEnumerable<string>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetQuerySteps(CancellationToken cancellationToken)
public Task<IActionResult> GetQuerySteps(CancellationToken cancellationToken)
{
IEnumerable<string> querySteps = _dynamicRootQueryStepCollection.Select(x => x.SupportedDirectionAlias);
return await Task.FromResult(Ok(querySteps));
return Task.FromResult<IActionResult>(Ok(querySteps));
}
}
@@ -63,6 +63,6 @@ public class ExecuteActionHealthCheckController : HealthCheckControllerBase
HealthCheckStatus result = await healthCheck.ExecuteActionAsync(_umbracoMapper.Map<HealthCheckAction>(action)!);
return await Task.FromResult(Ok(_umbracoMapper.Map<HealthCheckResultResponseModel>(result)));
return Ok(_umbracoMapper.Map<HealthCheckResultResponseModel>(result));
}
}
@@ -31,7 +31,7 @@ public class AllHealthCheckGroupController : HealthCheckGroupControllerBase
[HttpGet]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PagedViewModel<HealthCheckGroupResponseModel>), StatusCodes.Status200OK)]
public async Task<ActionResult<PagedViewModel<HealthCheckGroupResponseModel>>> All(
public Task<ActionResult<PagedViewModel<HealthCheckGroupResponseModel>>> All(
CancellationToken cancellationToken,
int skip = 0,
int take = 100)
@@ -46,6 +46,6 @@ public class AllHealthCheckGroupController : HealthCheckGroupControllerBase
Items = _umbracoMapper.MapEnumerable<IGrouping<string?, Core.HealthChecks.HealthCheck>, HealthCheckGroupResponseModel>(groups.Skip(skip).Take(take))
};
return await Task.FromResult(Ok(viewModel));
return Task.FromResult<ActionResult<PagedViewModel<HealthCheckGroupResponseModel>>>(Ok(viewModel));
}
}
@@ -31,7 +31,7 @@ public class ByNameHealthCheckGroupController : HealthCheckGroupControllerBase
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
[ProducesResponseType(typeof(HealthCheckGroupPresentationModel), StatusCodes.Status200OK)]
public async Task<IActionResult> ByName(
public Task<IActionResult> ByName(
CancellationToken cancellationToken,
string name)
{
@@ -42,9 +42,9 @@ public class ByNameHealthCheckGroupController : HealthCheckGroupControllerBase
if (group is null)
{
return HealthCheckGroupNotFound();
return Task.FromResult(HealthCheckGroupNotFound());
}
return await Task.FromResult(Ok(_umbracoMapper.Map<HealthCheckGroupPresentationModel>(group)));
return Task.FromResult<IActionResult>(Ok(_umbracoMapper.Map<HealthCheckGroupPresentationModel>(group)));
}
}
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
@@ -82,6 +82,5 @@ public class GetHelpController : HelpControllerBase
return Ok(PagedViewModel<HelpPageResponseModel>.Empty());
}
private bool IsAllowedUrl(string? url) =>
_helpPageSettings.HelpPageUrlAllowList is null || _helpPageSettings.HelpPageUrlAllowList.Contains(url);
private bool IsAllowedUrl(string? url) => url is null || _helpPageSettings.HelpPageUrlAllowList.Contains(url);
}
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Examine;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
@@ -34,11 +34,11 @@ public class DetailsIndexerController : IndexerControllerBase
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(IndexResponseModel), StatusCodes.Status200OK)]
public async Task<ActionResult<IndexResponseModel?>> Details(CancellationToken cancellationToken, string indexName)
public Task<ActionResult<IndexResponseModel?>> Details(CancellationToken cancellationToken, string indexName)
{
if (_examineManager.TryGetIndex(indexName, out IIndex? index))
{
return await Task.FromResult(_indexPresentationFactory.Create(index!));
return Task.FromResult<ActionResult<IndexResponseModel?>>(_indexPresentationFactory.Create(index));
}
var invalidModelProblem = new ProblemDetails
@@ -49,7 +49,6 @@ public class DetailsIndexerController : IndexerControllerBase
Type = "Error",
};
return await Task.FromResult(NotFound(invalidModelProblem));
return Task.FromResult<ActionResult<IndexResponseModel?>>(NotFound(invalidModelProblem));
}
}
@@ -36,7 +36,7 @@ public class RebuildIndexerController : IndexerControllerBase
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status409Conflict)]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<IActionResult> Rebuild(CancellationToken cancellationToken, string indexName)
public Task<IActionResult> Rebuild(CancellationToken cancellationToken, string indexName)
{
if (!_examineManager.TryGetIndex(indexName, out IIndex? index))
{
@@ -48,7 +48,7 @@ public class RebuildIndexerController : IndexerControllerBase
Type = "Error",
};
return await Task.FromResult(NotFound(invalidModelProblem));
return Task.FromResult<IActionResult>(NotFound(invalidModelProblem));
}
if (!_indexingRebuilderService.CanRebuild(index.Name))
@@ -62,14 +62,14 @@ public class RebuildIndexerController : IndexerControllerBase
Type = "Error",
};
return await Task.FromResult(BadRequest(invalidModelProblem));
return Task.FromResult<IActionResult>(BadRequest(invalidModelProblem));
}
_logger.LogInformation("Rebuilding index '{IndexName}'", indexName);
if (_indexingRebuilderService.TryRebuild(index, indexName))
{
return await Task.FromResult(Ok());
return Task.FromResult<IActionResult>(Ok());
}
var problemDetails = new ProblemDetails
@@ -80,6 +80,6 @@ public class RebuildIndexerController : IndexerControllerBase
Type = "Error",
};
return await Task.FromResult(Conflict(problemDetails));
return Task.FromResult<IActionResult>(Conflict(problemDetails));
}
}
@@ -30,7 +30,7 @@ public class AllSinkLevelLogViewerController : LogViewerControllerBase
[HttpGet("level")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PagedViewModel<LoggerResponseModel>), StatusCodes.Status200OK)]
public async Task<ActionResult<PagedViewModel<LoggerResponseModel>>> AllLogLevels(
public Task<ActionResult<PagedViewModel<LoggerResponseModel>>> AllLogLevels(
CancellationToken cancellationToken,
int skip = 0,
int take = 100)
@@ -45,6 +45,6 @@ public class AllSinkLevelLogViewerController : LogViewerControllerBase
Items = _umbracoMapper.MapEnumerable<KeyValuePair<string, LogLevel>, LoggerResponseModel>(logLevels.Skip(skip).Take(take))
};
return await Task.FromResult(Ok(viewModel));
return Task.FromResult<ActionResult<PagedViewModel<LoggerResponseModel>>>(Ok(viewModel));
}
}
@@ -1,12 +1,10 @@
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
using Umbraco.Cms.Api.Management.Factories;
using Umbraco.Cms.Api.Management.ViewModels.Media.Collection;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Security;
@@ -22,20 +20,6 @@ public class ByKeyMediaCollectionController : MediaCollectionControllerBase
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
private readonly IMediaCollectionPresentationFactory _mediaCollectionPresentationFactory;
[Obsolete("Please use the constructor taking all parameters.")]
public ByKeyMediaCollectionController(
IMediaListViewService mediaListViewService,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
IUmbracoMapper mapper)
: this(
mediaListViewService,
backOfficeSecurityAccessor,
mapper,
StaticServiceProvider.Instance.GetRequiredService<IMediaCollectionPresentationFactory>())
{
}
[ActivatorUtilitiesConstructor]
public ByKeyMediaCollectionController(
IMediaListViewService mediaListViewService,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Factories;
@@ -7,6 +7,7 @@ using Umbraco.Cms.Api.Management.ViewModels.Media;
namespace Umbraco.Cms.Api.Management.Controllers.Media;
[ApiVersion("1.0")]
[Obsolete("No longer used. Scheduled for removal in Umbraco 18.")]
public class ConfigurationMediaController : MediaControllerBase
{
private readonly IConfigurationPresentationFactory _configurationPresentationFactory;
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Factories;
@@ -25,13 +25,13 @@ public class ItemMediaItemController : MediaItemControllerBase
[HttpGet]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(IEnumerable<MediaItemResponseModel>), StatusCodes.Status200OK)]
public async Task<IActionResult> Item(
public Task<IActionResult> Item(
CancellationToken cancellationToken,
[FromQuery(Name = "id")] HashSet<Guid> ids)
{
if (ids.Count is 0)
{
return Ok(Enumerable.Empty<MediaItemResponseModel>());
return Task.FromResult<IActionResult>(Ok(Enumerable.Empty<MediaItemResponseModel>()));
}
IEnumerable<IMediaEntitySlim> media = _entityService
@@ -39,6 +39,6 @@ public class ItemMediaItemController : MediaItemControllerBase
.OfType<IMediaEntitySlim>();
IEnumerable<MediaItemResponseModel> responseModels = media.Select(_mediaPresentationFactory.CreateItemResponseModel);
return await Task.FromResult(Ok(responseModels));
return Task.FromResult<IActionResult>(Ok(responseModels));
}
}
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Factories;
@@ -23,24 +23,13 @@ public class SearchMediaItemController : MediaItemControllerBase
[NonAction]
[Obsolete("Scheduled to be removed in v16, use the non obsoleted method instead")]
public async Task<IActionResult> Search(CancellationToken cancellationToken, string query, int skip = 0, int take = 100)
=> await SearchFromParent(cancellationToken, query, skip, take, null);
[NonAction]
[Obsolete("Scheduled to be removed in v16, use the non obsoleted method instead")]
[ProducesResponseType(typeof(PagedModel<MediaItemResponseModel>), StatusCodes.Status200OK)]
public async Task<IActionResult> SearchFromParent(CancellationToken cancellationToken, string query, int skip = 0, int take = 100, Guid? parentId = null)
=> await SearchFromParentWithAllowedTypes(cancellationToken, query, skip, take, parentId);
[NonAction]
[Obsolete("Scheduled to be removed in v16, use the non obsoleted method instead")]
public async Task<IActionResult> SearchFromParentWithAllowedTypes(CancellationToken cancellationToken, string query, int skip = 0, int take = 100, Guid? parentId = null, [FromQuery]IEnumerable<Guid>? allowedMediaTypes = null)
=> await SearchFromParentWithAllowedTypes(cancellationToken, query, null, skip, take, parentId);
public Task<IActionResult> SearchFromParentWithAllowedTypes(CancellationToken cancellationToken, string query, int skip = 0, int take = 100, Guid? parentId = null, [FromQuery]IEnumerable<Guid>? allowedMediaTypes = null)
=> SearchFromParentWithAllowedTypes(cancellationToken, query, null, skip, take, parentId);
[HttpGet("search")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PagedModel<MediaItemResponseModel>), StatusCodes.Status200OK)]
public async Task<IActionResult> SearchFromParentWithAllowedTypes(CancellationToken cancellationToken, string query, bool? trashed = null, int skip = 0, int take = 100, Guid? parentId = null, [FromQuery]IEnumerable<Guid>? allowedMediaTypes = null)
public Task<IActionResult> SearchFromParentWithAllowedTypes(CancellationToken cancellationToken, string query, bool? trashed = null, int skip = 0, int take = 100, Guid? parentId = null, [FromQuery]IEnumerable<Guid>? allowedMediaTypes = null)
{
PagedModel<IEntitySlim> searchResult = _indexedEntitySearchService.Search(UmbracoObjectTypes.Media, query, parentId, allowedMediaTypes, trashed, skip, take);
var result = new PagedModel<MediaItemResponseModel>
@@ -49,6 +38,6 @@ public class SearchMediaItemController : MediaItemControllerBase
Total = searchResult.Total,
};
return await Task.FromResult(Ok(result));
return Task.FromResult<IActionResult>(Ok(result));
}
}
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Factories;
@@ -25,10 +25,10 @@ public class MediaUrlController : MediaControllerBase
[MapToApiVersion("1.0")]
[HttpGet("urls")]
[ProducesResponseType(typeof(IEnumerable<MediaUrlInfoResponseModel>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetUrls([FromQuery(Name = "id")] HashSet<Guid> ids)
public Task<IActionResult> GetUrls([FromQuery(Name = "id")] HashSet<Guid> ids)
{
IEnumerable<IMedia> items = _mediaService.GetByIds(ids);
return await Task.FromResult(Ok(_mediaUrlFactory.CreateUrlSets(items)));
return Task.FromResult<IActionResult>(Ok(_mediaUrlFactory.CreateUrlSets(items)));
}
}
@@ -23,15 +23,6 @@ public class AllowedChildrenMediaTypeController : MediaTypeControllerBase
_umbracoMapper = umbracoMapper;
}
[NonAction]
[Obsolete("Use the non obsoleted method instead. Scheduled for removal in Umbraco 16.")]
public async Task<IActionResult> AllowedChildrenByKey(
CancellationToken cancellationToken,
Guid id,
int skip = 0,
int take = 100)
=> await AllowedChildrenByKey(cancellationToken, id, null, skip, take);
[HttpGet("{id:guid}/allowed-children")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PagedViewModel<AllowedMediaType>), StatusCodes.Status200OK)]
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.MediaType;
@@ -34,6 +34,6 @@ public class ByKeyMediaTypeController : MediaTypeControllerBase
}
MediaTypeResponseModel model = _umbracoMapper.Map<MediaTypeResponseModel>(mediaType)!;
return await Task.FromResult(Ok(model));
return Ok(model);
}
}
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.MediaType.Item;
@@ -23,17 +23,17 @@ public class ItemMediaTypeItemController : MediaTypeItemControllerBase
[HttpGet]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(IEnumerable<MediaTypeItemResponseModel>), StatusCodes.Status200OK)]
public async Task<IActionResult> Item(
public Task<IActionResult> Item(
CancellationToken cancellationToken,
[FromQuery(Name = "id")] HashSet<Guid> ids)
{
if (ids.Count is 0)
{
return Ok(Enumerable.Empty<MediaTypeItemResponseModel>());
return Task.FromResult<IActionResult>(Ok(Enumerable.Empty<MediaTypeItemResponseModel>()));
}
IEnumerable<IMediaType> mediaTypes = _mediaTypeService.GetMany(ids);
List<MediaTypeItemResponseModel> responseModels = _mapper.MapEnumerable<IMediaType, MediaTypeItemResponseModel>(mediaTypes);
return await Task.FromResult(Ok(responseModels));
return Task.FromResult<IActionResult>(Ok(responseModels));
}
}
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.MediaType.Item;
@@ -27,12 +27,12 @@ public class SearchMediaTypeItemController : MediaTypeItemControllerBase
[HttpGet("search")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PagedModel<MediaTypeItemResponseModel>), StatusCodes.Status200OK)]
public async Task<IActionResult> Search(CancellationToken cancellationToken, string query, int skip = 0, int take = 100)
public Task<IActionResult> Search(CancellationToken cancellationToken, string query, int skip = 0, int take = 100)
{
PagedModel<IEntitySlim> searchResult = _entitySearchService.Search(UmbracoObjectTypes.MediaType, query, skip, take);
if (searchResult.Items.Any() is false)
{
return await Task.FromResult(Ok(new PagedModel<MediaTypeItemResponseModel> { Total = searchResult.Total }));
return Task.FromResult<IActionResult>(Ok(new PagedModel<MediaTypeItemResponseModel> { Total = searchResult.Total }));
}
IEnumerable<IMediaType> mediaTypes = _mediaTypeService.GetMany(searchResult.Items.Select(item => item.Key).ToArray().EmptyNull());
@@ -42,6 +42,6 @@ public class SearchMediaTypeItemController : MediaTypeItemControllerBase
Total = searchResult.Total
};
return Ok(result);
return Task.FromResult<IActionResult>(Ok(result));
}
}
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Factories;
@@ -25,13 +25,13 @@ public class ItemMemberItemController : MemberItemControllerBase
[HttpGet]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(IEnumerable<MemberItemResponseModel>), StatusCodes.Status200OK)]
public async Task<IActionResult> Item(
public Task<IActionResult> Item(
CancellationToken cancellationToken,
[FromQuery(Name = "id")] HashSet<Guid> ids)
{
if (ids.Count is 0)
{
return Ok(Enumerable.Empty<MemberItemResponseModel>());
return Task.FromResult<IActionResult>(Ok(Enumerable.Empty<MemberItemResponseModel>()));
}
IEnumerable<IMemberEntitySlim> members = _entityService
@@ -39,6 +39,6 @@ public class ItemMemberItemController : MemberItemControllerBase
.OfType<IMemberEntitySlim>();
IEnumerable<MemberItemResponseModel> responseModels = members.Select(_memberPresentationFactory.CreateItemResponseModel);
return await Task.FromResult(Ok(responseModels));
return Task.FromResult<IActionResult>(Ok(responseModels));
}
}
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Factories;
@@ -21,15 +21,10 @@ public class SearchMemberItemController : MemberItemControllerBase
_memberPresentationFactory = memberPresentationFactory;
}
[NonAction]
[Obsolete("Scheduled to be removed in v16, use the non obsoleted method instead")]
public async Task<IActionResult> Search(CancellationToken cancellationToken, string query, int skip = 0, int take = 100)
=> await SearchWithAllowedTypes(cancellationToken, query, skip, take);
[HttpGet("search")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PagedModel<MemberItemResponseModel>), StatusCodes.Status200OK)]
public async Task<IActionResult> SearchWithAllowedTypes(CancellationToken cancellationToken, string query, int skip = 0, int take = 100, [FromQuery]IEnumerable<Guid>? allowedMemberTypes = null)
public Task<IActionResult> SearchWithAllowedTypes(CancellationToken cancellationToken, string query, int skip = 0, int take = 100, [FromQuery]IEnumerable<Guid>? allowedMemberTypes = null)
{
PagedModel<IEntitySlim> searchResult = _indexedEntitySearchService.Search(UmbracoObjectTypes.Member, query, null, allowedMemberTypes, skip, take);
var result = new PagedModel<MemberItemResponseModel>
@@ -38,6 +33,6 @@ public class SearchMemberItemController : MemberItemControllerBase
Total = searchResult.Total
};
return await Task.FromResult(Ok(result));
return Task.FromResult<IActionResult>(Ok(result));
}
}
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
@@ -36,6 +36,6 @@ public class AllMemberGroupController : MemberGroupControllerBase
Items = _mapper.MapEnumerable<IMemberGroup, MemberGroupResponseModel>(memberGroups.Skip(skip).Take(take)),
};
return await Task.FromResult(Ok(viewModel));
return Ok(viewModel);
}
}
@@ -25,17 +25,17 @@ public class ItemMemberGroupItemController : MemberGroupItemControllerBase
[HttpGet]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(IEnumerable<MemberGroupItemResponseModel>), StatusCodes.Status200OK)]
public async Task<IActionResult> Item(
public Task<IActionResult> Item(
CancellationToken cancellationToken,
[FromQuery(Name = "id")] HashSet<Guid> ids)
{
if (ids.Count is 0)
{
return Ok(Enumerable.Empty<MemberGroupItemResponseModel>());
return Task.FromResult<IActionResult>(Ok(Enumerable.Empty<MemberGroupItemResponseModel>()));
}
IEnumerable<IEntitySlim> memberGroups = _entityService.GetAll(UmbracoObjectTypes.MemberGroup, ids.ToArray());
List<MemberGroupItemResponseModel> responseModel = _mapper.MapEnumerable<IEntitySlim, MemberGroupItemResponseModel>(memberGroups);
return Ok(responseModel);
return Task.FromResult<IActionResult>(Ok(responseModel));
}
}
@@ -23,17 +23,17 @@ public class ItemMemberTypeItemController : MemberTypeItemControllerBase
[HttpGet]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(IEnumerable<MemberTypeItemResponseModel>), StatusCodes.Status200OK)]
public async Task<IActionResult> Item(
public Task<IActionResult> Item(
CancellationToken cancellationToken,
[FromQuery(Name = "id")] HashSet<Guid> ids)
{
if (ids.Count is 0)
{
return Ok(Enumerable.Empty<MemberTypeItemResponseModel>());
return Task.FromResult<IActionResult>(Ok(Enumerable.Empty<MemberTypeItemResponseModel>()));
}
IEnumerable<IMemberType> memberTypes = _memberTypeService.GetMany(ids);
List<MemberTypeItemResponseModel> responseModels = _mapper.MapEnumerable<IMemberType, MemberTypeItemResponseModel>(memberTypes);
return Ok(responseModels);
return Task.FromResult<IActionResult>(Ok(responseModels));
}
}
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.MemberType.Item;
@@ -26,12 +26,12 @@ public class SearchMemberTypeItemController : MemberTypeItemControllerBase
[HttpGet("search")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PagedModel<MemberTypeItemResponseModel>), StatusCodes.Status200OK)]
public async Task<IActionResult> Search(CancellationToken cancellationToken, string query, int skip = 0, int take = 100)
public Task<IActionResult> Search(CancellationToken cancellationToken, string query, int skip = 0, int take = 100)
{
PagedModel<IEntitySlim> searchResult = _entitySearchService.Search(UmbracoObjectTypes.MemberType, query, skip, take);
if (searchResult.Items.Any() is false)
{
return await Task.FromResult(Ok(new PagedModel<MemberTypeItemResponseModel> { Total = searchResult.Total }));
return Task.FromResult<IActionResult>(Ok(new PagedModel<MemberTypeItemResponseModel> { Total = searchResult.Total }));
}
IEnumerable<IMemberType> memberTypes = _memberTypeService.GetMany(searchResult.Items.Select(item => item.Key).ToArray());
@@ -41,6 +41,6 @@ public class SearchMemberTypeItemController : MemberTypeItemControllerBase
Total = searchResult.Total
};
return Ok(result);
return Task.FromResult<IActionResult>(Ok(result));
}
}
@@ -19,7 +19,6 @@ public class BuildModelsBuilderController : ModelsBuilderControllerBase
private readonly ModelsGenerationError _mbErrors;
private readonly IModelsGenerator _modelGenerator;
[ActivatorUtilitiesConstructor]
public BuildModelsBuilderController(
IOptionsMonitor<ModelsBuilderSettings> modelsBuilderSettings,
ModelsGenerationError mbErrors,
@@ -32,31 +31,11 @@ public class BuildModelsBuilderController : ModelsBuilderControllerBase
modelsBuilderSettings.OnChange(x => _modelsBuilderSettings = x);
}
[Obsolete("Please use the constructor that accepts IModelsGenerator only. Will be removed in V16.")]
public BuildModelsBuilderController(
IOptionsMonitor<ModelsBuilderSettings> modelsBuilderSettings,
ModelsGenerationError mbErrors,
ModelsGenerator modelGenerator)
: this(modelsBuilderSettings, mbErrors, (IModelsGenerator)modelGenerator)
{
}
// this constructor is required for the DI, otherwise it'll throw an "Ambiguous Constructor" errors at boot time.
[Obsolete("Please use the constructor that accepts IModelsGenerator only. Will be removed in V16.")]
public BuildModelsBuilderController(
IOptionsMonitor<ModelsBuilderSettings> modelsBuilderSettings,
ModelsGenerationError mbErrors,
IModelsGenerator modelGenerator,
ModelsGenerator notUsed)
: this(modelsBuilderSettings, mbErrors, modelGenerator)
{
}
[HttpPost("build")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status428PreconditionRequired)]
[MapToApiVersion("1.0")]
public async Task<IActionResult> BuildModels(CancellationToken cancellationToken)
public Task<IActionResult> BuildModels(CancellationToken cancellationToken)
{
try
{
@@ -70,7 +49,7 @@ public class BuildModelsBuilderController : ModelsBuilderControllerBase
Type = "Error",
};
return new ObjectResult(problemDetailsModel) { StatusCode = StatusCodes.Status428PreconditionRequired };
return Task.FromResult<IActionResult>(new ObjectResult(problemDetailsModel) { StatusCode = StatusCodes.Status428PreconditionRequired });
}
_modelGenerator.GenerateModels();
@@ -81,6 +60,6 @@ public class BuildModelsBuilderController : ModelsBuilderControllerBase
_mbErrors.Report("Failed to build models.", e);
}
return Ok();
return Task.FromResult<IActionResult>(Ok());
}
}
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Factories;
@@ -16,6 +16,6 @@ public class GetModelsBuilderController : ModelsBuilderControllerBase
[HttpGet("dashboard")]
[ProducesResponseType(typeof(ModelsBuilderResponseModel), StatusCodes.Status200OK)]
[MapToApiVersion("1.0")]
public async Task<ActionResult<ModelsBuilderResponseModel>> GetDashboard(CancellationToken cancellationToken)
=> await Task.FromResult(Ok(_modelsBuilderPresentationFactory.Create()));
public Task<ActionResult<ModelsBuilderResponseModel>> GetDashboard(CancellationToken cancellationToken)
=> Task.FromResult<ActionResult<ModelsBuilderResponseModel>>(Ok(_modelsBuilderPresentationFactory.Create()));
}
@@ -1,4 +1,4 @@
using System.Threading.Tasks;
using System.Threading.Tasks;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
@@ -18,7 +18,7 @@ public class StatusModelsBuilderController : ModelsBuilderControllerBase
[HttpGet("status")]
[ProducesResponseType(typeof(OutOfDateStatusResponseModel), StatusCodes.Status200OK)]
[MapToApiVersion("1.0")]
public async Task<ActionResult<OutOfDateStatusResponseModel>> GetModelsOutOfDateStatus(CancellationToken cancellationToken)
public Task<ActionResult<OutOfDateStatusResponseModel>> GetModelsOutOfDateStatus(CancellationToken cancellationToken)
{
OutOfDateStatusResponseModel status = _outOfDateModelsStatus.IsEnabled
? _outOfDateModelsStatus.IsOutOfDate
@@ -26,6 +26,6 @@ public class StatusModelsBuilderController : ModelsBuilderControllerBase
: new OutOfDateStatusResponseModel { Status = OutOfDateType.Current }
: new OutOfDateStatusResponseModel { Status = OutOfDateType.Unknown };
return await Task.FromResult(Ok(status));
return Task.FromResult<ActionResult<OutOfDateStatusResponseModel>>(Ok(status));
}
}
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
@@ -17,11 +17,11 @@ public class AllowedObjectTypesController : ObjectTypesControllerBase
[HttpGet]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PagedViewModel<ObjectTypeResponseModel>), StatusCodes.Status200OK)]
public async Task<IActionResult> Allowed(CancellationToken cancellationToken, int skip = 0, int take = 100)
public Task<IActionResult> Allowed(CancellationToken cancellationToken, int skip = 0, int take = 100)
{
ObjectTypeResponseModel[] objectTypes = _objectTypePresentationFactory.Create().ToArray();
return await Task.FromResult(Ok(new PagedViewModel<ObjectTypeResponseModel>
return Task.FromResult<IActionResult>(Ok(new PagedViewModel<ObjectTypeResponseModel>
{
Total = objectTypes.Length,
Items = objectTypes.Skip(skip).Take(take),
@@ -44,6 +44,6 @@ public class AllCreatedPackageController : CreatedPackageControllerBase
Items = _umbracoMapper.MapEnumerable<PackageDefinition, PackageDefinitionResponseModel>(createdPackages.Items)
};
return await Task.FromResult(Ok(viewModel));
return Ok(viewModel);
}
}
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Extensions;
@@ -18,17 +18,17 @@ public class ItemPartialViewItemController : PartialViewItemControllerBase
[HttpGet]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(IEnumerable<PartialViewItemResponseModel>), StatusCodes.Status200OK)]
public async Task<IActionResult> Item(
public Task<IActionResult> Item(
CancellationToken cancellationToken,
[FromQuery(Name = "path")] HashSet<string> paths)
{
if (paths.Count is 0)
{
return Ok(Enumerable.Empty<PartialViewItemResponseModel>());
return Task.FromResult<IActionResult>(Ok(Enumerable.Empty<PartialViewItemResponseModel>()));
}
paths = paths.Select(path => path.VirtualPathToSystemPath()).ToHashSet();
IEnumerable<PartialViewItemResponseModel> responseModels = _fileItemPresentationFactory.CreatePartialViewItemResponseModels(paths);
return await Task.FromResult(Ok(responseModels));
return Task.FromResult<IActionResult>(Ok(responseModels));
}
}
@@ -1,18 +0,0 @@
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Umbraco.Cms.Api.Management.Controllers.PublishedCache;
[Obsolete("This controller no longer serves a purpose")]
[ApiVersion("1.0")]
public class CollectPublishedCacheController : PublishedCacheControllerBase
{
[HttpPost("collect")]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status501NotImplemented)]
public async Task<IActionResult> Collect(CancellationToken cancellationToken)
{
return StatusCode(StatusCodes.Status501NotImplemented);
}
}
@@ -22,7 +22,7 @@ public class RebuildPublishedCacheController : PublishedCacheControllerBase
var problemDetails = new ProblemDetails
{
Title = "Database cache cannot be rebuilt",
Detail = $"The database cache is in the process of rebuilding.",
Detail = "The database cache is in the process of rebuilding.",
Status = StatusCodes.Status400BadRequest,
Type = "Error",
};
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Core.Cache;
@@ -16,10 +16,9 @@ public class ReloadPublishedCacheController : PublishedCacheControllerBase
[HttpPost("reload")]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<IActionResult> Reload(CancellationToken cancellationToken)
public Task<IActionResult> Reload(CancellationToken cancellationToken)
{
_distributedCache.RefreshAllPublishedSnapshot();
return await Task.FromResult(Ok());
return Task.FromResult<IActionResult>(Ok());
}
}
@@ -1,18 +0,0 @@
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Umbraco.Cms.Api.Management.Controllers.PublishedCache;
[ApiVersion("1.0")]
[Obsolete("This no longer relevant since snapshots are no longer used")]
public class StatusPublishedCacheController : PublishedCacheControllerBase
{
[HttpGet("status")]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status501NotImplemented)]
public async Task<ActionResult<string>> Status(CancellationToken cancellationToken)
{
return StatusCode(StatusCodes.Status501NotImplemented);
}
}
@@ -23,17 +23,18 @@ public abstract class RecycleBinControllerBase<TItem> : ContentControllerBase
protected abstract Guid RecycleBinRootKey { get; }
protected async Task<ActionResult<PagedViewModel<TItem>>> GetRoot(int skip, int take)
protected Task<ActionResult<PagedViewModel<TItem>>> GetRoot(int skip, int take)
{
IEntitySlim[] rootEntities = GetPagedRootEntities(skip, take, out var totalItems);
TItem[] treeItemViewModels = MapRecycleBinViewModels(null, rootEntities);
PagedViewModel<TItem> result = PagedViewModel(treeItemViewModels, totalItems);
return await Task.FromResult(Ok(result));
return Task.FromResult<ActionResult<PagedViewModel<TItem>>>(Ok(result));
}
protected async Task<ActionResult<PagedViewModel<TItem>>> GetChildren(Guid parentKey, int skip, int take)
protected Task<ActionResult<PagedViewModel<TItem>>> GetChildren(Guid parentKey, int skip, int take)
{
IEntitySlim[] children = GetPagedChildEntities(parentKey, skip, take, out var totalItems);
@@ -41,7 +42,7 @@ public abstract class RecycleBinControllerBase<TItem> : ContentControllerBase
PagedViewModel<TItem> result = PagedViewModel(treeItemViewModels, totalItems);
return await Task.FromResult(Ok(result));
return Task.FromResult<ActionResult<PagedViewModel<TItem>>>(Ok(result));
}
protected virtual TItem MapRecycleBinViewModel(Guid? parentKey, IEntitySlim entity)
@@ -18,9 +18,9 @@ public class DeleteByKeyRedirectUrlManagementController : RedirectUrlManagementC
[MapToApiVersion("1.0")]
[HttpDelete("{id:guid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<IActionResult> DeleteByKey(CancellationToken cancellationToken, Guid id)
public Task<IActionResult> DeleteByKey(CancellationToken cancellationToken, Guid id)
{
_redirectUrlService.Delete(id);
return Ok();
return Task.FromResult<IActionResult>(Ok());
}
}
@@ -27,7 +27,7 @@ public class GetAllRedirectUrlManagementController : RedirectUrlManagementContro
[HttpGet]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(PagedViewModel<RedirectUrlResponseModel>), StatusCodes.Status200OK)]
public async Task<ActionResult<PagedViewModel<RedirectUrlResponseModel>>> GetAll(
public Task<ActionResult<PagedViewModel<RedirectUrlResponseModel>>> GetAll(
CancellationToken cancellationToken,
string? filter,
int skip = 0,
@@ -39,6 +39,6 @@ public class GetAllRedirectUrlManagementController : RedirectUrlManagementContro
: _redirectUrlService.SearchRedirectUrls(filter, skip, take, out total);
IEnumerable<RedirectUrlResponseModel> redirectViewModels = _redirectUrlPresentationFactory.CreateMany(redirects);
return new PagedViewModel<RedirectUrlResponseModel> { Items = redirectViewModels, Total = total };
return Task.FromResult<ActionResult<PagedViewModel<RedirectUrlResponseModel>>>(new PagedViewModel<RedirectUrlResponseModel> { Items = redirectViewModels, Total = total });
}
}
@@ -43,16 +43,15 @@ public class ByRelationTypeKeyRelationController : RelationControllerBase
if (relationsAttempt.Success is false)
{
return await Task.FromResult(RelationOperationStatusResult(relationsAttempt.Status));
return RelationOperationStatusResult(relationsAttempt.Status);
}
IEnumerable<RelationResponseModel> mappedRelations = relationsAttempt.Result.Items.Select(_relationPresentationFactory.Create);
return await Task.FromResult(Ok(new PagedViewModel<RelationResponseModel>
return Ok(new PagedViewModel<RelationResponseModel>
{
Total = relationsAttempt.Result.Total,
Items = mappedRelations,
}));
});
}
}
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.RelationType;
@@ -24,16 +24,16 @@ public class ByKeyRelationTypeController : RelationTypeControllerBase
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(RelationTypeResponseModel), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
public async Task<IActionResult> ByKey(CancellationToken cancellationToken, Guid id)
public Task<IActionResult> ByKey(CancellationToken cancellationToken, Guid id)
{
IRelationType? relationType = _relationService.GetRelationTypeById(id);
if (relationType is null)
{
return RelationTypeNotFound();
return Task.FromResult(RelationTypeNotFound());
}
RelationTypeResponseModel mappedRelationType = _mapper.Map<RelationTypeResponseModel>(relationType)!;
return await Task.FromResult(Ok(mappedRelationType));
return Task.FromResult<IActionResult>(Ok(mappedRelationType));
}
}
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.RelationType.Item;
@@ -23,13 +23,13 @@ public class ItemRelationTypeItemController : RelationTypeItemControllerBase
[HttpGet]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(IEnumerable<RelationTypeItemResponseModel>), StatusCodes.Status200OK)]
public async Task<IActionResult> Item(
public Task<IActionResult> Item(
CancellationToken cancellationToken,
[FromQuery(Name = "id")] HashSet<Guid> ids)
{
if (ids.Count is 0)
{
return Ok(Enumerable.Empty<RelationTypeItemResponseModel>());
return Task.FromResult<IActionResult>(Ok(Enumerable.Empty<RelationTypeItemResponseModel>()));
}
// relation service does not allow fetching a collection of relation types by their ids; instead it relies
@@ -40,6 +40,6 @@ public class ItemRelationTypeItemController : RelationTypeItemControllerBase
List<RelationTypeItemResponseModel> responseModels = _mapper.MapEnumerable<IRelationType, RelationTypeItemResponseModel>(relationTypes);
return await Task.FromResult(Ok(responseModels));
return Task.FromResult<IActionResult>(Ok(responseModels));
}
}
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Extensions;
@@ -18,17 +18,17 @@ public class ItemScriptItemController : ScriptItemControllerBase
[HttpGet]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(IEnumerable<ScriptItemResponseModel>), StatusCodes.Status200OK)]
public async Task<IActionResult> Item(
public Task<IActionResult> Item(
CancellationToken cancellationToken,
[FromQuery(Name = "path")] HashSet<string> paths)
{
if (paths.Count is 0)
{
return Ok(Enumerable.Empty<ScriptItemResponseModel>());
return Task.FromResult<IActionResult>(Ok(Enumerable.Empty<ScriptItemResponseModel>()));
}
paths = paths.Select(path => path.VirtualPathToSystemPath()).ToHashSet();
IEnumerable<ScriptItemResponseModel> responseModels = _fileItemPresentationFactory.CreateScriptItemResponseModels(paths);
return await Task.FromResult(Ok(responseModels));
return Task.FromResult<IActionResult>(Ok(responseModels));
}
}
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Examine;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
@@ -22,7 +22,7 @@ public class AllSearcherController : SearcherControllerBase
[HttpGet]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PagedViewModel<SearcherResponse>), StatusCodes.Status200OK)]
public async Task<ActionResult<PagedViewModel<SearcherResponse>>> All(
public Task<ActionResult<PagedViewModel<SearcherResponse>>> All(
CancellationToken cancellationToken,
int skip = 0,
int take = 100)
@@ -37,6 +37,6 @@ public class AllSearcherController : SearcherControllerBase
Total = searchers.Count,
};
return await Task.FromResult(Ok(viewModel));
return Task.FromResult<ActionResult<PagedViewModel<SearcherResponse>>>(Ok(viewModel));
}
}
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Examine;
using Examine.Lucene.Search;
using Examine.Search;
@@ -23,7 +23,7 @@ public class QuerySearcherController : SearcherControllerBase
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PagedViewModel<SearchResultResponseModel>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
public async Task<ActionResult<PagedViewModel<SearchResultResponseModel>>> Query(
public Task<ActionResult<PagedViewModel<SearchResultResponseModel>>> Query(
CancellationToken cancellationToken,
string searcherName,
string? term,
@@ -34,7 +34,7 @@ public class QuerySearcherController : SearcherControllerBase
if (term.IsNullOrWhiteSpace())
{
return new PagedViewModel<SearchResultResponseModel>();
return Task.FromResult<ActionResult<PagedViewModel<SearchResultResponseModel>>>(new PagedViewModel<SearchResultResponseModel>());
}
if (!_examineManagerService.TryFindSearcher(searcherName, out ISearcher searcher))
@@ -47,7 +47,7 @@ public class QuerySearcherController : SearcherControllerBase
Type = "Error",
};
return NotFound(invalidModelProblem);
return Task.FromResult<ActionResult<PagedViewModel<SearchResultResponseModel>>>(NotFound(invalidModelProblem));
}
ISearchResults results;
@@ -71,10 +71,10 @@ public class QuerySearcherController : SearcherControllerBase
Type = "Error",
};
return BadRequest(invalidModelProblem);
return Task.FromResult<ActionResult<PagedViewModel<SearchResultResponseModel>>>(BadRequest(invalidModelProblem));
}
return await Task.FromResult(new PagedViewModel<SearchResultResponseModel>
return Task.FromResult<ActionResult<PagedViewModel<SearchResultResponseModel>>>(new PagedViewModel<SearchResultResponseModel>
{
Total = results.TotalItemCount,
Items = results.Select(x => new SearchResultResponseModel
@@ -492,7 +492,7 @@ public class BackOfficeController : SecurityControllerBase
return new ChallengeResult(provider, properties);
}
private async Task<IActionResult> SignInBackOfficeUser(ClaimsPrincipal backOfficePrincipal, OpenIddictRequest request)
private Task<IActionResult> SignInBackOfficeUser(ClaimsPrincipal backOfficePrincipal, OpenIddictRequest request)
{
Claim[] backOfficeClaims = backOfficePrincipal.Claims.ToArray();
foreach (Claim backOfficeClaim in backOfficeClaims)
@@ -506,7 +506,7 @@ public class BackOfficeController : SecurityControllerBase
backOfficePrincipal.SetScopes(OpenIddictConstants.Scopes.OfflineAccess);
}
return new SignInResult(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, backOfficePrincipal);
return Task.FromResult<IActionResult>(new SignInResult(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, backOfficePrincipal));
}
private async Task<IActionResult> SignInBackOfficeUser(BackOfficeIdentityUser backOfficeUser, OpenIddictRequest request)
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
@@ -20,13 +20,13 @@ public class ConfigurationSecurityController : SecurityControllerBase
[HttpGet("configuration")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(SecurityConfigurationResponseModel), StatusCodes.Status200OK)]
public async Task<IActionResult> Configuration(CancellationToken cancellationToken)
public Task<IActionResult> Configuration(CancellationToken cancellationToken)
{
var viewModel = new SecurityConfigurationResponseModel
{
PasswordConfiguration = _passwordConfigurationPresentationFactory.CreatePasswordConfigurationResponseModel(),
};
return await Task.FromResult(Ok(viewModel));
return Task.FromResult<IActionResult>(Ok(viewModel));
}
}
@@ -1,13 +1,11 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Api.Management.Security;
using Umbraco.Cms.Api.Management.ViewModels.Server;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.DependencyInjection;
namespace Umbraco.Cms.Api.Management.Controllers.Server;
@@ -18,19 +16,6 @@ public class ConfigurationServerController : ServerControllerBase
private readonly GlobalSettings _globalSettings;
private readonly IBackOfficeExternalLoginProviders _externalLoginProviders;
[Obsolete("Use the constructor that accepts all arguments. Will be removed in V16.")]
public ConfigurationServerController(IOptions<SecuritySettings> securitySettings)
: this(securitySettings, StaticServiceProvider.Instance.GetRequiredService<IOptions<GlobalSettings>>())
{
}
[Obsolete("Use the constructor that accepts all arguments. Will be removed in V16.")]
public ConfigurationServerController(IOptions<SecuritySettings> securitySettings, IOptions<GlobalSettings> globalSettings)
: this(securitySettings, globalSettings, StaticServiceProvider.Instance.GetRequiredService<IBackOfficeExternalLoginProviders>())
{
}
[ActivatorUtilitiesConstructor]
public ConfigurationServerController(IOptions<SecuritySettings> securitySettings, IOptions<GlobalSettings> globalSettings, IBackOfficeExternalLoginProviders externalLoginProviders)
{
_securitySettings = securitySettings.Value;
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
@@ -19,6 +19,6 @@ public class StatusServerController : ServerControllerBase
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ServerStatusResponseModel), StatusCodes.Status200OK)]
public async Task<ActionResult<ServerStatusResponseModel>> Get(CancellationToken cancellationToken) =>
await Task.FromResult(new ServerStatusResponseModel { ServerStatus = _runtimeState.Level });
public Task<ActionResult<ServerStatusResponseModel>> Get(CancellationToken cancellationToken)
=> Task.FromResult<ActionResult<ServerStatusResponseModel>>(new ServerStatusResponseModel { ServerStatus = _runtimeState.Level });
}
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Extensions;
@@ -18,17 +18,17 @@ public class ItemStaticFileItemController : StaticFileItemControllerBase
[HttpGet]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(IEnumerable<StaticFileItemResponseModel>), StatusCodes.Status200OK)]
public async Task<IActionResult> Item(
public Task<IActionResult> Item(
CancellationToken cancellationToken,
[FromQuery(Name = "path")] HashSet<string> paths)
{
if (paths.Count is 0)
{
return Ok(Enumerable.Empty<StaticFileItemResponseModel>());
return Task.FromResult<IActionResult>(Ok(Enumerable.Empty<StaticFileItemResponseModel>()));
}
paths = paths.Select(path => path.VirtualPathToSystemPath()).ToHashSet();
IEnumerable<StaticFileItemResponseModel> responseModels = _fileItemPresentationFactory.CreateStaticFileItemResponseModels(paths);
return await Task.FromResult(Ok(responseModels));
return Task.FromResult<IActionResult>(Ok(responseModels));
}
}
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Extensions;
@@ -18,17 +18,17 @@ public class ItemStylesheetItemController : StylesheetItemControllerBase
[HttpGet]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(IEnumerable<StylesheetItemResponseModel>), StatusCodes.Status200OK)]
public async Task<IActionResult> Item(
public Task<IActionResult> Item(
CancellationToken cancellationToken,
[FromQuery(Name = "path")] HashSet<string> paths)
{
if (paths.Count is 0)
{
return Ok(Enumerable.Empty<StylesheetItemResponseModel>());
return Task.FromResult<IActionResult>(Ok(Enumerable.Empty<StylesheetItemResponseModel>()));
}
paths = paths.Select(path => path.VirtualPathToSystemPath()).ToHashSet();
IEnumerable<StylesheetItemResponseModel> responseModels = _fileItemPresentationFactory.CreateStylesheetItemResponseModels(paths);
return await Task.FromResult(Ok(responseModels));
return Task.FromResult<IActionResult>(Ok(responseModels));
}
}
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
@@ -42,6 +42,6 @@ public class ByQueryTagController : TagControllerBase
Total = responseModels.Count,
};
return await Task.FromResult(Ok(pagedViewModel));
return Ok(pagedViewModel);
}
}
@@ -13,13 +13,13 @@ public class AllTelemetryController : TelemetryControllerBase
[HttpGet]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PagedViewModel<TelemetryResponseModel>), StatusCodes.Status200OK)]
public async Task<PagedViewModel<TelemetryResponseModel>> GetAll(
public Task<PagedViewModel<TelemetryResponseModel>> GetAll(
CancellationToken cancellationToken,
int skip = 0,
int take = 100)
{
TelemetryLevel[] levels = Enum.GetValues<TelemetryLevel>();
return await Task.FromResult(new PagedViewModel<TelemetryResponseModel>
return Task.FromResult(new PagedViewModel<TelemetryResponseModel>
{
Total = levels.Length,
Items = levels.Skip(skip).Take(take).Select(level => new TelemetryResponseModel { TelemetryLevel = level }),
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Core.Services;
@@ -16,6 +16,6 @@ public class GetTelemetryController : TelemetryControllerBase
[HttpGet("level")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(TelemetryResponseModel), StatusCodes.Status200OK)]
public async Task<TelemetryRepresentationBase> Get(CancellationToken cancellationToken)
=> await Task.FromResult(new TelemetryResponseModel { TelemetryLevel = _metricsConsentService.GetConsentLevel() });
public Task<TelemetryRepresentationBase> Get(CancellationToken cancellationToken)
=> Task.FromResult<TelemetryRepresentationBase>(new TelemetryResponseModel { TelemetryLevel = _metricsConsentService.GetConsentLevel() });
}
@@ -1,4 +1,4 @@
using Asp.Versioning;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Core.Services;
@@ -34,6 +34,6 @@ public class SetTelemetryController : TelemetryControllerBase
}
await _metricsConsentService.SetConsentLevelAsync(telemetryRepresentationBase.TelemetryLevel);
return await Task.FromResult(Ok());
return Ok();
}
}

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