Merge remote-tracking branch 'origin/v9/dev' into v10/dev
# Conflicts: # build/build.ps1 # build/templates/UmbracoPackage/.template.config/template.json # build/templates/UmbracoProject/.template.config/dotnetcli.host.json # build/templates/UmbracoProject/.template.config/ide.host.json # build/templates/UmbracoProject/.template.config/template.json # src/Umbraco.Core/Constants-System.cs # src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Services.cs # src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs # src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs # umbraco-netcore-only.sln
This commit is contained in:
93
.github/CODE_OF_CONDUCT.md
vendored
93
.github/CODE_OF_CONDUCT.md
vendored
@@ -1,93 +0,0 @@
|
||||
# Umbraco Code of Conduct
|
||||
|
||||
## Preamble
|
||||
|
||||
We are the friendly CMS. And our friendliness stems from our values. That's why we have set for ourselves, Umbraco HQ, and the community, five values to guide us in everything we do:
|
||||
|
||||
* Trust - We believe in and empower people
|
||||
* Respect - We treat others as we would like to be treated
|
||||
* Open - We share our thoughts and knowledge
|
||||
* Hungry - We want to do things better, best is next
|
||||
* Friendly - We want to build long-lasting relationships
|
||||
|
||||
With these values in mind, we want to offer the Umbraco community a code of conduct that specifies a baseline standard of behavior so that people with different social values and communication styles can work together.
|
||||
|
||||
This code of conduct is based on the widely used Contributor Covenant, as described in [https://www.contributor-covenant.org/](https://www.contributor-covenant.org/)
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
Examples of behavior that contributes to a positive environment for our community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or advances of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders (e.g. Meetup & festival organizers, moderators, maintainers, ...) are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
|
||||
|
||||
Specific enforcement steps are listed in the [Code of Conduct Enforcement Guidelines](https://github.com/umbraco/Umbraco-CMS/blob/v8/contrib/.github/CODE_OF_CONDUCT_ENFORCEMENT.md) document which is an appendix of this document, updated and maintained by the Code of Conduct Team.
|
||||
|
||||
## Scope
|
||||
This Code of Conduct applies within all community spaces and events supported by Umbraco HQ or using the Umbraco name. It also applies when an individual is officially representing the community in public spaces.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior, may be reported at [conduct@umbraco.com](mailto:conduct@umbraco.com). All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
Or alternatively, you can reach out directly to any of the team members behind the address above:
|
||||
|
||||
* Sebastiaan Janssen (He, Him - Languages spoken: English, Dutch, Danish(Read)) [sebastiaan@umbraco.com](mailto:sebastiaan@umbraco.com)
|
||||
* Ilham Boulghallat (She, Her - Languages spoken: English, French, Arabic) [ilham@umbraco.com](mailto:ilham@umbraco.com)
|
||||
* Arnold Visser (He, Him - Languages spoken: English, Dutch) [arnold@umbraco.com](mailto:arnold@umbraco.com)
|
||||
* Emma Burstow (She, Her - Languages spoken: English) [ema@umbraco.com](mailto:ema@umbraco.com)
|
||||
|
||||
The review process is done with full respect for the privacy and security of the reporter of any incident.
|
||||
|
||||
People with a conflict of interest should exclude themselves or if necessary be excluded by the other team members.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
**1. Correction**
|
||||
Community Impact: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
|
||||
|
||||
Consequence: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
**2. Warning**
|
||||
Community Impact: A violation through a single incident or series of actions.
|
||||
|
||||
Consequence: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
|
||||
|
||||
**3. Temporary Ban**
|
||||
Community Impact: A serious violation of community standards, including sustained inappropriate behavior.
|
||||
|
||||
Consequence: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
|
||||
|
||||
**4. Permanent Ban**
|
||||
Community Impact: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
Consequence: A permanent ban from any sort of public interaction within the community.
|
||||
|
||||
## Attribution
|
||||
This Code of Conduct is adapted from the Contributor Covenant, version 2.0, available at [https://www.contributor-covenant.org/version/2/0/code_of_conduct.html](https://www.contributor-covenant.org/version/2/0/code_of_conduct.html).
|
||||
|
||||
This Code of Conduct will be maintained and reviewed by the team listed above.
|
||||
57
.github/CODE_OF_CONDUCT_ENFORCEMENT.md
vendored
57
.github/CODE_OF_CONDUCT_ENFORCEMENT.md
vendored
@@ -1,57 +0,0 @@
|
||||
# Umbraco Code of Conduct Enforcement guidelines - Consequence Ladder
|
||||
|
||||
These are the steps followed by the [Umbraco Code of Conduct Team](https://github.com/umbraco/Umbraco-CMS/blob/v8/contrib/.github/CODE_OF_CONDUCT.md) when we respond to an issue or incident brought to our attention by a community member.
|
||||
|
||||
This is an appendix to the Code of Conduct and is updated and maintained by the Code of Conduct Team.
|
||||
|
||||
To make sure that all reports will be reviewed and investigated promptly and fairly, as highlighted in the Umbraco Code of Conduct, we are following [Mozilla’s Consequence Ladder approach](https://github.com/mozilla/inclusion/blob/master/code-of-conduct-enforcement/consequence-ladder.md).
|
||||
|
||||
This approach helps the Team enforce the Code of Conduct in a structured manner and can be used as a way of communicating escalation. Each time the Team takes an action (warning, ban) the individual is made aware of future consequences. The Team can either follow the order of the levels in the ladder or decide to jump levels. When needed, the team can go directly to a permanent ban.
|
||||
|
||||
**Level 0: No Action**
|
||||
Recommendations do not indicate a violation of the Code of Conduct.
|
||||
|
||||
**Level 1: Simple Warning Issued**
|
||||
A private, written warning from the Code of Conduct Team, with clarity of violation, consequences of continued behavior.
|
||||
|
||||
**Level 2: Warning**
|
||||
A private, written warning from the Code of Conduct Team, with clarity of violation, consequences of continued behavior. Additionally:
|
||||
|
||||
* Communication of next-level consequences if behaviors are repeated (according to this ladder).
|
||||
|
||||
**Level 3: Warning + Mandatory Cooling Off Period (Access Retained)**
|
||||
A private warning from the Code of Conduct Team, with clarity of violation, consequences of continued behavior. Additionally:
|
||||
|
||||
* Request to avoid interaction on community messaging platforms (public forums, Our, commenting on issues).
|
||||
* This includes avoiding any interactions in any Umbraco channels, spaces/offices, as well as external channels like social media (e.g. Twitter, Facebook, LinkedIn). For example, 'following/liking/retweeting' would be considered a violation of these terms, and consequence would escalate according to this ladder.
|
||||
* Require they do not interact with others in the report, or those who they suspect are involved in the report.
|
||||
* Suggestions for 'out of office' type of message on platforms, to reduce curiosity, or suspicion among those not involved.
|
||||
|
||||
**Level 4: Temporary Ban (Access Revoked)**
|
||||
Private communication of ban from the Code of Conduct Team, with clarity of violation, consequences of continued behavior. Additionally:
|
||||
|
||||
* 3-6 months imposed break.
|
||||
* All accounts deactivated, or blocked during this time (Our, HQ Slack if applicable).
|
||||
* Require to avoid interaction on community messaging platforms (public forums, Our, commenting on issues).
|
||||
* This includes avoiding any interactions in any Umbraco channels, spaces/offices, as well as external channels like social media (e.g. Twitter, Facebook, LinkedIn). For example, 'following/liking/retweeting' would be considered a violation of these terms, and consequence would escalate according to this ladder.
|
||||
* All community leadership roles (e.g. Community Teams, Meetup/festival organizer, Commit right on Github..) suspended. (onboarding/reapplication required outside of this process)
|
||||
* No attendance at Umbraco events during the ban period.
|
||||
* Not allowed to enter Umbraco HQ offices during the ban period.
|
||||
* Permission to use the MVP title, if applicable, is revoked during this ban period.
|
||||
* The community leaders running events and other initiatives are informed of the ban.
|
||||
|
||||
**Level 5: Permanent Ban**
|
||||
Private communication of ban from the Code of Conduct Team, with clarity of violation, consequences of continued behavior. Additionally:
|
||||
|
||||
* All accounts deactivated permanently.
|
||||
* No attendance at Umbraco events going forward.
|
||||
* Not allowed to enter Umbraco HQ offices permanently.
|
||||
* All community leadership roles (e.g. Community Teams, Meetup/festival organizer, Commit right on Github..) permanently suspended.
|
||||
* Permission to use the MVP title, if applicable, revoked.
|
||||
* The community leaders running events and other initiatives are informed of the ban.
|
||||
|
||||
|
||||
Sources:
|
||||
* [Mozilla Code of Conduct - Enforcement Consequence Ladder](https://github.com/mozilla/inclusion/blob/master/code-of-conduct-enforcement/consequence-ladder.md)
|
||||
* [Drupal Conflict Resolution Policy and Process](https://www.drupal.org/conflict-resolution)
|
||||
* [Django Code of Conduct - Enforcement Manual](https://www.djangoproject.com/conduct/enforcement-manual/)
|
||||
2
.github/CONTRIBUTING.md
vendored
2
.github/CONTRIBUTING.md
vendored
@@ -10,7 +10,7 @@ Remember, we're a friendly bunch and are happy with whatever contribution you mi
|
||||
|
||||
**Code of conduct**
|
||||
|
||||
This project and everyone participating in it, is governed by the [our Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to [Sebastiaan Janssen - sj@umbraco.dk](mailto:sj@umbraco.dk).
|
||||
This project and everyone participating in it, is governed by the [our Code of Conduct](https://github.com/umbraco/.github/blob/main/.github/CODE_OF_CONDUCT.md).
|
||||
|
||||
**Table of contents**
|
||||
|
||||
|
||||
4
.github/README.md
vendored
4
.github/README.md
vendored
@@ -1,4 +1,4 @@
|
||||
# [Umbraco CMS](https://umbraco.com) · [](../LICENSE.md) [](https://umbraco.visualstudio.com/Umbraco%20Cms/_build?definitionId=75) [](CONTRIBUTING.md) [](https://twitter.com/intent/follow?screen_name=umbraco)
|
||||
# [Umbraco CMS](https://umbraco.com) · [](../LICENSE.md) [](https://umbraco.visualstudio.com/Umbraco%20Cms/_build?definitionId=75) [](CONTRIBUTING.md) [](https://twitter.com/intent/follow?screen_name=umbraco) [](https://discord.gg/umbraco)
|
||||
|
||||
Umbraco is the friendliest, most flexible and fastest growing ASP.NET CMS, and used by more than 500,000 websites worldwide. Our mission is to help you deliver delightful digital experiences by making Umbraco friendly, simpler and social.
|
||||
|
||||
@@ -15,7 +15,7 @@ See the official [Umbraco website](https://umbraco.com) for an introduction, cor
|
||||
- [Community](#join-the-umbraco-community)
|
||||
- [Contributing](#contributing)
|
||||
|
||||
Please also see our [Code of Conduct](CODE_OF_CONDUCT.md).
|
||||
Please also see our [Code of Conduct](https://github.com/umbraco/.github/blob/main/.github/CODE_OF_CONDUCT.md).
|
||||
|
||||
## Getting Started
|
||||
|
||||
|
||||
26
.github/workflows/pr-first-response.yml
vendored
Normal file
26
.github/workflows/pr-first-response.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
name: pr-first-response
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
send-response:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Fetch random comment 🗣️
|
||||
uses: JamesIves/fetch-api-data-action@v2.1.0
|
||||
with:
|
||||
ENDPOINT: https://collaboratorsv2.euwest01.umbraco.io/umbraco/api/comments/PostComment
|
||||
CONFIGURATION: '{ "method": "POST", "headers": {"Authorization": "Bearer ${{ secrets.OUR_BOT_API_TOKEN }}", "Content-Type": "application/json" }, "body": { "repo": "${{ github.repository }}", "number": "${{ github.event.number }}", "actor": "${{ github.actor }}", "commentType": "opened-pr-first-comment"} }'
|
||||
- name: Add PR comment
|
||||
if: "${{ env.fetch-api-data != '' }}"
|
||||
uses: actions/github-script@v5
|
||||
with:
|
||||
script: |
|
||||
github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: `${{ env.fetch-api-data }}`
|
||||
})
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -85,6 +85,12 @@ src/Umbraco.Web.UI/wwwroot/[Uu]mbraco/lib/*
|
||||
src/Umbraco.Web.UI/wwwroot/[Uu]mbraco/views/*
|
||||
src/Umbraco.Web.UI/wwwroot/Media/*
|
||||
src/Umbraco.Web.UI/Smidge/
|
||||
src/Umbraco.Web.UI/App_Code/
|
||||
src/Umbraco.Web.UI/App_Plugins/
|
||||
src/Umbraco.Web.UI/Views/
|
||||
!src/Umbraco.Web.UI/Views/Partials/blocklist/
|
||||
!src/Umbraco.Web.UI/Views/Partials/grid/
|
||||
!src/Umbraco.Web.UI/Views/_ViewImports.cshtml
|
||||
|
||||
# Tests
|
||||
cypress.env.json
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);wwwroot\is-cache\**;wwwroot\ms-cache\**</DefaultItemExcludes>
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);App_Plugins/**</DefaultItemExcludes>
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);umbraco/Data/**</DefaultItemExcludes>
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);umbraco/Logs/**</DefaultItemExcludes>
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);wwwroot/media/**</DefaultItemExcludes>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<PropertyGroup>
|
||||
<ContentFilesPath>$(MSBuildThisFileDirectory)..\content\umbraco\**\*.*</ContentFilesPath>
|
||||
@@ -6,16 +6,6 @@
|
||||
<UmbracoWwwrootName Condition="'$(UmbracoWwwrootName)' == ''">umbraco</UmbracoWwwrootName>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);App_Plugins\**;</DefaultItemExcludes>
|
||||
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);umbraco\Data\**;</DefaultItemExcludes>
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);umbraco\Logs\**;</DefaultItemExcludes>
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);umbraco\mediacache\**;</DefaultItemExcludes>
|
||||
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);wwwroot\media\**;</DefaultItemExcludes>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="CopyUmbracoAssets" BeforeTargets="BeforeBuild">
|
||||
<ItemGroup>
|
||||
<ContentFiles Include="$(ContentFilesPath)" />
|
||||
@@ -39,6 +29,7 @@
|
||||
|
||||
<ContentWithTargetPath
|
||||
Include="@(_AppPluginsFiles)"
|
||||
Exclude="@(ContentWithTargetPath)"
|
||||
TargetPath="%(Identity)"
|
||||
CopyToOutputDirectory="PreserveNewest"
|
||||
CopyToPublishDirectory="PreserveNewest"/>
|
||||
@@ -65,6 +56,7 @@
|
||||
|
||||
<ContentWithTargetPath
|
||||
Include="@(_UmbracoFolderFiles)"
|
||||
Exclude="@(ContentWithTargetPath)"
|
||||
TargetPath="%(Identity)"
|
||||
CopyToOutputDirectory="PreserveNewest"
|
||||
CopyToPublishDirectory="PreserveNewest"/>
|
||||
@@ -92,7 +84,7 @@
|
||||
|
||||
<Target Name="IncludeUmbracoRazorFiles" BeforeTargets="ResolveRazorGenerateInputs">
|
||||
<ItemGroup>
|
||||
<Content Include="$(MSBuildProjectDirectory)\umbraco\**\*.cshtml" />
|
||||
<Content Include="$(MSBuildProjectDirectory)\umbraco\**\*.cshtml" Exclude="@(Content)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
|
||||
@@ -540,41 +540,26 @@ stages:
|
||||
|
||||
$ubuild = build/build.ps1 -get -continue
|
||||
|
||||
|
||||
$version = $ubuild.GetUmbracoVersion()
|
||||
|
||||
$isRelease = [regex]::matches($env:BUILD_SOURCEBRANCH,"v\d+\/\d+.\d+.*")
|
||||
|
||||
if ($isRelease.Count -gt 0) {
|
||||
$continuous = $version.Semver
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$date = (Get-Date).ToString("yyyyMMdd")
|
||||
$continuous = "$($version.release)-preview$date.$(Build.BuildId)"
|
||||
$ubuild.SetUmbracoVersion($continuous)
|
||||
|
||||
#Update the version in templates also
|
||||
|
||||
$templatePath =
|
||||
'build/templates/UmbracoProject/.template.config/template.json'
|
||||
|
||||
$a = Get-Content $templatePath -raw | ConvertFrom-Json
|
||||
|
||||
$a.symbols.version.defaultValue = $continuous
|
||||
|
||||
$a | ConvertTo-Json -depth 32| set-content $templatePath
|
||||
|
||||
|
||||
$templatePath =
|
||||
'build/templates/UmbracoPackage/.template.config/template.json'
|
||||
|
||||
$a = Get-Content $templatePath -raw | ConvertFrom-Json
|
||||
|
||||
$a.symbols.version.defaultValue = $continuous
|
||||
|
||||
$a | ConvertTo-Json -depth 32| set-content $templatePath
|
||||
# Update the default Umbraco version in templates
|
||||
$templatePaths = Get-ChildItem 'templates/**/.template.config/template.json'
|
||||
foreach ($templatePath in $templatePaths) {
|
||||
$a = Get-Content $templatePath -Raw | ConvertFrom-Json
|
||||
if ($a.symbols -and $a.symbols.UmbracoVersion) {
|
||||
$a.symbols.UmbracoVersion.defaultValue = $continuous
|
||||
$a | ConvertTo-Json -Depth 32 | Set-Content $templatePath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "##vso[build.updatebuildnumber]$continuous.$(Build.BuildId)"
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
@{ Continue = $continue })
|
||||
if ($ubuild.OnError()) { return }
|
||||
|
||||
Write-Host "Umbraco Cms Build"
|
||||
Write-Host "Umbraco CMS Build"
|
||||
Write-Host "Umbraco.Build v$($ubuild.BuildVersion)"
|
||||
|
||||
# ################################################################
|
||||
@@ -84,7 +84,7 @@
|
||||
$this.SetEnvVar("NPM_CONFIG_CACHE", $node_npmcache)
|
||||
$this.SetEnvVar("NPM_CONFIG_PREFIX", $node_npmprefix)
|
||||
|
||||
$ignore = $this.ClearEnvVar("NODE_NO_HTTP2")
|
||||
$this.ClearEnvVar("NODE_NO_HTTP2")
|
||||
})
|
||||
|
||||
$ubuild.DefineMethod("CompileBelle",
|
||||
@@ -171,11 +171,6 @@
|
||||
$src = "$($this.SolutionRoot)\src"
|
||||
$log = "$($this.BuildTemp)\build.umbraco.log"
|
||||
|
||||
if ($this.BuildEnv.VisualStudio -eq $null)
|
||||
{
|
||||
throw "Build environment does not provide VisualStudio."
|
||||
}
|
||||
|
||||
Write-Host "Compile Umbraco"
|
||||
Write-Host "Logging to $log"
|
||||
|
||||
@@ -191,14 +186,14 @@
|
||||
|
||||
# remove extra files
|
||||
$webAppBin = "$($this.BuildTemp)\WebApp\bin"
|
||||
$excludeDirs = @("$($webAppBin)\refs","$($webAppBin)\runtimes","$($webAppBin)\Umbraco","$($webAppBin)\wwwroot")
|
||||
$excludeDirs = @("$($webAppBin)\refs","$($webAppBin)\runtimes","$($webAppBin)\umbraco","$($webAppBin)\wwwroot")
|
||||
$excludeFiles = @("$($webAppBin)\appsettings.*","$($webAppBin)\*.deps.json","$($webAppBin)\*.exe","$($webAppBin)\*.config","$($webAppBin)\*.runtimeconfig.json")
|
||||
$this.RemoveDirectory($excludeDirs)
|
||||
$this.RemoveFile($excludeFiles)
|
||||
|
||||
# copy rest of the files into WebApp
|
||||
$this.CopyFiles("$($this.SolutionRoot)\src\Umbraco.Web.UI\Umbraco", "*", "$($this.BuildTemp)\WebApp\umbraco")
|
||||
$excludeUmbracoDirs = @("$($this.BuildTemp)\WebApp\umbraco\lib")
|
||||
$this.CopyFiles("$($this.SolutionRoot)\src\Umbraco.Web.UI\umbraco", "*", "$($this.BuildTemp)\WebApp\umbraco")
|
||||
$excludeUmbracoDirs = @("$($this.BuildTemp)\WebApp\umbraco\lib","$($this.BuildTemp)\WebApp\umbraco\Data","$($this.BuildTemp)\WebApp\umbraco\Logs")
|
||||
$this.RemoveDirectory($excludeUmbracoDirs)
|
||||
$this.CopyFiles("$($this.SolutionRoot)\src\Umbraco.Web.UI\Views", "*", "$($this.BuildTemp)\WebApp\Views")
|
||||
Copy-Item "$($this.SolutionRoot)\src\Umbraco.Web.UI\appsettings.json" "$($this.BuildTemp)\WebApp"
|
||||
@@ -251,27 +246,21 @@
|
||||
$buildConfiguration = "Release"
|
||||
$log = "$($this.BuildTemp)\msbuild.tests.log"
|
||||
|
||||
if ($this.BuildEnv.VisualStudio -eq $null)
|
||||
{
|
||||
throw "Build environment does not provide VisualStudio."
|
||||
}
|
||||
|
||||
Write-Host "Compile Tests"
|
||||
Write-Host "Logging to $log"
|
||||
|
||||
# beware of the weird double \\ at the end of paths
|
||||
# see http://edgylogic.com/blog/powershell-and-external-commands-done-right/
|
||||
&$this.BuildEnv.VisualStudio.MsBuild "$($this.SolutionRoot)\tests\Umbraco.Tests\Umbraco.Tests.csproj" `
|
||||
/p:WarningLevel=0 `
|
||||
/p:Configuration=$buildConfiguration `
|
||||
/p:Platform=AnyCPU `
|
||||
/p:UseWPP_CopyWebApplication=True `
|
||||
/p:PipelineDependsOnBuild=False `
|
||||
/p:OutDir="$($this.BuildTemp)\tests\\" `
|
||||
/p:Verbosity=minimal `
|
||||
/t:Build `
|
||||
/tv:"$($this.BuildEnv.VisualStudio.ToolsVersion)" `
|
||||
/p:UmbracoBuild=True `
|
||||
&dotnet msbuild "$($this.SolutionRoot)\tests\Umbraco.Tests\Umbraco.Tests.csproj" `
|
||||
-target:Build `
|
||||
-property:WarningLevel=0 `
|
||||
-property:Configuration=$buildConfiguration `
|
||||
-property:Platform=AnyCPU `
|
||||
-property:UseWPP_CopyWebApplication=True `
|
||||
-property:PipelineDependsOnBuild=False `
|
||||
-property:OutDir="$($this.BuildTemp)\tests\\" `
|
||||
-property:Verbosity=minimal `
|
||||
-property:UmbracoBuild=True `
|
||||
> $log
|
||||
|
||||
if (-not $?) { throw "Failed to compile tests." }
|
||||
@@ -285,10 +274,6 @@
|
||||
|
||||
$src = "$($this.SolutionRoot)\src"
|
||||
$tmp = "$($this.BuildTemp)"
|
||||
$out = "$($this.BuildOutput)"
|
||||
$templates = "$($this.SolutionRoot)\build\templates"
|
||||
|
||||
$buildConfiguration = "Release"
|
||||
|
||||
# cleanup build
|
||||
Write-Host "Clean build"
|
||||
@@ -302,7 +287,6 @@
|
||||
# create directories
|
||||
Write-Host "Create directories"
|
||||
mkdir "$tmp\WebApp\App_Data" > $null
|
||||
mkdir "$tmp\Templates" > $null
|
||||
#mkdir "$tmp\WebApp\Media" > $null
|
||||
#mkdir "$tmp\WebApp\Views" > $null
|
||||
|
||||
@@ -324,17 +308,6 @@
|
||||
$this.CopyFiles("$src\Umbraco.Web.UI\wwwroot\umbraco\js", "*", "$tmp\WebApp\wwwroot\umbraco\js")
|
||||
$this.CopyFiles("$src\Umbraco.Web.UI\wwwroot\umbraco\lib", "*", "$tmp\WebApp\wwwroot\umbraco\lib")
|
||||
$this.CopyFiles("$src\Umbraco.Web.UI\wwwroot\umbraco\views", "*", "$tmp\WebApp\wwwroot\umbraco\views")
|
||||
|
||||
# Prepare templates
|
||||
Write-Host "Copy template files"
|
||||
$this.CopyFiles("$templates", "*", "$tmp\Templates")
|
||||
|
||||
Write-Host "Copy files for dotnet templates"
|
||||
$this.CopyFiles("$src\Umbraco.Web.UI", "Program.cs", "$tmp\Templates\UmbracoProject")
|
||||
$this.CopyFiles("$src\Umbraco.Web.UI", "Startup.cs", "$tmp\Templates\UmbracoProject")
|
||||
$this.CopyFiles("$src\Umbraco.Web.UI\Views", "*", "$tmp\Templates\UmbracoProject\Views")
|
||||
|
||||
$this.RemoveDirectory("$tmp\Templates\UmbracoProject\bin")
|
||||
})
|
||||
|
||||
|
||||
@@ -376,7 +349,7 @@
|
||||
$ubuild.DefineMethod("PackageNuGet",
|
||||
{
|
||||
$nuspecs = "$($this.SolutionRoot)\build\NuSpecs"
|
||||
$templates = "$($this.BuildTemp)\Templates"
|
||||
$templates = "$($this.SolutionRoot)\templates"
|
||||
|
||||
Write-Host "Create NuGet packages"
|
||||
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata minClientVersion="4.1.0">
|
||||
<id>Umbraco.Templates</id>
|
||||
<version>1.0.0</version>
|
||||
<authors>Umbraco HQ</authors>
|
||||
<owners>Umbraco HQ</owners>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://umbraco.com/</projectUrl>
|
||||
<iconUrl>https://umbraco.com/dist/nuget/logo-small.png</iconUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>Umbraco Cms templates for .NET Core Template Engine available through the dotnet CLI's new command</description>
|
||||
<language>en-US</language>
|
||||
<tags>umbraco</tags>
|
||||
<repository type="git" url="https://github.com/umbraco/umbraco-cms" />
|
||||
<packageTypes>
|
||||
<packageType name="Template" />
|
||||
</packageTypes>
|
||||
</metadata>
|
||||
</package>
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/dotnetcli.host",
|
||||
"symbolInfo": {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/vs-2017.3.host",
|
||||
"order" : 0,
|
||||
"icon": "icon.png",
|
||||
"description": {
|
||||
"id": "UmbracoPackage",
|
||||
"text": "Umbraco Package - An empty Umbraco CMS package (Plugin)"
|
||||
},
|
||||
"symbolInfo": [
|
||||
|
||||
]
|
||||
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/template",
|
||||
"author": "Umbraco HQ",
|
||||
"description": "An empty Umbraco Package/Plugin ready to get started",
|
||||
"classifications": [ "Web", "CMS", "Umbraco", "Package", "Plugin"],
|
||||
"groupIdentity": "Umbraco.Templates.UmbracoPackage",
|
||||
"identity": "Umbraco.Templates.UmbracoPackage.CSharp",
|
||||
"name": "Umbraco Package",
|
||||
"shortName": "umbracopackage",
|
||||
"defaultName": "UmbracoPackage1",
|
||||
"preferNameDirectory": true,
|
||||
"tags": {
|
||||
"language": "C#",
|
||||
"type": "project"
|
||||
},
|
||||
"primaryOutputs": [
|
||||
{
|
||||
"path": "UmbracoPackage.csproj"
|
||||
}
|
||||
],
|
||||
"sourceName": "UmbracoPackage",
|
||||
"preferNameDirectory": true,
|
||||
"symbols": {
|
||||
"version": {
|
||||
"type": "parameter",
|
||||
"datatype": "string",
|
||||
"defaultValue": "10.0.0-rc",
|
||||
"description": "The version of Umbraco to load using NuGet",
|
||||
"replaces": "UMBRACO_VERSION_FROM_TEMPLATE"
|
||||
},
|
||||
"namespaceReplacer": {
|
||||
"type": "generated",
|
||||
"generator": "regex",
|
||||
"dataType": "string",
|
||||
"replaces": "UmbracoPackage",
|
||||
"parameters": {
|
||||
"source": "name",
|
||||
"steps": [
|
||||
{
|
||||
"regex": "\\s",
|
||||
"replacement": "_"
|
||||
},
|
||||
{
|
||||
"regex": "-",
|
||||
"replacement": "_"
|
||||
},
|
||||
{
|
||||
"regex": "^[^a-zA-Z_]+",
|
||||
"replacement": "_"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"msbuildReplacer": {
|
||||
"type": "generated",
|
||||
"generator": "regex",
|
||||
"dataType": "string",
|
||||
"replaces": "UmbracoPackageMsBuild",
|
||||
"parameters": {
|
||||
"source": "name",
|
||||
"steps": [
|
||||
{
|
||||
"regex": "\\s",
|
||||
"replacement": ""
|
||||
},
|
||||
{
|
||||
"regex": "\\.",
|
||||
"replacement": ""
|
||||
},
|
||||
{
|
||||
"regex": "-",
|
||||
"replacement": ""
|
||||
},
|
||||
{
|
||||
"regex": "^[^a-zA-Z_]+",
|
||||
"replacement": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"Framework": {
|
||||
"type": "parameter",
|
||||
"description": "The target framework for the project.",
|
||||
"datatype": "choice",
|
||||
"choices": [
|
||||
{
|
||||
"choice": "net6.0",
|
||||
"description": "Target net6.0"
|
||||
}
|
||||
],
|
||||
"replaces": "net6.0",
|
||||
"defaultValue": "net6.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
{
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/dotnetcli.host",
|
||||
"symbolInfo": {
|
||||
"PackageTestSiteName": {
|
||||
"longName": "PackageTestSiteName",
|
||||
"shortName": "p"
|
||||
},
|
||||
"SkipRestore": {
|
||||
"longName": "no-restore",
|
||||
"shortName": ""
|
||||
},
|
||||
"FriendlyName": {
|
||||
"longName": "friendly-name",
|
||||
"shortName": ""
|
||||
},
|
||||
"Email": {
|
||||
"longName": "email",
|
||||
"shortName": ""
|
||||
},
|
||||
"Password": {
|
||||
"longName": "password",
|
||||
"shortName": ""
|
||||
},
|
||||
"ConnectionString":{
|
||||
"longName": "connection-string",
|
||||
"shortName": ""
|
||||
},
|
||||
"NoNodesViewPath":{
|
||||
"longName": "no-nodes-view-path",
|
||||
"shortName": ""
|
||||
},
|
||||
"UseHttpsRedirect": {
|
||||
"longName": "use-https-redirect",
|
||||
"shortName": ""
|
||||
}
|
||||
},
|
||||
"usageExamples": [
|
||||
"dotnet new umbraco -n MyNewProject",
|
||||
"dotnet new umbraco -n MyNewProject --no-restore",
|
||||
"dotnet new umbraco -n MyNewProject --friendly-name \"Friendly User\" --email user@email.com --password password1234 --connection-string \"Server=ConnectionStringHere\""
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 22 KiB |
@@ -1,67 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/vs-2017.3.host",
|
||||
"order" : 0,
|
||||
"icon": "icon.png",
|
||||
"description": {
|
||||
"id": "UmbracoProject",
|
||||
"text": "Umbraco Web Application - An empty Umbraco CMS web application"
|
||||
},
|
||||
"symbolInfo": [
|
||||
{
|
||||
"id": "SkipRestore",
|
||||
"name": {
|
||||
"text": "Skips the automatic NuGet restore of the project on create"
|
||||
},
|
||||
"isVisible": "true"
|
||||
},
|
||||
{
|
||||
"id": "PackageTestSiteName",
|
||||
"name": {
|
||||
"text": "Optional: Specify the name of a package that this should be a test site for"
|
||||
},
|
||||
"isVisible": "true"
|
||||
},
|
||||
{
|
||||
"id": "FriendlyName",
|
||||
"name": {
|
||||
"text": "Optional: The friendly name of the user for Umbraco login when using Unattended install"
|
||||
},
|
||||
"isVisible": "true"
|
||||
},
|
||||
{
|
||||
"id": "Email",
|
||||
"name": {
|
||||
"text": "Optional: Email to use for Umbraco login when using Unattended install"
|
||||
},
|
||||
"isVisible": "true"
|
||||
},
|
||||
{
|
||||
"id": "Password",
|
||||
"name": {
|
||||
"text": "Optional: Password to use for Umbraco login when using Unattended install"
|
||||
},
|
||||
"isVisible": "true"
|
||||
},
|
||||
{
|
||||
"id": "ConnectionString",
|
||||
"name": {
|
||||
"text": "Optional: Database connection string when using Unattended install"
|
||||
},
|
||||
"isVisible": "true"
|
||||
},
|
||||
{
|
||||
"id": "NoNodesViewPath",
|
||||
"name": {
|
||||
"text": "Optional: Path to a custom view presented with the Umbraco installation contains no published content"
|
||||
},
|
||||
"isVisible": "true"
|
||||
},
|
||||
{
|
||||
"id": "UseHttpsRedirect",
|
||||
"name": {
|
||||
"text": "Optional: Adds code to Startup.cs to redirect HTTP to HTTPS and enables the UseHttps setting."
|
||||
},
|
||||
"isVisible": "true"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,294 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/template",
|
||||
"author": "Umbraco HQ",
|
||||
"description": "An empty Umbraco Project ready to get started",
|
||||
"classifications": [ "Web", "CMS", "Umbraco"],
|
||||
"groupIdentity": "Umbraco.Templates.UmbracoProject",
|
||||
"identity": "Umbraco.Templates.UmbracoProject.CSharp",
|
||||
"name": "Umbraco Project",
|
||||
"shortName": "umbraco",
|
||||
"defaultName": "UmbracoProject1",
|
||||
"preferNameDirectory": true,
|
||||
"tags": {
|
||||
"language": "C#",
|
||||
"type": "project"
|
||||
},
|
||||
"primaryOutputs": [
|
||||
{
|
||||
"path": "UmbracoProject.csproj"
|
||||
}
|
||||
],
|
||||
"postActions": [
|
||||
{
|
||||
"condition": "(!SkipRestore)",
|
||||
"description": "Restore NuGet packages required by this project",
|
||||
"manualInstructions": [{
|
||||
"text": "Run 'dotnet restore'"
|
||||
}],
|
||||
"actionId": "210D431B-A78B-4D2F-B762-4ED3E3EA9025",
|
||||
"continueOnError": true
|
||||
}
|
||||
],
|
||||
"sourceName": "UmbracoProject",
|
||||
"symbols": {
|
||||
"namespaceReplacer": {
|
||||
"type": "generated",
|
||||
"generator": "regex",
|
||||
"dataType": "string",
|
||||
"replaces": "Umbraco.Cms.Web.UI",
|
||||
"parameters": {
|
||||
"source": "name",
|
||||
"steps": [
|
||||
{
|
||||
"regex": "\\s",
|
||||
"replacement": "_"
|
||||
},
|
||||
{
|
||||
"regex": "-",
|
||||
"replacement": "_"
|
||||
},
|
||||
{
|
||||
"regex": "^[^a-zA-Z_]+",
|
||||
"replacement": "_"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"version": {
|
||||
"type": "parameter",
|
||||
"datatype": "string",
|
||||
"defaultValue": "10.0.0-rc",
|
||||
"description": "The version of Umbraco to load using NuGet",
|
||||
"replaces": "UMBRACO_VERSION_FROM_TEMPLATE"
|
||||
},
|
||||
"PackageTestSiteName": {
|
||||
"type": "parameter",
|
||||
"datatype":"text",
|
||||
"defaultValue": "",
|
||||
"replaces":"PackageTestSiteName",
|
||||
"description": "The name of the package this should be a test site for (Default: '')"
|
||||
},
|
||||
"Framework": {
|
||||
"type": "parameter",
|
||||
"description": "The target framework for the project",
|
||||
"datatype": "choice",
|
||||
"choices": [
|
||||
{
|
||||
"choice": "net6.0",
|
||||
"description": "Target net6.0"
|
||||
}
|
||||
],
|
||||
"replaces": "net6.0",
|
||||
"defaultValue": "net6.0"
|
||||
},
|
||||
"SkipRestore": {
|
||||
"type": "parameter",
|
||||
"datatype": "bool",
|
||||
"description": "If specified, skips the automatic restore of the project on create",
|
||||
"defaultValue": "false"
|
||||
},
|
||||
"HttpPort": {
|
||||
"type": "generated",
|
||||
"generator": "port",
|
||||
"replaces": "HTTP_PORT_FROM_TEMPLATE",
|
||||
"parameters": {
|
||||
"high": 65535,
|
||||
"low": 1024,
|
||||
"fallback": 5000
|
||||
}
|
||||
},
|
||||
"HttpsPort": {
|
||||
"type": "generated",
|
||||
"generator": "port",
|
||||
"replaces": "HTTPS_PORT_FROM_TEMPLATE",
|
||||
"parameters": {
|
||||
"low": 44300,
|
||||
"high": 44399,
|
||||
"fallback": 5001
|
||||
}
|
||||
},
|
||||
"FriendlyName":{
|
||||
"type": "parameter",
|
||||
"datatype":"text",
|
||||
"description": "The friendly name of the user for Umbraco login when using Unattended install (Without installer wizard UI)",
|
||||
"defaultValue": ""
|
||||
},
|
||||
"FriendlyNameReplaced":{
|
||||
"type": "generated",
|
||||
"generator": "regex",
|
||||
"dataType": "string",
|
||||
"replaces": "FRIENDLY_NAME_FROM_TEMPLATE",
|
||||
"parameters": {
|
||||
"source": "FriendlyName",
|
||||
"steps": [
|
||||
{
|
||||
"regex": "\\\\",
|
||||
"replacement": "\\\\"
|
||||
},
|
||||
{
|
||||
"regex": "\\\"",
|
||||
"replacement": "\\\""
|
||||
},
|
||||
{
|
||||
"regex": "\\\n",
|
||||
"replacement": "\\\n"
|
||||
},
|
||||
{
|
||||
"regex": "\\\t",
|
||||
"replacement": "\\\t"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"Email":{
|
||||
"type": "parameter",
|
||||
"datatype":"text",
|
||||
"description": "Email to use for Umbraco login when using Unattended install (Without installer wizard UI)",
|
||||
"defaultValue": ""
|
||||
},
|
||||
"EmailReplaced":{
|
||||
"type": "generated",
|
||||
"generator": "regex",
|
||||
"dataType": "string",
|
||||
"replaces": "EMAIL_FROM_TEMPLATE",
|
||||
"parameters": {
|
||||
"source": "Email",
|
||||
"steps": [
|
||||
{
|
||||
"regex": "\\\\",
|
||||
"replacement": "\\\\"
|
||||
},
|
||||
{
|
||||
"regex": "\\\"",
|
||||
"replacement": "\\\""
|
||||
},
|
||||
{
|
||||
"regex": "\\\n",
|
||||
"replacement": "\\\n"
|
||||
},
|
||||
{
|
||||
"regex": "\\\t",
|
||||
"replacement": "\\\t"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"Password":{
|
||||
"type": "parameter",
|
||||
"datatype":"text",
|
||||
"description": "Password to use for Umbraco login when using Unattended install (Without installer wizard UI)",
|
||||
"defaultValue": ""
|
||||
},
|
||||
"PasswordReplaced":{
|
||||
"type": "generated",
|
||||
"generator": "regex",
|
||||
"dataType": "string",
|
||||
"replaces": "PASSWORD_FROM_TEMPLATE",
|
||||
"parameters": {
|
||||
"source": "Password",
|
||||
"steps": [
|
||||
{
|
||||
"regex": "\\\\",
|
||||
"replacement": "\\\\"
|
||||
},
|
||||
{
|
||||
"regex": "\\\"",
|
||||
"replacement": "\\\""
|
||||
},
|
||||
{
|
||||
"regex": "\\\n",
|
||||
"replacement": "\\\n"
|
||||
},
|
||||
{
|
||||
"regex": "\\\t",
|
||||
"replacement": "\\\t"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"ConnectionString":{
|
||||
"type": "parameter",
|
||||
"datatype":"text",
|
||||
"description": "Database connection string when using Unattended install (Without installer wizard UI)",
|
||||
"defaultValue": ""
|
||||
},
|
||||
"ConnectionStringReplaced":{
|
||||
"type": "generated",
|
||||
"generator": "regex",
|
||||
"dataType": "string",
|
||||
"replaces": "CONNECTION_FROM_TEMPLATE",
|
||||
"parameters": {
|
||||
"source": "ConnectionString",
|
||||
"steps": [
|
||||
{
|
||||
"regex": "\\\\",
|
||||
"replacement": "\\\\"
|
||||
},
|
||||
{
|
||||
"regex": "\\\"",
|
||||
"replacement": "\\\""
|
||||
},
|
||||
{
|
||||
"regex": "\\\n",
|
||||
"replacement": "\\\n"
|
||||
},
|
||||
{
|
||||
"regex": "\\\t",
|
||||
"replacement": "\\\t"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"NoNodesViewPath":{
|
||||
"type": "parameter",
|
||||
"datatype":"text",
|
||||
"description": "Path to a custom view presented with the Umbraco installation contains no published content",
|
||||
"defaultValue": ""
|
||||
},
|
||||
"NoNodesViewPathReplaced":{
|
||||
"type": "generated",
|
||||
"generator": "regex",
|
||||
"dataType": "string",
|
||||
"replaces": "NO_NODES_VIEW_PATH_FROM_TEMPLATE",
|
||||
"parameters": {
|
||||
"source": "NoNodesViewPath",
|
||||
"steps": [
|
||||
{
|
||||
"regex": "\\\\",
|
||||
"replacement": "\\\\"
|
||||
},
|
||||
{
|
||||
"regex": "\\\"",
|
||||
"replacement": "\\\""
|
||||
},
|
||||
{
|
||||
"regex": "\\\n",
|
||||
"replacement": "\\\n"
|
||||
},
|
||||
{
|
||||
"regex": "\\\t",
|
||||
"replacement": "\\\t"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"HasConnectionString":{
|
||||
"type": "computed",
|
||||
"value": "(ConnectionString != \"\")"
|
||||
},
|
||||
"HasNoNodesViewPath":{
|
||||
"type": "computed",
|
||||
"value": "(NoNodesViewPath != \"\")"
|
||||
},
|
||||
"UsingUnattenedInstall":{
|
||||
"type": "computed",
|
||||
"value": "(FriendlyName != \"\" && Email != \"\" && Password != \"\" && ConnectionString != \"\")"
|
||||
},
|
||||
"UseHttpsRedirect":{
|
||||
"type": "parameter",
|
||||
"datatype":"bool",
|
||||
"defaultValue": "false",
|
||||
"description": "Adds code to Startup.cs to redirect HTTP to HTTPS and enables the UseHttps setting (Default: false)"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<RootNamespace Condition="'$(name)' != '$(name{-VALUE-FORMS-}safe_namespace)'">Umbraco.Cms.Web.UI</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Umbraco.Cms" Version="UMBRACO_VERSION_FROM_TEMPLATE" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Force windows to use ICU. Otherwise Windows 10 2019H1+ will do it, but older windows 10 and most if not all winodws servers will run NLS -->
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.ICU.ICU4C.Runtime" Version="68.2.0.9" />
|
||||
|
||||
<RuntimeHostConfigurationOption
|
||||
Condition="$(RuntimeIdentifier.StartsWith('linux')) Or $(RuntimeIdentifier.StartsWith('win')) Or ('$(RuntimeIdentifier)' == '' And !$([MSBuild]::IsOSPlatform('osx')))"
|
||||
Include="System.Globalization.AppLocalIcu"
|
||||
Value="68.2.0.9" />
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="..\PackageTestSiteName\build\PackageTestSiteName.targets" Condition="'$(PackageTestSiteName)' != ''" />
|
||||
|
||||
<ItemGroup Condition="'$(PackageTestSiteName)' != ''">
|
||||
<ProjectReference Include="..\PackageTestSiteName\PackageTestSiteName.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<CopyRazorGenerateFilesToPublishDirectory>true</CopyRazorGenerateFilesToPublishDirectory>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Set this to true if ModelsBuilder mode is not InMemoryAuto-->
|
||||
<PropertyGroup>
|
||||
<RazorCompileOnBuild>false</RazorCompileOnBuild>
|
||||
<RazorCompileOnPublish>false</RazorCompileOnPublish>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,8 +0,0 @@
|
||||
@using Umbraco.Web.UI
|
||||
@using Umbraco.Extensions
|
||||
@using Umbraco.Web.PublishedModels
|
||||
@using Umbraco.Cms.Core.Models.PublishedContent
|
||||
@using Microsoft.AspNetCore.Html
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@addTagHelper *, Smidge
|
||||
@inject Smidge.SmidgeHelper SmidgeHelper
|
||||
@@ -5,7 +5,20 @@
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommandLineParser" Version="2.8.0" />
|
||||
<PackageReference Include="NJsonSchema" Version="10.5.2" />
|
||||
<PackageReference Include="System.Xml.XPath.XmlDocument" Version="4.3.0" />
|
||||
<PackageReference Include="Umbraco.Deploy.Core" Version="9.2.0" />
|
||||
<PackageReference Include="Umbraco.Forms.Core" Version="9.2.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommandLineParser" Version="2.8.0" />
|
||||
<PackageReference Include="NJsonSchema" Version="10.5.2" />
|
||||
@@ -21,7 +34,7 @@
|
||||
<ProjectReference Include="..\Umbraco.Core\Umbraco.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Copy forms xml docs-->
|
||||
<!-- Copy Forms XML docs-->
|
||||
<PropertyGroup>
|
||||
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -198,7 +198,7 @@ namespace Umbraco.Cms.Core.Composing
|
||||
IEnumerable<Assembly> assemblies = null,
|
||||
bool onlyConcreteClasses = true)
|
||||
{
|
||||
var assemblyList = (assemblies ?? AssembliesToScan).ToList();
|
||||
var assemblyList = assemblies ?? AssembliesToScan;
|
||||
|
||||
return GetClassesWithBaseType(assignTypeFrom, assemblyList, onlyConcreteClasses,
|
||||
//the additional filter will ensure that any found types also have the attribute applied.
|
||||
@@ -214,7 +214,7 @@ namespace Umbraco.Cms.Core.Composing
|
||||
/// <returns></returns>
|
||||
public IEnumerable<Type> FindClassesOfType(Type assignTypeFrom, IEnumerable<Assembly> assemblies = null, bool onlyConcreteClasses = true)
|
||||
{
|
||||
var assemblyList = (assemblies ?? AssembliesToScan).ToList();
|
||||
var assemblyList = assemblies ?? AssembliesToScan;
|
||||
|
||||
return GetClassesWithBaseType(assignTypeFrom, assemblyList, onlyConcreteClasses);
|
||||
}
|
||||
@@ -231,7 +231,7 @@ namespace Umbraco.Cms.Core.Composing
|
||||
IEnumerable<Assembly> assemblies = null,
|
||||
bool onlyConcreteClasses = true)
|
||||
{
|
||||
var assemblyList = (assemblies ?? AssembliesToScan).ToList();
|
||||
var assemblyList = assemblies ?? AssembliesToScan;
|
||||
|
||||
return GetClassesWithAttribute(attributeType, assemblyList, onlyConcreteClasses);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Umbraco.Cms.Core.Configuration.Models
|
||||
internal const bool StaticHideTopLevelNodeFromPath = true;
|
||||
internal const bool StaticUseHttps = false;
|
||||
internal const int StaticVersionCheckPeriod = 7;
|
||||
internal const string StaticUmbracoPath = "~/umbraco";
|
||||
internal const string StaticUmbracoPath = Constants.System.DefaultUmbracoPath;
|
||||
internal const string StaticIconsPath = "~/umbraco/assets/icons";
|
||||
internal const string StaticUmbracoCssPath = "~/css";
|
||||
internal const string StaticUmbracoScriptsPath = "~/scripts";
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace Umbraco.Cms.Core.Configuration.Models
|
||||
public class KeepAliveSettings
|
||||
{
|
||||
internal const bool StaticDisableKeepAliveTask = false;
|
||||
internal const string StaticKeepAlivePingUrl = "~/api/keepalive/ping";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the keep alive task is disabled.
|
||||
@@ -20,8 +21,9 @@ namespace Umbraco.Cms.Core.Configuration.Models
|
||||
public bool DisableKeepAliveTask { get; set; } = StaticDisableKeepAliveTask;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value for the keep alive ping URL.
|
||||
/// Gets or sets a value for the keep alive ping URL.
|
||||
/// </summary>
|
||||
public string KeepAlivePingUrl => "~/api/keepalive/ping";
|
||||
[DefaultValue(StaticKeepAlivePingUrl)]
|
||||
public string KeepAlivePingUrl { get; set; } = StaticKeepAlivePingUrl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace Umbraco.Cms.Core.Configuration.Models
|
||||
{
|
||||
internal const string StaticNuCacheSerializerType = "MessagePack";
|
||||
internal const int StaticSqlPageSize = 1000;
|
||||
internal const int StaticKitBatchSize = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value defining the BTree block size.
|
||||
@@ -31,6 +32,12 @@ namespace Umbraco.Cms.Core.Configuration.Models
|
||||
[DefaultValue(StaticSqlPageSize)]
|
||||
public int SqlPageSize { get; set; } = StaticSqlPageSize;
|
||||
|
||||
/// <summary>
|
||||
/// The size to use for nucache Kit batches. Higher value means more content loaded into memory at a time.
|
||||
/// </summary>
|
||||
[DefaultValue(StaticKitBatchSize)]
|
||||
public int KitBatchSize { get; set; } = StaticKitBatchSize;
|
||||
|
||||
public bool UnPublishedContentCompression { get; set; } = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
|
||||
public const string UmbracoDefaultDatabaseName = "Umbraco";
|
||||
|
||||
public const string UmbracoConnectionName = "umbracoDbDSN";
|
||||
public const string UmbracoConnectionName = "umbracoDbDSN";public const string DefaultUmbracoPath = "~/umbraco";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
32
src/Umbraco.Core/Constants-Telemetry.cs
Normal file
32
src/Umbraco.Core/Constants-Telemetry.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
namespace Umbraco.Cms.Core
|
||||
{
|
||||
public static partial class Constants
|
||||
{
|
||||
public static class Telemetry
|
||||
{
|
||||
|
||||
public static string RootCount = "RootCount";
|
||||
public static string DomainCount = "DomainCount";
|
||||
public static string ExamineIndexCount = "ExamineIndexCount";
|
||||
public static string LanguageCount = "LanguageCount";
|
||||
public static string MacroCount = "MacroCount";
|
||||
public static string MediaCount = "MediaCount";
|
||||
public static string MemberCount = "MemberCount";
|
||||
public static string TemplateCount = "TemplateCount";
|
||||
public static string ContentCount = "ContentCount";
|
||||
public static string DocumentTypeCount = "DocumentTypeCount";
|
||||
public static string Properties = "Properties";
|
||||
public static string UserCount = "UserCount";
|
||||
public static string UserGroupCount = "UserGroupCount";
|
||||
public static string ServerOs = "ServerOs";
|
||||
public static string ServerFramework = "ServerFramework";
|
||||
public static string OsLanguage = "OsLanguage";
|
||||
public static string WebServer = "WebServer";
|
||||
public static string ModelsBuilderMode = "ModelBuilderMode";
|
||||
public static string CustomUmbracoPath = "CustomUmbracoPath";
|
||||
public static string AspEnvironment = "AspEnvironment";
|
||||
public static string IsDebug = "IsDebug";
|
||||
public static string DatabaseProvider = "DatabaseProvider";
|
||||
}
|
||||
}
|
||||
}
|
||||
15
src/Umbraco.Core/Dashboards/AnalyticsDashboard.cs
Normal file
15
src/Umbraco.Core/Dashboards/AnalyticsDashboard.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Cms.Core.Dashboards
|
||||
{
|
||||
public class AnalyticsDashboard : IDashboard
|
||||
{
|
||||
public string Alias => "settingsAnalytics";
|
||||
|
||||
public string[] Sections => new [] { "settings" };
|
||||
|
||||
public string View => "views/dashboard/settings/analytics.html";
|
||||
|
||||
public IAccessRule[] AccessRules => Array.Empty<IAccessRule>();
|
||||
}
|
||||
}
|
||||
@@ -118,7 +118,8 @@ namespace Umbraco.Cms.Core.DependencyInjection
|
||||
.Append<Soundcloud>()
|
||||
.Append<Issuu>()
|
||||
.Append<Hulu>()
|
||||
.Append<Giphy>();
|
||||
.Append<Giphy>()
|
||||
.Append<LottieFiles>();
|
||||
builder.SearchableTrees().Add(() => builder.TypeLoader.GetTypes<ISearchableTree>());
|
||||
builder.BackOfficeAssets();
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ using Umbraco.Cms.Core.Install;
|
||||
using Umbraco.Cms.Core.IO;
|
||||
using Umbraco.Cms.Core.Logging;
|
||||
using Umbraco.Cms.Core.Mail;
|
||||
using Umbraco.Cms.Core.Manifest;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Cms.Core.Notifications;
|
||||
using Umbraco.Cms.Core.Packaging;
|
||||
@@ -42,7 +42,6 @@ using Umbraco.Cms.Core.Sync;
|
||||
using Umbraco.Cms.Core.Telemetry;
|
||||
using Umbraco.Cms.Core.Templates;
|
||||
using Umbraco.Cms.Core.Web;
|
||||
using Umbraco.Cms.Web.Common.DependencyInjection;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.DependencyInjection
|
||||
@@ -200,7 +199,7 @@ namespace Umbraco.Cms.Core.DependencyInjection
|
||||
Services.AddSingleton<UriUtility>();
|
||||
|
||||
Services.AddUnique<IDashboardService, DashboardService>();
|
||||
Services.AddUnique<IUserDataService, UserDataService>();
|
||||
Services.AddSingleton<IMetricsConsentService, MetricsConsentService>();
|
||||
|
||||
// will be injected in controllers when needed to invoke rest endpoints on Our
|
||||
Services.AddUnique<IInstallationService, InstallationService>();
|
||||
|
||||
@@ -1082,7 +1082,7 @@ namespace Umbraco.Extensions
|
||||
{
|
||||
return content.Parent != null
|
||||
? content.Parent.Children(variationContextAccessor, culture)
|
||||
: publishedSnapshot.Content.GetAtRoot().WhereIsInvariantOrHasCulture(variationContextAccessor, culture);
|
||||
: publishedSnapshot.Content.GetAtRoot(culture).WhereIsInvariantOrHasCulture(variationContextAccessor, culture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1098,7 +1098,7 @@ namespace Umbraco.Extensions
|
||||
{
|
||||
return content.Parent != null
|
||||
? content.Parent.ChildrenOfType(variationContextAccessor, contentTypeAlias, culture)
|
||||
: publishedSnapshot.Content.GetAtRoot().OfTypes(contentTypeAlias).WhereIsInvariantOrHasCulture(variationContextAccessor, culture);
|
||||
: publishedSnapshot.Content.GetAtRoot(culture).OfTypes(contentTypeAlias).WhereIsInvariantOrHasCulture(variationContextAccessor, culture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1115,7 +1115,7 @@ namespace Umbraco.Extensions
|
||||
{
|
||||
return content.Parent != null
|
||||
? content.Parent.Children<T>(variationContextAccessor, culture)
|
||||
: publishedSnapshot.Content.GetAtRoot().OfType<T>().WhereIsInvariantOrHasCulture(variationContextAccessor, culture);
|
||||
: publishedSnapshot.Content.GetAtRoot(culture).OfType<T>().WhereIsInvariantOrHasCulture(variationContextAccessor, culture);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
52
src/Umbraco.Core/Media/EmbedProviders/LottieFiles.cs
Normal file
52
src/Umbraco.Core/Media/EmbedProviders/LottieFiles.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Core.Media.EmbedProviders
|
||||
{
|
||||
/// <summary>
|
||||
/// Embed Provider for lottiefiles.com the popular opensource JSON-based animation format platform.
|
||||
/// </summary>
|
||||
public class LottieFiles : OEmbedProviderBase
|
||||
{
|
||||
public LottieFiles(IJsonSerializer jsonSerializer) : base(jsonSerializer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override string ApiEndpoint => "https://embed.lottiefiles.com/oembed";
|
||||
|
||||
public override string[] UrlSchemeRegex => new string[]
|
||||
{
|
||||
@"lottiefiles\.com/*"
|
||||
};
|
||||
public override Dictionary<string, string> RequestParams => new Dictionary<string, string>();
|
||||
|
||||
public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0)
|
||||
{
|
||||
var requestUrl = base.GetEmbedProviderUrl(url, maxWidth, maxHeight);
|
||||
OEmbedResponse oembed = base.GetJsonResponse<OEmbedResponse>(requestUrl);
|
||||
var html = oembed.GetHtml();
|
||||
//LottieFiles doesn't seem to support maxwidth and maxheight via oembed
|
||||
// this is therefore a hack... with regexes.. is that ok? HtmlAgility etc etc
|
||||
// otherwise it always defaults to 300...
|
||||
if (maxWidth > 0 && maxHeight > 0)
|
||||
{
|
||||
|
||||
html = Regex.Replace(html, "width=\"([0-9]{1,4})\"", "width=\"" + maxWidth + "\"");
|
||||
html = Regex.Replace(html, "height=\"([0-9]{1,4})\"", "height=\"" + maxHeight + "\"");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//if set to 0, let's default to 100% as an easter egg
|
||||
html = Regex.Replace(html, "width=\"([0-9]{1,4})\"", "width=\"100%\"");
|
||||
html = Regex.Replace(html, "height=\"([0-9]{1,4})\"", "height=\"100%\"");
|
||||
}
|
||||
return html;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
12
src/Umbraco.Core/Models/TelemetryLevel.cs
Normal file
12
src/Umbraco.Core/Models/TelemetryLevel.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Core.Models
|
||||
{
|
||||
[DataContract]
|
||||
public enum TelemetryLevel
|
||||
{
|
||||
Minimal,
|
||||
Basic,
|
||||
Detailed,
|
||||
}
|
||||
}
|
||||
11
src/Umbraco.Core/Models/TelemetryResource.cs
Normal file
11
src/Umbraco.Core/Models/TelemetryResource.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Core.Models
|
||||
{
|
||||
[DataContract]
|
||||
public class TelemetryResource
|
||||
{
|
||||
[DataMember]
|
||||
public TelemetryLevel TelemetryLevel { get; set; }
|
||||
}
|
||||
}
|
||||
20
src/Umbraco.Core/Models/UsageInformation.cs
Normal file
20
src/Umbraco.Core/Models/UsageInformation.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Core.Models
|
||||
{
|
||||
[DataContract]
|
||||
public class UsageInformation
|
||||
{
|
||||
[DataMember(Name = "name")]
|
||||
public string Name { get; }
|
||||
|
||||
[DataMember(Name = "data")]
|
||||
public object Data { get; }
|
||||
|
||||
public UsageInformation(string name, object data)
|
||||
{
|
||||
Name = name;
|
||||
Data = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
20
src/Umbraco.Core/Models/UserTwoFactorProviderModel.cs
Normal file
20
src/Umbraco.Core/Models/UserTwoFactorProviderModel.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Core.Models
|
||||
{
|
||||
[DataContract]
|
||||
public class UserTwoFactorProviderModel
|
||||
{
|
||||
public UserTwoFactorProviderModel(string providerName, bool isEnabledOnUser)
|
||||
{
|
||||
ProviderName = providerName;
|
||||
IsEnabledOnUser = isEnabledOnUser;
|
||||
}
|
||||
|
||||
[DataMember(Name = "providerName")]
|
||||
public string ProviderName { get; }
|
||||
|
||||
[DataMember(Name = "isEnabledOnUser")]
|
||||
public bool IsEnabledOnUser { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
using Umbraco.Cms.Core.Web;
|
||||
|
||||
namespace Umbraco.Cms.Core.Notifications
|
||||
{
|
||||
public class SendingAllowedChildrenNotification : INotification
|
||||
{
|
||||
public IUmbracoContext UmbracoContext { get; }
|
||||
|
||||
public IEnumerable<ContentTypeBasic> Children { get; set; }
|
||||
|
||||
public SendingAllowedChildrenNotification(IEnumerable<ContentTypeBasic> children, IUmbracoContext umbracoContext)
|
||||
{
|
||||
UmbracoContext = umbracoContext;
|
||||
Children = children;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Cms.Core.Notifications
|
||||
{
|
||||
public class UserTwoFactorRequestedNotification : INotification
|
||||
{
|
||||
public UserTwoFactorRequestedNotification(Guid userKey)
|
||||
{
|
||||
UserKey = userKey;
|
||||
}
|
||||
|
||||
public Guid UserKey { get; }
|
||||
}
|
||||
}
|
||||
7
src/Umbraco.Core/Services/IExamineIndexCountService.cs
Normal file
7
src/Umbraco.Core/Services/IExamineIndexCountService.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Umbraco.Cms.Core.Services
|
||||
{
|
||||
public interface IExamineIndexCountService
|
||||
{
|
||||
public int GetCount();
|
||||
}
|
||||
}
|
||||
11
src/Umbraco.Core/Services/IMetricsConsentService.cs
Normal file
11
src/Umbraco.Core/Services/IMetricsConsentService.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Umbraco.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services
|
||||
{
|
||||
public interface IMetricsConsentService
|
||||
{
|
||||
TelemetryLevel GetConsentLevel();
|
||||
|
||||
void SetConsentLevel(TelemetryLevel telemetryLevel);
|
||||
}
|
||||
}
|
||||
10
src/Umbraco.Core/Services/INodeCountService.cs
Normal file
10
src/Umbraco.Core/Services/INodeCountService.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services
|
||||
{
|
||||
public interface INodeCountService
|
||||
{
|
||||
int GetNodeCount(Guid nodeType);
|
||||
int GetMediaCount();
|
||||
}
|
||||
}
|
||||
@@ -58,4 +58,12 @@ namespace Umbraco.Cms.Core.Services
|
||||
/// </summary>
|
||||
Task<IEnumerable<string>> GetEnabledTwoFactorProviderNamesAsync(Guid userOrMemberKey);
|
||||
}
|
||||
|
||||
[Obsolete("This will be merged into ITwoFactorLoginService in Umbraco 11")]
|
||||
public interface ITwoFactorLoginService2 : ITwoFactorLoginService
|
||||
{
|
||||
Task<bool> DisableWithCodeAsync(string providerName, Guid userOrMemberKey, string code);
|
||||
|
||||
Task<bool> ValidateAndSaveAsync(string providerName, Guid userKey, string secret, string code);
|
||||
}
|
||||
}
|
||||
|
||||
10
src/Umbraco.Core/Services/IUsageInformationService.cs
Normal file
10
src/Umbraco.Core/Services/IUsageInformationService.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services
|
||||
{
|
||||
public interface IUsageInformationService
|
||||
{
|
||||
IEnumerable<UsageInformation> GetDetailed();
|
||||
}
|
||||
}
|
||||
34
src/Umbraco.Core/Services/MetricsConsentService.cs
Normal file
34
src/Umbraco.Core/Services/MetricsConsentService.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services
|
||||
{
|
||||
public class MetricsConsentService : IMetricsConsentService
|
||||
{
|
||||
internal const string Key = "UmbracoAnalyticsLevel";
|
||||
|
||||
private readonly IKeyValueService _keyValueService;
|
||||
|
||||
public MetricsConsentService(IKeyValueService keyValueService)
|
||||
{
|
||||
_keyValueService = keyValueService;
|
||||
}
|
||||
|
||||
public TelemetryLevel GetConsentLevel()
|
||||
{
|
||||
var analyticsLevelString = _keyValueService.GetValue(Key);
|
||||
|
||||
if (analyticsLevelString is null || Enum.TryParse(analyticsLevelString, out TelemetryLevel analyticsLevel) is false)
|
||||
{
|
||||
return TelemetryLevel.Basic;
|
||||
}
|
||||
|
||||
return analyticsLevel;
|
||||
}
|
||||
|
||||
public void SetConsentLevel(TelemetryLevel telemetryLevel)
|
||||
{
|
||||
_keyValueService.SetValue(Key, telemetryLevel.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
@@ -9,11 +10,13 @@ using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services
|
||||
{
|
||||
[Obsolete("Use the IUserDataService interface instead")]
|
||||
public class UserDataService : IUserDataService
|
||||
{
|
||||
private readonly IUmbracoVersion _version;
|
||||
private readonly ILocalizationService _localizationService;
|
||||
|
||||
|
||||
public UserDataService(IUmbracoVersion version, ILocalizationService localizationService)
|
||||
{
|
||||
_version = version;
|
||||
|
||||
@@ -84,5 +84,11 @@ namespace Umbraco.Extensions
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public static IUser GetByKey(this IUserService userService, Guid key)
|
||||
{
|
||||
int id = BitConverter.ToInt32(key.ToByteArray(), 0);
|
||||
return userService.GetUserById(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Core.Telemetry.Models
|
||||
{
|
||||
@@ -30,5 +31,8 @@ namespace Umbraco.Cms.Core.Telemetry.Models
|
||||
/// </remarks>
|
||||
[DataMember(Name = "packages")]
|
||||
public IEnumerable<PackageTelemetry> Packages { get; set; }
|
||||
|
||||
[DataMember(Name = "detailed")]
|
||||
public IEnumerable<UsageInformation> Detailed { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Cms.Core.Configuration;
|
||||
using Umbraco.Cms.Core.Manifest;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Telemetry.Models;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
@@ -16,6 +18,8 @@ namespace Umbraco.Cms.Core.Telemetry
|
||||
private readonly IManifestParser _manifestParser;
|
||||
private readonly IUmbracoVersion _umbracoVersion;
|
||||
private readonly ISiteIdentifierService _siteIdentifierService;
|
||||
private readonly IUsageInformationService _usageInformationService;
|
||||
private readonly IMetricsConsentService _metricsConsentService;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TelemetryService"/> class.
|
||||
@@ -23,11 +27,15 @@ namespace Umbraco.Cms.Core.Telemetry
|
||||
public TelemetryService(
|
||||
IManifestParser manifestParser,
|
||||
IUmbracoVersion umbracoVersion,
|
||||
ISiteIdentifierService siteIdentifierService)
|
||||
ISiteIdentifierService siteIdentifierService,
|
||||
IUsageInformationService usageInformationService,
|
||||
IMetricsConsentService metricsConsentService)
|
||||
{
|
||||
_manifestParser = manifestParser;
|
||||
_umbracoVersion = umbracoVersion;
|
||||
_siteIdentifierService = siteIdentifierService;
|
||||
_usageInformationService = usageInformationService;
|
||||
_metricsConsentService = metricsConsentService;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -42,14 +50,30 @@ namespace Umbraco.Cms.Core.Telemetry
|
||||
telemetryReportData = new TelemetryReportData
|
||||
{
|
||||
Id = telemetryId,
|
||||
Version = _umbracoVersion.SemanticVersion.ToSemanticStringWithoutBuild(),
|
||||
Version = GetVersion(),
|
||||
Packages = GetPackageTelemetry(),
|
||||
Detailed = _usageInformationService.GetDetailed(),
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
private string GetVersion()
|
||||
{
|
||||
if (_metricsConsentService.GetConsentLevel() == TelemetryLevel.Minimal)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return _umbracoVersion.SemanticVersion.ToSemanticStringWithoutBuild();
|
||||
}
|
||||
|
||||
private IEnumerable<PackageTelemetry> GetPackageTelemetry()
|
||||
{
|
||||
if (_metricsConsentService.GetConsentLevel() == TelemetryLevel.Minimal)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
List<PackageTelemetry> packages = new();
|
||||
IEnumerable<PackageManifest> manifests = _manifestParser.GetManifests();
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ using Umbraco.Cms.Infrastructure.Runtime;
|
||||
using Umbraco.Cms.Infrastructure.Scoping;
|
||||
using Umbraco.Cms.Infrastructure.Search;
|
||||
using Umbraco.Cms.Infrastructure.Serialization;
|
||||
using Umbraco.Cms.Infrastructure.Services.Implement;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.DependencyInjection
|
||||
@@ -201,6 +202,7 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection
|
||||
|
||||
builder.Services.AddSingleton<PackageDataInstallation>();
|
||||
|
||||
builder.Services.AddTransient<INodeCountService, NodeCountService>();
|
||||
builder.AddInstaller();
|
||||
|
||||
// Services required to run background jobs (with out the handler)
|
||||
|
||||
@@ -47,6 +47,9 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection
|
||||
builder.Services.AddSingleton<PackageDataInstallation>();
|
||||
builder.Services.AddUnique<IPackageInstallation, PackageInstallation>();
|
||||
builder.Services.AddUnique<IHtmlMacroParameterParser, HtmlMacroParameterParser>();
|
||||
builder.Services.AddTransient<IExamineIndexCountService, ExamineIndexCountService>();
|
||||
builder.Services.AddUnique<IUserDataService, SystemInformationTelemetryProvider>();
|
||||
builder.Services.AddTransient<IUsageInformationService, UsageInformationService>();
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Umbraco.Cms.Infrastructure.Telemetry.Interfaces;
|
||||
using Umbraco.Cms.Infrastructure.Telemetry.Providers;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.DependencyInjection
|
||||
{
|
||||
public static class UmbracoBuilder_TelemetryProviders
|
||||
{
|
||||
public static IUmbracoBuilder AddTelemetryProviders(this IUmbracoBuilder builder)
|
||||
{
|
||||
builder.Services.AddTransient<IDetailedTelemetryProvider, ContentTelemetryProvider>();
|
||||
builder.Services.AddTransient<IDetailedTelemetryProvider, DomainTelemetryProvider>();
|
||||
builder.Services.AddTransient<IDetailedTelemetryProvider, ExamineTelemetryProvider>();
|
||||
builder.Services.AddTransient<IDetailedTelemetryProvider, LanguagesTelemetryProvider>();
|
||||
builder.Services.AddTransient<IDetailedTelemetryProvider, MacroTelemetryProvider>();
|
||||
builder.Services.AddTransient<IDetailedTelemetryProvider, MediaTelemetryProvider>();
|
||||
builder.Services.AddTransient<IDetailedTelemetryProvider, NodeCountTelemetryProvider>();
|
||||
builder.Services.AddTransient<IDetailedTelemetryProvider, PropertyEditorTelemetryProvider>();
|
||||
builder.Services.AddTransient<IDetailedTelemetryProvider, UserTelemetryProvider>();
|
||||
builder.Services.AddTransient<IDetailedTelemetryProvider, SystemInformationTelemetryProvider>();
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -859,7 +859,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install
|
||||
|
||||
if (_database.Exists<NodeDto>(1048))
|
||||
{
|
||||
_database.Insert(Cms.Core.Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1048, EditorAlias = Cms.Core.Constants.PropertyEditors.Aliases.MemberPicker, DbType = "Ntext" });
|
||||
_database.Insert(Cms.Core.Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1048, EditorAlias = Cms.Core.Constants.PropertyEditors.Aliases.MediaPicker, DbType = "Ntext" });
|
||||
}
|
||||
|
||||
if (_database.Exists<NodeDto>(1049))
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType) => PropertyCacheLevel.Snapshot;
|
||||
|
||||
public override bool? IsValue(object value, PropertyValueLevel level) => value?.ToString() != "[]";
|
||||
public override bool? IsValue(object value, PropertyValueLevel level) => value != null && value.ToString() != "[]";
|
||||
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview) => source?.ToString();
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters
|
||||
{
|
||||
var maxNumber = propertyType.DataType.ConfigurationAs<MultiUrlPickerConfiguration>().MaxNumber;
|
||||
|
||||
if (inter == null)
|
||||
if (string.IsNullOrWhiteSpace(inter?.ToString()))
|
||||
{
|
||||
return maxNumber == 1 ? null : Enumerable.Empty<Link>();
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ namespace Umbraco.Cms.Core.Security
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IUmbracoMapper _mapper;
|
||||
private readonly AppCaches _appCaches;
|
||||
private readonly ITwoFactorLoginService _twoFactorLoginService;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BackOfficeUserStore"/> class.
|
||||
@@ -48,7 +49,8 @@ namespace Umbraco.Cms.Core.Security
|
||||
IOptionsSnapshot<GlobalSettings> globalSettings,
|
||||
IUmbracoMapper mapper,
|
||||
BackOfficeErrorDescriber describer,
|
||||
AppCaches appCaches)
|
||||
AppCaches appCaches,
|
||||
ITwoFactorLoginService twoFactorLoginService)
|
||||
: base(describer)
|
||||
{
|
||||
_scopeProvider = scopeProvider;
|
||||
@@ -58,10 +60,71 @@ namespace Umbraco.Cms.Core.Security
|
||||
_globalSettings = globalSettings.Value;
|
||||
_mapper = mapper;
|
||||
_appCaches = appCaches;
|
||||
_twoFactorLoginService = twoFactorLoginService;
|
||||
_userService = userService;
|
||||
_externalLoginService = externalLoginService;
|
||||
}
|
||||
|
||||
[Obsolete("Use non obsolete ctor")]
|
||||
public BackOfficeUserStore(
|
||||
IScopeProvider scopeProvider,
|
||||
IUserService userService,
|
||||
IEntityService entityService,
|
||||
IExternalLoginWithKeyService externalLoginService,
|
||||
IOptions<GlobalSettings> globalSettings,
|
||||
IUmbracoMapper mapper,
|
||||
BackOfficeErrorDescriber describer,
|
||||
AppCaches appCaches)
|
||||
: this(
|
||||
scopeProvider,
|
||||
userService,
|
||||
entityService,
|
||||
externalLoginService,
|
||||
StaticServiceProvider.Instance.GetRequiredService<IOptionsSnapshot<GlobalSettings>>(),
|
||||
mapper,
|
||||
describer,
|
||||
appCaches,
|
||||
StaticServiceProvider.Instance.GetRequiredService<ITwoFactorLoginService>())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[Obsolete("Use non obsolete ctor")]
|
||||
public BackOfficeUserStore(
|
||||
IScopeProvider scopeProvider,
|
||||
IUserService userService,
|
||||
IEntityService entityService,
|
||||
IExternalLoginService externalLoginService,
|
||||
IOptions<GlobalSettings> globalSettings,
|
||||
IUmbracoMapper mapper,
|
||||
BackOfficeErrorDescriber describer,
|
||||
AppCaches appCaches)
|
||||
: this(
|
||||
scopeProvider,
|
||||
userService,
|
||||
entityService,
|
||||
StaticServiceProvider.Instance.GetRequiredService<IExternalLoginWithKeyService>(),
|
||||
StaticServiceProvider.Instance.GetRequiredService<IOptionsSnapshot<GlobalSettings>>(),
|
||||
mapper,
|
||||
describer,
|
||||
appCaches,
|
||||
StaticServiceProvider.Instance.GetRequiredService<ITwoFactorLoginService>())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<bool> GetTwoFactorEnabledAsync(BackOfficeIdentityUser user,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (!int.TryParse(user.Id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intUserId))
|
||||
{
|
||||
return await base.GetTwoFactorEnabledAsync(user, cancellationToken);
|
||||
}
|
||||
|
||||
return await _twoFactorLoginService.IsTwoFactorEnabledAsync(user.Key);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task<IdentityResult> CreateAsync(BackOfficeIdentityUser user, CancellationToken cancellationToken = default)
|
||||
{
|
||||
|
||||
@@ -597,7 +597,10 @@ namespace Umbraco.Cms.Core.Security
|
||||
|| (member.LastLoginDate != default && identityUser.LastLoginDateUtc.HasValue == false)
|
||||
|| (identityUser.LastLoginDateUtc.HasValue && member.LastLoginDate.ToUniversalTime() != identityUser.LastLoginDateUtc.Value))
|
||||
{
|
||||
changeType = MemberDataChangeType.LoginOnly;
|
||||
// If the LastLoginDate is default on the member we have to do a full save.
|
||||
// This is because the umbraco property data for the member doesn't exist yet in this case
|
||||
// meaning we can't just update that property data, but have to do a full save to create it
|
||||
changeType = member.LastLoginDate == default ? MemberDataChangeType.FullSave : MemberDataChangeType.LoginOnly;
|
||||
|
||||
// if the LastLoginDate is being set to MinValue, don't convert it ToLocalTime
|
||||
DateTime dt = identityUser.LastLoginDateUtc == DateTime.MinValue ? DateTime.MinValue : identityUser.LastLoginDateUtc.Value.ToLocalTime();
|
||||
|
||||
@@ -49,10 +49,10 @@ namespace Umbraco.Cms.Core.Security
|
||||
public override bool SupportsQueryableUsers => false; // It would be nice to support this but we don't need to currently and that would require IQueryable support for our user service/repository
|
||||
|
||||
/// <summary>
|
||||
/// Developers will need to override this to support custom 2 factor auth
|
||||
/// Both users and members supports 2FA
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public override bool SupportsUserTwoFactor => false;
|
||||
public override bool SupportsUserTwoFactor => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool SupportsUserPhoneNumber => false; // We haven't needed to support this yet, though might be necessary for 2FA
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using System.Linq;
|
||||
using Examine;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Services.Implement
|
||||
{
|
||||
public class ExamineIndexCountService : IExamineIndexCountService
|
||||
{
|
||||
private readonly IExamineManager _examineManager;
|
||||
|
||||
public ExamineIndexCountService(IExamineManager examineManager)
|
||||
{
|
||||
_examineManager = examineManager;
|
||||
}
|
||||
|
||||
public int GetCount()
|
||||
{
|
||||
return _examineManager.Indexes.Count();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Infrastructure.Persistence.Dtos;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Services.Implement
|
||||
{
|
||||
public class NodeCountService : INodeCountService
|
||||
{
|
||||
private readonly IScopeProvider _scopeProvider;
|
||||
|
||||
public NodeCountService(IScopeProvider scopeProvider) => _scopeProvider = scopeProvider;
|
||||
|
||||
public int GetNodeCount(Guid nodeType)
|
||||
{
|
||||
int count = 0;
|
||||
using (IScope scope = _scopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
var query = scope.Database.SqlContext.Sql()
|
||||
.SelectCount()
|
||||
.From<NodeDto>()
|
||||
.Where<NodeDto>(x => x.NodeObjectType == nodeType && x.Trashed == false);
|
||||
|
||||
count = scope.Database.ExecuteScalar<int>(query);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
public int GetMediaCount()
|
||||
{
|
||||
using (IScope scope = _scopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
var query = scope.Database.SqlContext.Sql()
|
||||
.SelectCount()
|
||||
.From<NodeDto>()
|
||||
.InnerJoin<ContentDto>()
|
||||
.On<NodeDto, ContentDto>(left => left.NodeId, right => right.NodeId)
|
||||
.InnerJoin<ContentTypeDto>()
|
||||
.On<ContentDto, ContentTypeDto>(left => left.ContentTypeId, right => right.NodeId)
|
||||
.Where<NodeDto>(x => x.NodeObjectType == Constants.ObjectTypes.Media)
|
||||
.Where<NodeDto>(x => !x.Trashed)
|
||||
.Where<ContentTypeDto>(x => x.Alias != Constants.Conventions.MediaTypes.Folder);
|
||||
|
||||
return scope.Database.ExecuteScalar<int>(query);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,22 +3,26 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Persistence.Repositories;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Web.Common.DependencyInjection;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class TwoFactorLoginService : ITwoFactorLoginService
|
||||
public class TwoFactorLoginService : ITwoFactorLoginService2
|
||||
{
|
||||
private readonly ITwoFactorLoginRepository _twoFactorLoginRepository;
|
||||
private readonly IScopeProvider _scopeProvider;
|
||||
private readonly IOptions<IdentityOptions> _identityOptions;
|
||||
private readonly IOptions<BackOfficeIdentityOptions> _backOfficeIdentityOptions;
|
||||
private readonly IDictionary<string, ITwoFactorProvider> _twoFactorSetupGenerators;
|
||||
private readonly ILogger<TwoFactorLoginService> _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TwoFactorLoginService"/> class.
|
||||
@@ -28,16 +32,34 @@ namespace Umbraco.Cms.Core.Services
|
||||
IScopeProvider scopeProvider,
|
||||
IEnumerable<ITwoFactorProvider> twoFactorSetupGenerators,
|
||||
IOptions<IdentityOptions> identityOptions,
|
||||
IOptions<BackOfficeIdentityOptions> backOfficeIdentityOptions
|
||||
)
|
||||
IOptions<BackOfficeIdentityOptions> backOfficeIdentityOptions,
|
||||
ILogger<TwoFactorLoginService> logger)
|
||||
{
|
||||
_twoFactorLoginRepository = twoFactorLoginRepository;
|
||||
_scopeProvider = scopeProvider;
|
||||
_identityOptions = identityOptions;
|
||||
_backOfficeIdentityOptions = backOfficeIdentityOptions;
|
||||
_logger = logger;
|
||||
_twoFactorSetupGenerators = twoFactorSetupGenerators.ToDictionary(x =>x.ProviderName);
|
||||
}
|
||||
|
||||
[Obsolete("Use ctor with all params - This will be removed in v11")]
|
||||
public TwoFactorLoginService(
|
||||
ITwoFactorLoginRepository twoFactorLoginRepository,
|
||||
IScopeProvider scopeProvider,
|
||||
IEnumerable<ITwoFactorProvider> twoFactorSetupGenerators,
|
||||
IOptions<IdentityOptions> identityOptions,
|
||||
IOptions<BackOfficeIdentityOptions> backOfficeIdentityOptions)
|
||||
: this(twoFactorLoginRepository,
|
||||
scopeProvider,
|
||||
twoFactorSetupGenerators,
|
||||
identityOptions,
|
||||
backOfficeIdentityOptions,
|
||||
StaticServiceProvider.Instance.GetRequiredService<ILogger<TwoFactorLoginService>>())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task DeleteUserLoginsAsync(Guid userOrMemberKey)
|
||||
{
|
||||
@@ -51,6 +73,56 @@ namespace Umbraco.Cms.Core.Services
|
||||
return await GetEnabledProviderNamesAsync(userOrMemberKey);
|
||||
}
|
||||
|
||||
public async Task<bool> DisableWithCodeAsync(string providerName, Guid userOrMemberKey, string code)
|
||||
{
|
||||
var secret = await GetSecretForUserAndProviderAsync(userOrMemberKey, providerName);
|
||||
|
||||
if (!_twoFactorSetupGenerators.TryGetValue(providerName, out ITwoFactorProvider generator))
|
||||
{
|
||||
throw new InvalidOperationException($"No ITwoFactorSetupGenerator found for provider: {providerName}");
|
||||
}
|
||||
|
||||
var isValid = generator.ValidateTwoFactorPIN(secret, code);
|
||||
|
||||
if (!isValid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return await DisableAsync(userOrMemberKey, providerName);
|
||||
}
|
||||
|
||||
public async Task<bool> ValidateAndSaveAsync(string providerName, Guid userOrMemberKey, string secret, string code)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
var isValid = ValidateTwoFactorSetup(providerName, secret, code);
|
||||
if (isValid == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var twoFactorLogin = new TwoFactorLogin()
|
||||
{
|
||||
Confirmed = true,
|
||||
Secret = secret,
|
||||
UserOrMemberKey = userOrMemberKey,
|
||||
ProviderName = providerName
|
||||
};
|
||||
|
||||
await SaveAsync(twoFactorLogin);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Could not log in with the provided one-time-password");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<string>> GetEnabledProviderNamesAsync(Guid userOrMemberKey)
|
||||
{
|
||||
using IScope scope = _scopeProvider.CreateScope(autoComplete: true);
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Telemetry.Interfaces
|
||||
{
|
||||
internal interface IDetailedTelemetryProvider
|
||||
{
|
||||
IEnumerable<UsageInformation> GetInformation();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Infrastructure.Telemetry.Interfaces;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Telemetry.Providers
|
||||
{
|
||||
public class ContentTelemetryProvider : IDetailedTelemetryProvider
|
||||
{
|
||||
private readonly IContentService _contentService;
|
||||
|
||||
public ContentTelemetryProvider(IContentService contentService) => _contentService = contentService;
|
||||
|
||||
public IEnumerable<UsageInformation> GetInformation()
|
||||
{
|
||||
var rootNodes = _contentService.GetRootContent();
|
||||
int nodes = rootNodes.Count();
|
||||
yield return new UsageInformation(Constants.Telemetry.RootCount, nodes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Infrastructure.Telemetry.Interfaces;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Telemetry.Providers
|
||||
{
|
||||
public class DomainTelemetryProvider : IDetailedTelemetryProvider
|
||||
{
|
||||
private readonly IDomainService _domainService;
|
||||
|
||||
public DomainTelemetryProvider(IDomainService domainService) => _domainService = domainService;
|
||||
|
||||
public IEnumerable<UsageInformation> GetInformation()
|
||||
{
|
||||
var domains = _domainService.GetAll(true).Count();
|
||||
yield return new UsageInformation(Constants.Telemetry.DomainCount, domains);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Infrastructure.Telemetry.Interfaces;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Telemetry.Providers
|
||||
{
|
||||
public class ExamineTelemetryProvider : IDetailedTelemetryProvider
|
||||
{
|
||||
private readonly IExamineIndexCountService _examineIndexCountService;
|
||||
|
||||
public ExamineTelemetryProvider(IExamineIndexCountService examineIndexCountService) => _examineIndexCountService = examineIndexCountService;
|
||||
|
||||
public IEnumerable<UsageInformation> GetInformation()
|
||||
{
|
||||
var indexes = _examineIndexCountService.GetCount();
|
||||
yield return new UsageInformation(Constants.Telemetry.ExamineIndexCount, indexes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Infrastructure.Telemetry.Interfaces;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Telemetry.Providers
|
||||
{
|
||||
public class LanguagesTelemetryProvider : IDetailedTelemetryProvider
|
||||
{
|
||||
private readonly ILocalizationService _localizationService;
|
||||
|
||||
public LanguagesTelemetryProvider(ILocalizationService localizationService)
|
||||
{
|
||||
_localizationService = localizationService;
|
||||
}
|
||||
|
||||
public IEnumerable<UsageInformation> GetInformation()
|
||||
{
|
||||
int languages = _localizationService.GetAllLanguages().Count();
|
||||
yield return new UsageInformation(Constants.Telemetry.LanguageCount, languages);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Infrastructure.Telemetry.Interfaces;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Telemetry.Providers
|
||||
{
|
||||
public class MacroTelemetryProvider : IDetailedTelemetryProvider
|
||||
{
|
||||
private readonly IMacroService _macroService;
|
||||
|
||||
public MacroTelemetryProvider(IMacroService macroService)
|
||||
{
|
||||
_macroService = macroService;
|
||||
}
|
||||
|
||||
public IEnumerable<UsageInformation> GetInformation()
|
||||
{
|
||||
var macros = _macroService.GetAll().Count();
|
||||
yield return new UsageInformation(Constants.Telemetry.MacroCount, macros);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Infrastructure.Telemetry.Interfaces;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Telemetry.Providers
|
||||
{
|
||||
public class MediaTelemetryProvider : IDetailedTelemetryProvider
|
||||
{
|
||||
private readonly INodeCountService _nodeCountService;
|
||||
|
||||
public MediaTelemetryProvider(INodeCountService nodeCountService) => _nodeCountService = nodeCountService;
|
||||
|
||||
public IEnumerable<UsageInformation> GetInformation()
|
||||
{
|
||||
yield return new UsageInformation(Constants.Telemetry.MediaCount, _nodeCountService.GetMediaCount());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Infrastructure.Telemetry.Interfaces;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Telemetry.Providers
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class NodeCountTelemetryProvider : IDetailedTelemetryProvider
|
||||
{
|
||||
private readonly INodeCountService _nodeCountService;
|
||||
|
||||
public NodeCountTelemetryProvider(INodeCountService nodeCountService) => _nodeCountService = nodeCountService;
|
||||
|
||||
public IEnumerable<UsageInformation> GetInformation()
|
||||
{
|
||||
yield return new UsageInformation(Constants.Telemetry.MemberCount, _nodeCountService.GetNodeCount(Constants.ObjectTypes.Member));
|
||||
yield return new UsageInformation(Constants.Telemetry.TemplateCount, _nodeCountService.GetNodeCount(Constants.ObjectTypes.Template));
|
||||
yield return new UsageInformation(Constants.Telemetry.ContentCount, _nodeCountService.GetNodeCount(Constants.ObjectTypes.Document));
|
||||
yield return new UsageInformation(Constants.Telemetry.DocumentTypeCount, _nodeCountService.GetNodeCount(Constants.ObjectTypes.DocumentType));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Infrastructure.Telemetry.Interfaces;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Telemetry.Providers
|
||||
{
|
||||
public class PropertyEditorTelemetryProvider : IDetailedTelemetryProvider
|
||||
{
|
||||
private readonly IContentTypeService _contentTypeService;
|
||||
|
||||
public PropertyEditorTelemetryProvider(IContentTypeService contentTypeService) => _contentTypeService = contentTypeService;
|
||||
|
||||
public IEnumerable<UsageInformation> GetInformation()
|
||||
{
|
||||
var contentTypes = _contentTypeService.GetAll();
|
||||
var propertyTypes = new HashSet<string>();
|
||||
foreach (IContentType contentType in contentTypes)
|
||||
{
|
||||
propertyTypes.UnionWith(contentType.PropertyTypes.Select(x => x.PropertyEditorAlias));
|
||||
}
|
||||
|
||||
yield return new UsageInformation(Constants.Telemetry.Properties, propertyTypes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Configuration;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Infrastructure.Persistence;
|
||||
using Umbraco.Cms.Infrastructure.Telemetry.Interfaces;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Telemetry.Providers
|
||||
{
|
||||
internal class SystemInformationTelemetryProvider : IDetailedTelemetryProvider, IUserDataService
|
||||
{
|
||||
private readonly IUmbracoVersion _version;
|
||||
private readonly ILocalizationService _localizationService;
|
||||
private readonly IHostEnvironment _hostEnvironment;
|
||||
private readonly Lazy<IUmbracoDatabase> _database;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly HostingSettings _hostingSettings;
|
||||
private readonly ModelsBuilderSettings _modelsBuilderSettings;
|
||||
|
||||
public SystemInformationTelemetryProvider(
|
||||
IUmbracoVersion version,
|
||||
ILocalizationService localizationService,
|
||||
IOptions<ModelsBuilderSettings> modelsBuilderSettings,
|
||||
IOptions<HostingSettings> hostingSettings,
|
||||
IOptions<GlobalSettings> globalSettings,
|
||||
IHostEnvironment hostEnvironment,
|
||||
Lazy<IUmbracoDatabase> database)
|
||||
{
|
||||
_version = version;
|
||||
_localizationService = localizationService;
|
||||
_hostEnvironment = hostEnvironment;
|
||||
_database = database;
|
||||
_globalSettings = globalSettings.Value;
|
||||
_hostingSettings = hostingSettings.Value;
|
||||
_modelsBuilderSettings = modelsBuilderSettings.Value;
|
||||
}
|
||||
|
||||
private string CurrentWebServer => IsRunningInProcessIIS() ? "IIS" : "Kestrel";
|
||||
|
||||
private string ServerFramework => RuntimeInformation.FrameworkDescription;
|
||||
|
||||
private string ModelsBuilderMode => _modelsBuilderSettings.ModelsMode.ToString();
|
||||
|
||||
private string CurrentCulture => Thread.CurrentThread.CurrentCulture.ToString();
|
||||
|
||||
private bool IsDebug => _hostingSettings.Debug;
|
||||
|
||||
private bool UmbracoPathCustomized => _globalSettings.UmbracoPath != Constants.System.DefaultUmbracoPath;
|
||||
|
||||
private string AspEnvironment => _hostEnvironment.EnvironmentName;
|
||||
|
||||
private string ServerOs => RuntimeInformation.OSDescription;
|
||||
|
||||
private string DatabaseProvider => _database.Value.DatabaseType.GetProviderName();
|
||||
|
||||
public IEnumerable<UsageInformation> GetInformation() =>
|
||||
new UsageInformation[]
|
||||
{
|
||||
new(Constants.Telemetry.ServerOs, ServerOs),
|
||||
new(Constants.Telemetry.ServerFramework, ServerFramework),
|
||||
new(Constants.Telemetry.OsLanguage, CurrentCulture),
|
||||
new(Constants.Telemetry.WebServer, CurrentWebServer),
|
||||
new(Constants.Telemetry.ModelsBuilderMode, ModelsBuilderMode),
|
||||
new(Constants.Telemetry.CustomUmbracoPath, UmbracoPathCustomized),
|
||||
new(Constants.Telemetry.AspEnvironment, AspEnvironment),
|
||||
new(Constants.Telemetry.IsDebug, IsDebug),
|
||||
new(Constants.Telemetry.DatabaseProvider, DatabaseProvider),
|
||||
};
|
||||
|
||||
public IEnumerable<UserData> GetUserData() =>
|
||||
new UserData[]
|
||||
{
|
||||
new("Server OS", ServerOs),
|
||||
new("Server Framework", ServerFramework),
|
||||
new("Default Language", _localizationService.GetDefaultLanguageIsoCode()),
|
||||
new("Umbraco Version", _version.SemanticVersion.ToSemanticStringWithoutBuild()),
|
||||
new("Current Culture", CurrentCulture),
|
||||
new("Current UI Culture", Thread.CurrentThread.CurrentUICulture.ToString()),
|
||||
new("Current Webserver", CurrentWebServer),
|
||||
new("Models Builder Mode", ModelsBuilderMode),
|
||||
new("Debug Mode", IsDebug.ToString()),
|
||||
new("Database Provider", DatabaseProvider),
|
||||
};
|
||||
|
||||
private bool IsRunningInProcessIIS()
|
||||
{
|
||||
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string processName = Path.GetFileNameWithoutExtension(Process.GetCurrentProcess().ProcessName);
|
||||
return (processName.Contains("w3wp") || processName.Contains("iisexpress"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Infrastructure.Telemetry.Interfaces;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Telemetry.Providers
|
||||
{
|
||||
public class UserTelemetryProvider : IDetailedTelemetryProvider
|
||||
{
|
||||
private readonly IUserService _userService;
|
||||
|
||||
public UserTelemetryProvider(IUserService userService)
|
||||
{
|
||||
_userService = userService;
|
||||
}
|
||||
|
||||
public IEnumerable<UsageInformation> GetInformation()
|
||||
{
|
||||
_userService.GetAll(1, 1, out long total);
|
||||
int userGroups = _userService.GetAllUserGroups().Count();
|
||||
|
||||
yield return new UsageInformation(Constants.Telemetry.UserCount, total);
|
||||
yield return new UsageInformation(Constants.Telemetry.UserGroupCount, userGroups);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Infrastructure.Telemetry.Interfaces;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services
|
||||
{
|
||||
internal class UsageInformationService : IUsageInformationService
|
||||
{
|
||||
private readonly IMetricsConsentService _metricsConsentService;
|
||||
private readonly IEnumerable<IDetailedTelemetryProvider> _providers;
|
||||
|
||||
public UsageInformationService(
|
||||
IMetricsConsentService metricsConsentService,
|
||||
IEnumerable<IDetailedTelemetryProvider> providers)
|
||||
{
|
||||
_metricsConsentService = metricsConsentService;
|
||||
_providers = providers;
|
||||
}
|
||||
|
||||
public IEnumerable<UsageInformation> GetDetailed()
|
||||
{
|
||||
if (_metricsConsentService.GetConsentLevel() != TelemetryLevel.Detailed)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var detailedUsageInformation = new List<UsageInformation>();
|
||||
foreach (IDetailedTelemetryProvider provider in _providers)
|
||||
{
|
||||
detailedUsageInformation.AddRange(provider.GetInformation());
|
||||
}
|
||||
|
||||
return detailedUsageInformation;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Cms.Core.PublishedCache;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
using Umbraco.Cms.Infrastructure.PublishedCache.Snap;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.PublishedCache
|
||||
{
|
||||
@@ -443,10 +444,18 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
|
||||
refreshedIdsA.Contains(x.ContentTypeId) &&
|
||||
BuildKit(x, out _)))
|
||||
{
|
||||
// replacing the node: must preserve the parents
|
||||
// replacing the node: must preserve the relations
|
||||
var node = GetHead(_contentNodes, kit.Node.Id)?.Value;
|
||||
if (node != null)
|
||||
{
|
||||
// Preserve children
|
||||
kit.Node.FirstChildContentId = node.FirstChildContentId;
|
||||
kit.Node.LastChildContentId = node.LastChildContentId;
|
||||
|
||||
// Also preserve siblings
|
||||
kit.Node.NextSiblingContentId = node.NextSiblingContentId;
|
||||
kit.Node.PreviousSiblingContentId = node.PreviousSiblingContentId;
|
||||
}
|
||||
|
||||
SetValueLocked(_contentNodes, kit.Node.Id, kit.Node);
|
||||
|
||||
@@ -688,7 +697,36 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Thrown if this method is not called within a write lock
|
||||
/// </exception>
|
||||
[Obsolete("Use the overload that takes a 'kitGroupSize' parameter instead")]
|
||||
public bool SetAllFastSortedLocked(IEnumerable<ContentNodeKit> kits, bool fromDb)
|
||||
{
|
||||
return SetAllFastSortedLocked(kits, 1, fromDb);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds all kits on startup using a fast forward only cursor
|
||||
/// </summary>
|
||||
/// <param name="kits">
|
||||
/// All kits sorted by Level + Parent Id + Sort order
|
||||
/// </param>
|
||||
/// <param name="kitGroupSize"></param>
|
||||
/// <param name="fromDb">True if the data is coming from the database (not the local cache db)</param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This requires that the collection is sorted by Level + ParentId + Sort Order.
|
||||
/// This should be used only on a site startup as the first generations.
|
||||
/// This CANNOT be used after startup since it bypasses all checks for Generations.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This methods MUST be called from within a write lock, normally wrapped within GetScopedWriteLock
|
||||
/// otherwise an exception will occur.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Thrown if this method is not called within a write lock
|
||||
/// </exception>
|
||||
public bool SetAllFastSortedLocked(IEnumerable<ContentNodeKit> kits, int kitGroupSize, bool fromDb)
|
||||
{
|
||||
EnsureLocked();
|
||||
|
||||
@@ -706,7 +744,19 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
|
||||
ContentNode previousNode = null;
|
||||
ContentNode parent = null;
|
||||
|
||||
foreach (var kit in kits)
|
||||
// By using InGroupsOf() here we are forcing the database query result extraction to retrieve items in batches,
|
||||
// reducing the possibility of a database timeout (ThreadAbortException) on large datasets.
|
||||
// This in turn reduces the possibility that the NuCache file will remain locked, because an exception
|
||||
// here results in the calling method to not release the lock.
|
||||
|
||||
// However the larger the batck size, the more content loaded into memory. So by default, this is set to 1 and can be increased by setting
|
||||
// the configuration setting Umbraco:CMS:NuCache:KitPageSize to a higher value.
|
||||
|
||||
// If we are not loading from the database, then we can ignore this restriction.
|
||||
|
||||
foreach (var kitGroup in kits.InGroupsOf(!fromDb || kitGroupSize < 1 ? 1 : kitGroupSize))
|
||||
{
|
||||
foreach (var kit in kitGroup)
|
||||
{
|
||||
if (!BuildKit(kit, out var parentLink))
|
||||
{
|
||||
@@ -755,6 +805,7 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
|
||||
|
||||
_contentKeyToIdMap[kit.Node.Uid] = kit.Node.Id;
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
@@ -771,7 +822,27 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Thrown if this method is not called within a write lock
|
||||
/// </exception>
|
||||
[Obsolete("Use the overload that takes the 'kitGroupSize' and 'fromDb' parameters instead")]
|
||||
public bool SetAllLocked(IEnumerable<ContentNodeKit> kits)
|
||||
{
|
||||
return SetAllLocked(kits, 1, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set all data for a collection of <see cref="ContentNodeKit"/>
|
||||
/// </summary>
|
||||
/// <param name="kits"></param>
|
||||
/// <param name="kitGroupSize"></param>
|
||||
/// <param name="fromDb">True if the data is coming from the database (not the local cache db)</param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This methods MUST be called from within a write lock, normally wrapped within GetScopedWriteLock
|
||||
/// otherwise an exception will occur.
|
||||
/// </remarks>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Thrown if this method is not called within a write lock
|
||||
/// </exception>
|
||||
public bool SetAllLocked(IEnumerable<ContentNodeKit> kits, int kitGroupSize, bool fromDb)
|
||||
{
|
||||
EnsureLocked();
|
||||
|
||||
@@ -784,7 +855,18 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
|
||||
//ClearLocked(_contentTypesById);
|
||||
//ClearLocked(_contentTypesByAlias);
|
||||
|
||||
foreach (var kit in kits)
|
||||
// By using InGroupsOf() here we are forcing the database query result extraction to retrieve items in batches,
|
||||
// reducing the possibility of a database timeout (ThreadAbortException) on large datasets.
|
||||
// This in turn reduces the possibility that the NuCache file will remain locked, because an exception
|
||||
// here results in the calling method to not release the lock.
|
||||
|
||||
// However the larger the batck size, the more content loaded into memory. So by default, this is set to 1 and can be increased by setting
|
||||
// the configuration setting Umbraco:CMS:NuCache:KitPageSize to a higher value.
|
||||
|
||||
// If we are not loading from the database, then we can ignore this restriction.
|
||||
foreach (var kitGroup in kits.InGroupsOf(!fromDb || kitGroupSize < 1 ? 1 : kitGroupSize))
|
||||
{
|
||||
foreach (var kit in kitGroup)
|
||||
{
|
||||
if (!BuildKit(kit, out var parent))
|
||||
{
|
||||
@@ -804,6 +886,7 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
|
||||
|
||||
_contentKeyToIdMap[kit.Node.Uid] = kit.Node.Id;
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
@@ -337,8 +337,19 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
|
||||
_localContentDb?.Clear();
|
||||
|
||||
// IMPORTANT GetAllContentSources sorts kits by level + parentId + sortOrder
|
||||
|
||||
try
|
||||
{
|
||||
var kits = _publishedContentService.GetAllContentSources();
|
||||
return onStartup ? _contentStore.SetAllFastSortedLocked(kits, true) : _contentStore.SetAllLocked(kits);
|
||||
return onStartup ? _contentStore.SetAllFastSortedLocked(kits, _config.KitBatchSize, true) : _contentStore.SetAllLocked(kits, _config.KitBatchSize, true);
|
||||
}
|
||||
catch (ThreadAbortException tae)
|
||||
{
|
||||
// Caught a ThreadAbortException, most likely from a database timeout.
|
||||
// If we don't catch it here, the whole local cache can remain locked causing widespread panic (see above comment).
|
||||
_logger.LogWarning(tae, tae.Message);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,8 +396,20 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
|
||||
|
||||
_logger.LogDebug("Loading media from database...");
|
||||
// IMPORTANT GetAllMediaSources sorts kits by level + parentId + sortOrder
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
var kits = _publishedContentService.GetAllMediaSources();
|
||||
return onStartup ? _mediaStore.SetAllFastSortedLocked(kits, true) : _mediaStore.SetAllLocked(kits);
|
||||
return onStartup ? _mediaStore.SetAllFastSortedLocked(kits, _config.KitBatchSize, true) : _mediaStore.SetAllLocked(kits, _config.KitBatchSize, true);
|
||||
}
|
||||
catch (ThreadAbortException tae)
|
||||
{
|
||||
// Caught a ThreadAbortException, most likely from a database timeout.
|
||||
// If we don't catch it here, the whole local cache can remain locked causing widespread panic (see above comment).
|
||||
_logger.LogWarning(tae, tae.Message);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,7 +457,7 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
|
||||
return false;
|
||||
}
|
||||
|
||||
return onStartup ? store.SetAllFastSortedLocked(kits, false) : store.SetAllLocked(kits);
|
||||
return onStartup ? store.SetAllFastSortedLocked(kits, _config.KitBatchSize, false) : store.SetAllLocked(kits, _config.KitBatchSize, false);
|
||||
}
|
||||
|
||||
private void LockAndLoadDomains()
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
|
||||
namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
public class AnalyticsController : UmbracoAuthorizedJsonController
|
||||
{
|
||||
private readonly IMetricsConsentService _metricsConsentService;
|
||||
public AnalyticsController(IMetricsConsentService metricsConsentService)
|
||||
{
|
||||
_metricsConsentService = metricsConsentService;
|
||||
}
|
||||
|
||||
public TelemetryLevel GetConsentLevel()
|
||||
{
|
||||
return _metricsConsentService.GetConsentLevel();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public IActionResult SetConsentLevel([FromBody]TelemetryResource telemetryResource)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return BadRequest();
|
||||
}
|
||||
|
||||
_metricsConsentService.SetConsentLevel(telemetryResource.TelemetryLevel);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
public IEnumerable<TelemetryLevel> GetAllLevels() => new[] { TelemetryLevel.Minimal, TelemetryLevel.Basic, TelemetryLevel.Detailed };
|
||||
}
|
||||
}
|
||||
@@ -74,6 +74,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
private readonly IBackOfficeExternalLoginProviders _externalAuthenticationOptions;
|
||||
private readonly IBackOfficeTwoFactorOptions _backOfficeTwoFactorOptions;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly ITwoFactorLoginService _twoFactorLoginService;
|
||||
private readonly WebRoutingSettings _webRoutingSettings;
|
||||
|
||||
// TODO: We need to review all _userManager.Raise calls since many/most should be on the usermanager or signinmanager, very few should be here
|
||||
@@ -97,7 +98,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
IBackOfficeExternalLoginProviders externalAuthenticationOptions,
|
||||
IBackOfficeTwoFactorOptions backOfficeTwoFactorOptions,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
IOptions<WebRoutingSettings> webRoutingSettings)
|
||||
IOptions<WebRoutingSettings> webRoutingSettings,
|
||||
ITwoFactorLoginService twoFactorLoginService)
|
||||
{
|
||||
_backofficeSecurityAccessor = backofficeSecurityAccessor;
|
||||
_userManager = backOfficeUserManager;
|
||||
@@ -118,6 +120,95 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
_backOfficeTwoFactorOptions = backOfficeTwoFactorOptions;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_webRoutingSettings = webRoutingSettings.Value;
|
||||
_twoFactorLoginService = twoFactorLoginService;
|
||||
}
|
||||
|
||||
[Obsolete("Use constructor that takes all params, scheduled for removal in V11")]
|
||||
public AuthenticationController(
|
||||
IBackOfficeSecurityAccessor backofficeSecurityAccessor,
|
||||
IBackOfficeUserManager backOfficeUserManager,
|
||||
IBackOfficeSignInManager signInManager,
|
||||
IUserService userService,
|
||||
ILocalizedTextService textService,
|
||||
IUmbracoMapper umbracoMapper,
|
||||
IOptions<GlobalSettings> globalSettings,
|
||||
IOptions<SecuritySettings> securitySettings,
|
||||
ILogger<AuthenticationController> logger,
|
||||
IIpResolver ipResolver,
|
||||
IOptions<UserPasswordConfigurationSettings> passwordConfiguration,
|
||||
IEmailSender emailSender,
|
||||
ISmsSender smsSender,
|
||||
IHostingEnvironment hostingEnvironment,
|
||||
LinkGenerator linkGenerator,
|
||||
IBackOfficeExternalLoginProviders externalAuthenticationOptions,
|
||||
IBackOfficeTwoFactorOptions backOfficeTwoFactorOptions,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
IOptions<WebRoutingSettings> webRoutingSettings)
|
||||
: this(
|
||||
backofficeSecurityAccessor,
|
||||
backOfficeUserManager,
|
||||
signInManager,
|
||||
userService,
|
||||
textService,
|
||||
umbracoMapper,
|
||||
globalSettings,
|
||||
securitySettings,
|
||||
logger,
|
||||
ipResolver,
|
||||
passwordConfiguration,
|
||||
emailSender,
|
||||
smsSender,
|
||||
hostingEnvironment,
|
||||
linkGenerator,
|
||||
externalAuthenticationOptions,
|
||||
backOfficeTwoFactorOptions,
|
||||
StaticServiceProvider.Instance.GetRequiredService<IHttpContextAccessor>(),
|
||||
StaticServiceProvider.Instance.GetRequiredService<IOptions<WebRoutingSettings>>(),
|
||||
StaticServiceProvider.Instance.GetRequiredService<ITwoFactorLoginService>())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[Obsolete("Use constructor that takes all params, scheduled for removal in V11")]
|
||||
public AuthenticationController(
|
||||
IBackOfficeSecurityAccessor backofficeSecurityAccessor,
|
||||
IBackOfficeUserManager backOfficeUserManager,
|
||||
IBackOfficeSignInManager signInManager,
|
||||
IUserService userService,
|
||||
ILocalizedTextService textService,
|
||||
IUmbracoMapper umbracoMapper,
|
||||
IOptions<GlobalSettings> globalSettings,
|
||||
IOptions<SecuritySettings> securitySettings,
|
||||
ILogger<AuthenticationController> logger,
|
||||
IIpResolver ipResolver,
|
||||
IOptions<UserPasswordConfigurationSettings> passwordConfiguration,
|
||||
IEmailSender emailSender,
|
||||
ISmsSender smsSender,
|
||||
IHostingEnvironment hostingEnvironment,
|
||||
LinkGenerator linkGenerator,
|
||||
IBackOfficeExternalLoginProviders externalAuthenticationOptions,
|
||||
IBackOfficeTwoFactorOptions backOfficeTwoFactorOptions)
|
||||
: this(
|
||||
backofficeSecurityAccessor,
|
||||
backOfficeUserManager,
|
||||
signInManager,
|
||||
userService,
|
||||
textService,
|
||||
umbracoMapper,
|
||||
globalSettings,
|
||||
securitySettings,
|
||||
logger,
|
||||
ipResolver,
|
||||
passwordConfiguration,
|
||||
emailSender,
|
||||
smsSender,
|
||||
hostingEnvironment,
|
||||
linkGenerator,
|
||||
externalAuthenticationOptions,
|
||||
backOfficeTwoFactorOptions,
|
||||
StaticServiceProvider.Instance.GetRequiredService<IHttpContextAccessor>(),
|
||||
StaticServiceProvider.Instance.GetRequiredService<IOptions<WebRoutingSettings>>())
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -427,7 +518,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var userFactors = await _userManager.GetValidTwoFactorProvidersAsync(user);
|
||||
var userFactors = await _twoFactorLoginService.GetEnabledTwoFactorProviderNamesAsync(user.Key);
|
||||
|
||||
return new ObjectResult(userFactors);
|
||||
}
|
||||
|
||||
|
||||
@@ -241,6 +241,10 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
"authenticationApiBaseUrl", _linkGenerator.GetUmbracoApiServiceBaseUrl<AuthenticationController>(
|
||||
controller => controller.PostLogin(null))
|
||||
},
|
||||
{
|
||||
"twoFactorLoginApiBaseUrl", _linkGenerator.GetUmbracoApiServiceBaseUrl<TwoFactorLoginController>(
|
||||
controller => controller.SetupInfo(null))
|
||||
},
|
||||
{
|
||||
"currentUserApiBaseUrl", _linkGenerator.GetUmbracoApiServiceBaseUrl<CurrentUserController>(
|
||||
controller => controller.PostChangePassword(null))
|
||||
@@ -387,7 +391,11 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
"trackedReferencesApiBaseUrl", _linkGenerator.GetUmbracoApiServiceBaseUrl<TrackedReferencesController>(
|
||||
controller => controller.GetPagedReferences(0, 1, 1, false))
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyticsApiBaseUrl", _linkGenerator.GetUmbracoApiServiceBaseUrl<AnalyticsController>(
|
||||
controller => controller.GetConsentLevel())
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -22,6 +22,7 @@ using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Umbraco.Cms.Infrastructure.Packaging;
|
||||
using Umbraco.Cms.Web.BackOffice.Filters;
|
||||
using Umbraco.Cms.Web.Common.ActionsResults;
|
||||
using Umbraco.Cms.Web.Common.Attributes;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
@@ -452,6 +453,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
/// </summary>
|
||||
/// <param name="contentId"></param>
|
||||
[Authorize(Policy = AuthorizationPolicies.TreeAccessDocumentsOrDocumentTypes)]
|
||||
[OutgoingEditorModelEvent]
|
||||
public IEnumerable<ContentTypeBasic> GetAllowedChildren(int contentId)
|
||||
{
|
||||
if (contentId == Constants.System.RecycleBinContent)
|
||||
|
||||
@@ -3,6 +3,8 @@ using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Mime;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -191,6 +193,39 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
return _umbracoMapper.Map<IDictionaryItem, DictionaryDisplay>(dictionary);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the structure for dictionary items
|
||||
/// </summary>
|
||||
/// <param name="move"></param>
|
||||
/// <returns></returns>
|
||||
public IActionResult PostMove(MoveOrCopy move)
|
||||
{
|
||||
var dictionaryItem = _localizationService.GetDictionaryItemById(move.Id);
|
||||
if (dictionaryItem == null)
|
||||
return ValidationProblem(_localizedTextService.Localize("dictionary", "itemDoesNotExists"));
|
||||
|
||||
var parent = _localizationService.GetDictionaryItemById(move.ParentId);
|
||||
if (parent == null)
|
||||
{
|
||||
if (move.ParentId == Constants.System.Root)
|
||||
dictionaryItem.ParentId = null;
|
||||
else
|
||||
return ValidationProblem(_localizedTextService.Localize("dictionary", "parentDoesNotExists"));
|
||||
}
|
||||
else
|
||||
{
|
||||
dictionaryItem.ParentId = parent.Key;
|
||||
if (dictionaryItem.Key == parent.ParentId)
|
||||
return ValidationProblem(_localizedTextService.Localize("moveOrCopy", "notAllowedByPath"));
|
||||
}
|
||||
|
||||
_localizationService.Save(dictionaryItem);
|
||||
|
||||
var model = _umbracoMapper.Map<IDictionaryItem, DictionaryDisplay>(dictionaryItem);
|
||||
|
||||
return Content(model.Path, MediaTypeNames.Text.Plain, Encoding.UTF8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves a dictionary item
|
||||
/// </summary>
|
||||
|
||||
@@ -12,6 +12,7 @@ using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Umbraco.Cms.Web.BackOffice.Filters;
|
||||
using Umbraco.Cms.Web.Common.ActionsResults;
|
||||
using Umbraco.Cms.Web.Common.Attributes;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
@@ -339,6 +340,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
/// </summary>
|
||||
/// <param name="contentId"></param>
|
||||
[Authorize(Policy = AuthorizationPolicies.TreeAccessMediaOrMediaTypes)]
|
||||
[OutgoingEditorModelEvent]
|
||||
public IEnumerable<ContentTypeBasic> GetAllowedChildren(int contentId)
|
||||
{
|
||||
if (contentId == Constants.System.RecycleBinContent)
|
||||
|
||||
@@ -252,5 +252,19 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
|
||||
return display;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy the member type
|
||||
/// </summary>
|
||||
/// <param name="copy"></param>
|
||||
/// <returns></returns>
|
||||
[Authorize(Policy = AuthorizationPolicies.TreeAccessMemberTypes)]
|
||||
public IActionResult PostCopy(MoveOrCopy copy)
|
||||
{
|
||||
return PerformCopy(
|
||||
copy,
|
||||
i => _memberTypeService.Get(i),
|
||||
(type, i) => _memberTypeService.Copy(type, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Web.BackOffice.Security;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
|
||||
namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{
|
||||
public class TwoFactorLoginController : UmbracoAuthorizedJsonController
|
||||
{
|
||||
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
|
||||
private readonly ILogger<TwoFactorLoginController> _logger;
|
||||
private readonly ITwoFactorLoginService2 _twoFactorLoginService;
|
||||
private readonly IBackOfficeSignInManager _backOfficeSignInManager;
|
||||
private readonly IBackOfficeUserManager _backOfficeUserManager;
|
||||
private readonly IOptionsSnapshot<TwoFactorLoginViewOptions> _twoFactorLoginViewOptions;
|
||||
|
||||
public TwoFactorLoginController(
|
||||
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
|
||||
ILogger<TwoFactorLoginController> logger,
|
||||
ITwoFactorLoginService twoFactorLoginService,
|
||||
IBackOfficeSignInManager backOfficeSignInManager,
|
||||
IBackOfficeUserManager backOfficeUserManager,
|
||||
IOptionsSnapshot<TwoFactorLoginViewOptions> twoFactorLoginViewOptions)
|
||||
{
|
||||
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
|
||||
_logger = logger;
|
||||
|
||||
if (twoFactorLoginService is not ITwoFactorLoginService2 twoFactorLoginService2)
|
||||
{
|
||||
throw new ArgumentException("twoFactorLoginService needs to implement ITwoFactorLoginService2 until the interfaces are merged", nameof(twoFactorLoginService));
|
||||
}
|
||||
_twoFactorLoginService = twoFactorLoginService2;
|
||||
_backOfficeSignInManager = backOfficeSignInManager;
|
||||
_backOfficeUserManager = backOfficeUserManager;
|
||||
_twoFactorLoginViewOptions = twoFactorLoginViewOptions;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to retrieve the 2FA providers for code submission
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[AllowAnonymous]
|
||||
public async Task<ActionResult<IEnumerable<string>>> GetEnabled2FAProvidersForCurrentUser()
|
||||
{
|
||||
var user = await _backOfficeSignInManager.GetTwoFactorAuthenticationUserAsync();
|
||||
if (user == null)
|
||||
{
|
||||
_logger.LogWarning("No verified user found, returning 404");
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var userFactors = await _backOfficeUserManager.GetValidTwoFactorProvidersAsync(user);
|
||||
return new ObjectResult(userFactors);
|
||||
}
|
||||
|
||||
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<IEnumerable<UserTwoFactorProviderModel>>> Get2FAProvidersForUser(int userId)
|
||||
{
|
||||
var user = await _backOfficeUserManager.FindByIdAsync(userId.ToString());
|
||||
|
||||
var enabledProviderNameHashSet = new HashSet<string>(await _twoFactorLoginService.GetEnabledTwoFactorProviderNamesAsync(user.Key));
|
||||
|
||||
var providerNames = await _backOfficeUserManager.GetValidTwoFactorProvidersAsync(user);
|
||||
|
||||
return providerNames.Select(providerName =>
|
||||
new UserTwoFactorProviderModel(providerName, enabledProviderNameHashSet.Contains(providerName))).ToArray();
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<object>> SetupInfo(string providerName)
|
||||
{
|
||||
var user = _backOfficeSecurityAccessor?.BackOfficeSecurity.CurrentUser;
|
||||
|
||||
var setupInfo = await _twoFactorLoginService.GetSetupInfoAsync(user.Key, providerName);
|
||||
|
||||
return setupInfo;
|
||||
}
|
||||
|
||||
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<bool>> ValidateAndSave(string providerName, string secret, string code)
|
||||
{
|
||||
var user = _backOfficeSecurityAccessor?.BackOfficeSecurity.CurrentUser;
|
||||
|
||||
return await _twoFactorLoginService.ValidateAndSaveAsync(providerName, user.Key, secret, code);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessUsers)]
|
||||
public async Task<ActionResult<bool>> Disable(string providerName, Guid userKey)
|
||||
{
|
||||
return await _twoFactorLoginService.DisableAsync(userKey, providerName);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<bool>> DisableWithCode(string providerName, string code)
|
||||
{
|
||||
Guid key = _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser.Key;
|
||||
|
||||
return await _twoFactorLoginService.DisableWithCodeAsync(providerName, key, code);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public ActionResult<string> ViewPathForProviderName(string providerName)
|
||||
{
|
||||
var options = _twoFactorLoginViewOptions.Get(providerName);
|
||||
return options.SetupViewPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,11 @@ namespace Umbraco.Extensions
|
||||
{
|
||||
o.Cookie.Name = Constants.Security.BackOfficeTwoFactorAuthenticationType;
|
||||
o.ExpireTimeSpan = TimeSpan.FromMinutes(5);
|
||||
})
|
||||
.AddCookie(Constants.Security.BackOfficeTwoFactorRememberMeAuthenticationType, o =>
|
||||
{
|
||||
o.Cookie.Name = Constants.Security.BackOfficeTwoFactorRememberMeAuthenticationType;
|
||||
o.ExpireTimeSpan = TimeSpan.FromMinutes(5);
|
||||
});
|
||||
|
||||
builder.Services.ConfigureOptions<ConfigureBackOfficeCookieOptions>();
|
||||
|
||||
@@ -42,7 +42,8 @@ namespace Umbraco.Extensions
|
||||
factory.GetRequiredService<IOptionsSnapshot<GlobalSettings>>(),
|
||||
factory.GetRequiredService<IUmbracoMapper>(),
|
||||
factory.GetRequiredService<BackOfficeErrorDescriber>(),
|
||||
factory.GetRequiredService<AppCaches>()
|
||||
factory.GetRequiredService<AppCaches>(),
|
||||
factory.GetRequiredService<ITwoFactorLoginService>()
|
||||
))
|
||||
.AddUserManager<IBackOfficeUserManager, BackOfficeUserManager>()
|
||||
.AddSignInManager<IBackOfficeSignInManager, BackOfficeSignInManager>()
|
||||
@@ -64,7 +65,7 @@ namespace Umbraco.Extensions
|
||||
|
||||
services.TryAddScoped<IIpResolver, AspNetCoreIpResolver>();
|
||||
services.TryAddSingleton<IBackOfficeExternalLoginProviders, BackOfficeExternalLoginProviders>();
|
||||
services.TryAddSingleton<IBackOfficeTwoFactorOptions, NoopBackOfficeTwoFactorOptions>();
|
||||
services.TryAddSingleton<IBackOfficeTwoFactorOptions, DefaultBackOfficeTwoFactorOptions>();
|
||||
|
||||
return new BackOfficeIdentityBuilder(services);
|
||||
}
|
||||
|
||||
@@ -84,6 +84,12 @@ namespace Umbraco.Cms.Web.BackOffice.Filters
|
||||
case IEnumerable<Tab<IDashboardSlim>> dashboards:
|
||||
_eventAggregator.Publish(new SendingDashboardsNotification(dashboards, umbracoContext));
|
||||
break;
|
||||
case IEnumerable<ContentTypeBasic> allowedChildren:
|
||||
// Changing the Enumerable will generate a new instance, so we need to update the context result with the new content
|
||||
var notification = new SendingAllowedChildrenNotification(allowedChildren, umbracoContext);
|
||||
_eventAggregator.Publish(notification);
|
||||
context.Result = new ObjectResult(notification.Children);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,14 @@ using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Core.Notifications;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Web.Common.DependencyInjection;
|
||||
using Umbraco.Cms.Web.Common.Security;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
@@ -24,6 +28,7 @@ namespace Umbraco.Cms.Web.BackOffice.Security
|
||||
{
|
||||
private readonly BackOfficeUserManager _userManager;
|
||||
private readonly IBackOfficeExternalLoginProviders _externalLogins;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
|
||||
protected override string AuthenticationType => Constants.Security.BackOfficeAuthenticationType;
|
||||
@@ -43,14 +48,32 @@ namespace Umbraco.Cms.Web.BackOffice.Security
|
||||
IOptions<GlobalSettings> globalSettings,
|
||||
ILogger<SignInManager<BackOfficeIdentityUser>> logger,
|
||||
IAuthenticationSchemeProvider schemes,
|
||||
IUserConfirmation<BackOfficeIdentityUser> confirmation)
|
||||
IUserConfirmation<BackOfficeIdentityUser> confirmation,
|
||||
IEventAggregator eventAggregator)
|
||||
: base(userManager, contextAccessor, claimsFactory, optionsAccessor, logger, schemes, confirmation)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_externalLogins = externalLogins;
|
||||
_eventAggregator = eventAggregator;
|
||||
_globalSettings = globalSettings.Value;
|
||||
}
|
||||
|
||||
[Obsolete("Use ctor with all params")]
|
||||
public BackOfficeSignInManager(
|
||||
BackOfficeUserManager userManager,
|
||||
IHttpContextAccessor contextAccessor,
|
||||
IBackOfficeExternalLoginProviders externalLogins,
|
||||
IUserClaimsPrincipalFactory<BackOfficeIdentityUser> claimsFactory,
|
||||
IOptions<IdentityOptions> optionsAccessor,
|
||||
IOptions<GlobalSettings> globalSettings,
|
||||
ILogger<SignInManager<BackOfficeIdentityUser>> logger,
|
||||
IAuthenticationSchemeProvider schemes,
|
||||
IUserConfirmation<BackOfficeIdentityUser> confirmation)
|
||||
: this(userManager, contextAccessor, externalLogins, claimsFactory, optionsAccessor, globalSettings, logger, schemes, confirmation, StaticServiceProvider.Instance.GetRequiredService<IEventAggregator>())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Custom ExternalLoginSignInAsync overload for handling external sign in with auto-linking
|
||||
/// </summary>
|
||||
@@ -284,6 +307,31 @@ namespace Umbraco.Cms.Web.BackOffice.Security
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task<SignInResult> SignInOrTwoFactorAsync(BackOfficeIdentityUser user, bool isPersistent,
|
||||
string loginProvider = null, bool bypassTwoFactor = false)
|
||||
{
|
||||
var result = await base.SignInOrTwoFactorAsync(user, isPersistent, loginProvider, bypassTwoFactor);
|
||||
|
||||
if (result.RequiresTwoFactor)
|
||||
{
|
||||
NotifyRequiresTwoFactor(user);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void NotifyRequiresTwoFactor(BackOfficeIdentityUser user) => Notify(user,
|
||||
(currentUser) => new UserTwoFactorRequestedNotification(currentUser.Key)
|
||||
);
|
||||
|
||||
private T Notify<T>(BackOfficeIdentityUser currentUser, Func<BackOfficeIdentityUser, T> createNotification) where T : INotification
|
||||
{
|
||||
|
||||
var notification = createNotification(currentUser);
|
||||
_eventAggregator.Publish(notification);
|
||||
return notification;
|
||||
}
|
||||
|
||||
private void LogFailedExternalLogin(ExternalLoginInfo loginInfo, BackOfficeIdentityUser user) =>
|
||||
Logger.LogWarning("The AutoLinkOptions of the external authentication provider '{LoginProvider}' have refused the login based on the OnExternalLogin method. Affected user id: '{UserId}'", loginInfo.LoginProvider, user.Id);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Cms.Web.BackOffice.Security
|
||||
{
|
||||
public class DefaultBackOfficeTwoFactorOptions : IBackOfficeTwoFactorOptions
|
||||
{
|
||||
public string GetTwoFactorView(string username) => "views\\common\\login-2fa.html";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
namespace Umbraco.Cms.Web.BackOffice.Security
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Cms.Web.BackOffice.Security
|
||||
{
|
||||
[Obsolete("Not used anymore")]
|
||||
public class NoopBackOfficeTwoFactorOptions : IBackOfficeTwoFactorOptions
|
||||
{
|
||||
public string GetTwoFactorView(string username) => null;
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace Umbraco.Cms.Web.BackOffice.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Options used as named options for 2fa providers
|
||||
/// </summary>
|
||||
public class TwoFactorLoginViewOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the path of the view to show when setting up this 2fa provider
|
||||
/// </summary>
|
||||
public string SetupViewPath { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -126,7 +126,11 @@ namespace Umbraco.Cms.Web.BackOffice.Trees
|
||||
menu.Items.Add<ActionNew>(LocalizedTextService, opensDialog: true);
|
||||
|
||||
if (id != Constants.System.RootString)
|
||||
{
|
||||
menu.Items.Add<ActionDelete>(LocalizedTextService, true, opensDialog: true);
|
||||
menu.Items.Add<ActionMove>(LocalizedTextService, true, opensDialog: true);
|
||||
}
|
||||
|
||||
|
||||
menu.Items.Add(new RefreshNode(LocalizedTextService, true));
|
||||
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Trees;
|
||||
using Umbraco.Cms.Web.Common.Attributes;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
using Umbraco.Cms.Web.Common.DependencyInjection;
|
||||
using Constants = Umbraco.Cms.Core.Constants;
|
||||
|
||||
namespace Umbraco.Cms.Web.BackOffice.Trees
|
||||
@@ -21,14 +24,34 @@ namespace Umbraco.Cms.Web.BackOffice.Trees
|
||||
{
|
||||
private readonly IMemberGroupService _memberGroupService;
|
||||
|
||||
[ActivatorUtilitiesConstructor]
|
||||
public MemberGroupTreeController(
|
||||
ILocalizedTextService localizedTextService,
|
||||
UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection,
|
||||
IMenuItemCollectionFactory menuItemCollectionFactory,
|
||||
IMemberGroupService memberGroupService,
|
||||
IEventAggregator eventAggregator,
|
||||
IMemberTypeService memberTypeService)
|
||||
: base(localizedTextService, umbracoApiControllerTypeCollection, menuItemCollectionFactory, eventAggregator, memberTypeService)
|
||||
=> _memberGroupService = memberGroupService;
|
||||
|
||||
[Obsolete("Use ctor with all params")]
|
||||
public MemberGroupTreeController(
|
||||
ILocalizedTextService localizedTextService,
|
||||
UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection,
|
||||
IMenuItemCollectionFactory menuItemCollectionFactory,
|
||||
IMemberGroupService memberGroupService,
|
||||
IEventAggregator eventAggregator)
|
||||
: base(localizedTextService, umbracoApiControllerTypeCollection, menuItemCollectionFactory, eventAggregator)
|
||||
=> _memberGroupService = memberGroupService;
|
||||
: this(localizedTextService,
|
||||
umbracoApiControllerTypeCollection,
|
||||
menuItemCollectionFactory,
|
||||
memberGroupService,
|
||||
eventAggregator,
|
||||
StaticServiceProvider.Instance.GetRequiredService<IMemberTypeService>())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected override IEnumerable<TreeNode> GetTreeNodesFromService(string id, FormCollection queryStrings)
|
||||
=> _memberGroupService.GetAll()
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
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.Events;
|
||||
@@ -8,6 +10,8 @@ using Umbraco.Cms.Core.Models.Trees;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Trees;
|
||||
using Umbraco.Cms.Web.Common.Attributes;
|
||||
using Umbraco.Cms.Web.Common.DependencyInjection;
|
||||
using Umbraco.Extensions;
|
||||
using Constants = Umbraco.Cms.Core.Constants;
|
||||
|
||||
namespace Umbraco.Cms.Web.BackOffice.Trees
|
||||
@@ -16,21 +20,46 @@ namespace Umbraco.Cms.Web.BackOffice.Trees
|
||||
[CoreTree]
|
||||
public abstract class MemberTypeAndGroupTreeControllerBase : TreeController
|
||||
{
|
||||
private readonly IMemberTypeService _memberTypeService;
|
||||
|
||||
public IMenuItemCollectionFactory MenuItemCollectionFactory { get; }
|
||||
|
||||
protected MemberTypeAndGroupTreeControllerBase(
|
||||
ILocalizedTextService localizedTextService,
|
||||
UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection,
|
||||
IMenuItemCollectionFactory menuItemCollectionFactory,
|
||||
IEventAggregator eventAggregator)
|
||||
IEventAggregator eventAggregator,
|
||||
IMemberTypeService memberTypeService)
|
||||
: base(localizedTextService, umbracoApiControllerTypeCollection, eventAggregator)
|
||||
{
|
||||
MenuItemCollectionFactory = menuItemCollectionFactory;
|
||||
|
||||
_memberTypeService = memberTypeService;
|
||||
}
|
||||
|
||||
[Obsolete("Use ctor injecting IMemberTypeService")]
|
||||
protected MemberTypeAndGroupTreeControllerBase(
|
||||
ILocalizedTextService localizedTextService,
|
||||
UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection,
|
||||
IMenuItemCollectionFactory menuItemCollectionFactory,
|
||||
IEventAggregator eventAggregator)
|
||||
: this(
|
||||
localizedTextService,
|
||||
umbracoApiControllerTypeCollection,
|
||||
menuItemCollectionFactory,
|
||||
eventAggregator,
|
||||
StaticServiceProvider.Instance.GetRequiredService<IMemberTypeService>())
|
||||
{
|
||||
}
|
||||
|
||||
protected override ActionResult<TreeNodeCollection> GetTreeNodes(string id, FormCollection queryStrings)
|
||||
{
|
||||
var nodes = new TreeNodeCollection();
|
||||
|
||||
// if the request is for folders only then just return
|
||||
if (queryStrings["foldersonly"].ToString().IsNullOrWhiteSpace() == false && queryStrings["foldersonly"].ToString() == "1")
|
||||
return nodes;
|
||||
|
||||
nodes.AddRange(GetTreeNodesFromService(id, queryStrings));
|
||||
return nodes;
|
||||
}
|
||||
@@ -48,6 +77,12 @@ namespace Umbraco.Cms.Web.BackOffice.Trees
|
||||
}
|
||||
else
|
||||
{
|
||||
var memberType = _memberTypeService.Get(int.Parse(id));
|
||||
if (memberType != null)
|
||||
{
|
||||
menu.Items.Add<ActionCopy>(LocalizedTextService, opensDialog: true);
|
||||
}
|
||||
|
||||
// delete member type/group
|
||||
menu.Items.Add<ActionDelete>(LocalizedTextService, opensDialog: true);
|
||||
}
|
||||
|
||||
@@ -32,13 +32,12 @@ namespace Umbraco.Cms.Web.BackOffice.Trees
|
||||
UmbracoTreeSearcher treeSearcher,
|
||||
IMemberTypeService memberTypeService,
|
||||
IEventAggregator eventAggregator)
|
||||
: base(localizedTextService, umbracoApiControllerTypeCollection, menuItemCollectionFactory, eventAggregator)
|
||||
: base(localizedTextService, umbracoApiControllerTypeCollection, menuItemCollectionFactory, eventAggregator, memberTypeService)
|
||||
{
|
||||
_treeSearcher = treeSearcher;
|
||||
_memberTypeService = memberTypeService;
|
||||
}
|
||||
|
||||
|
||||
protected override ActionResult<TreeNode> CreateRootNode(FormCollection queryStrings)
|
||||
{
|
||||
var rootResult = base.CreateRootNode(queryStrings);
|
||||
|
||||
@@ -92,8 +92,6 @@ namespace Umbraco.Cms.Web.Common.ApplicationBuilder
|
||||
{
|
||||
UseUmbracoCoreMiddleware();
|
||||
|
||||
AppBuilder.UseStatusCodePages();
|
||||
|
||||
// Important we handle image manipulations before the static files, otherwise the querystring is just ignored.
|
||||
AppBuilder.UseImageSharp();
|
||||
|
||||
|
||||
@@ -159,6 +159,7 @@ namespace Umbraco.Extensions
|
||||
));
|
||||
|
||||
builder.AddCoreInitialServices();
|
||||
builder.AddTelemetryProviders();
|
||||
|
||||
// aspnet app lifetime mgmt
|
||||
builder.Services.AddUnique<IUmbracoApplicationLifetime, AspNetCoreUmbracoApplicationLifetime>();
|
||||
|
||||
@@ -799,9 +799,13 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder
|
||||
if (!_disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (_watcher != null)
|
||||
{
|
||||
_watcher.EnableRaisingEvents = false;
|
||||
_watcher.Dispose();
|
||||
}
|
||||
|
||||
_locker.Dispose();
|
||||
}
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@ namespace Umbraco.Cms.Web.Common.Security
|
||||
return await base.VerifyPasswordAsync(store, user, password);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Override to check the user approval value as well as the user lock out date, by default this only checks the user's locked out date
|
||||
/// </summary>
|
||||
|
||||
@@ -45,9 +45,6 @@ namespace Umbraco.Cms.Web.Common.Security
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool SupportsUserTwoFactor => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<bool> IsMemberAuthorizedAsync(IEnumerable<string> allowTypes = null, IEnumerable<string> allowGroups = null, IEnumerable<int> allowMembers = null)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function AppHeaderDirective(eventsService, appState, userService, focusService, overlayService, $timeout) {
|
||||
function AppHeaderDirective(eventsService, appState, userService, focusService, $timeout, editorService) {
|
||||
|
||||
function link(scope, element) {
|
||||
|
||||
@@ -72,17 +72,15 @@
|
||||
};
|
||||
|
||||
scope.avatarClick = function () {
|
||||
|
||||
const dialog = {
|
||||
view: "user",
|
||||
position: "right",
|
||||
name: "overlay-user",
|
||||
const userEditor = {
|
||||
size: "small",
|
||||
view: "views/common/infiniteeditors/user/user.html",
|
||||
close: function() {
|
||||
overlayService.close();
|
||||
editorService.close();
|
||||
}
|
||||
};
|
||||
|
||||
overlayService.open(dialog);
|
||||
editorService.open(userEditor);
|
||||
};
|
||||
|
||||
scope.logoModal = {
|
||||
|
||||
@@ -443,12 +443,16 @@
|
||||
vm.twoFactor.submitCallback = function submitCallback() {
|
||||
vm.onLogin();
|
||||
}
|
||||
vm.twoFactor.cancelCallback = function cancelCallback() {
|
||||
vm.showLogin();
|
||||
}
|
||||
vm.twoFactor.view = viewPath;
|
||||
vm.view = "2fa-login";
|
||||
SetTitle();
|
||||
}
|
||||
|
||||
function resetInputValidation() {
|
||||
vm.loginStates.submitButton = "init";
|
||||
vm.confirmPassword = "";
|
||||
vm.password = "";
|
||||
vm.login = "";
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user