Merge branch 'v8/dev' of https://github.com/umbraco/Umbraco-CMS into pr/6691_vary-by-culture-set-unset-culture-flag-only
# Conflicts: # src/Umbraco.Web/Models/Mapping/ContentTypeMapDefinition.cs
This commit is contained in:
+5
-3
@@ -1,4 +1,4 @@
|
||||
# Umbraco Cms Build
|
||||
# Umbraco CMS Build
|
||||
|
||||
## Are you sure?
|
||||
|
||||
@@ -39,6 +39,8 @@ To build Umbraco, fire up PowerShell and move to Umbraco's repository root (the
|
||||
|
||||
build/build.ps1
|
||||
|
||||
If you only see a build.bat-file, you're probably on the wrong branch. If you switch to the correct branch (dev-v8) the file will appear and you can build it.
|
||||
|
||||
You might run into [Powershell quirks](#powershell-quirks).
|
||||
|
||||
### Build Infrastructure
|
||||
@@ -66,7 +68,7 @@ The Visual Studio object is `null` when Visual Studio has not been detected (eg
|
||||
* `Path`: Visual Studio installation path (eg some place under `Program Files`)
|
||||
* `Major`: Visual Studio major version (eg `15` for VS 2017)
|
||||
* `Minor`: Visual Studio minor version
|
||||
* `MsBUild`: the absolute path to the MsBuild executable
|
||||
* `MsBuild`: the absolute path to the MsBuild executable
|
||||
|
||||
#### GetUmbracoVersion
|
||||
|
||||
@@ -209,4 +211,4 @@ The best solution is to unblock the Zip file before un-zipping: right-click the
|
||||
|
||||
### Git Quirks
|
||||
|
||||
Git might have issues dealing with long file paths during build. You may want/need to enable `core.longpaths` support (see [this page](https://github.com/msysgit/msysgit/wiki/Git-cannot-create-a-file-or-directory-with-a-long-path) for details).
|
||||
Git might have issues dealing with long file paths during build. You may want/need to enable `core.longpaths` support (see [this page](https://github.com/msysgit/msysgit/wiki/Git-cannot-create-a-file-or-directory-with-a-long-path) for details).
|
||||
|
||||
@@ -29,4 +29,4 @@ Don't rest on your laurels and never accept the status quo. Contribute and give
|
||||
|
||||
## Friendly
|
||||
|
||||
Don’t judge upon mistakes made but rather upon the speed and quality with which mistakes are corrected. Friendly posts and contributions generate smiles and builds long lasting relationships.
|
||||
Don’t judge upon mistakes made but rather upon the speed and quality with which mistakes are corrected. Friendly posts and contributions generate smiles and build long lasting relationships.
|
||||
+39
-30
@@ -2,15 +2,15 @@
|
||||
|
||||
👍🎉 First off, thanks for taking the time to contribute! 🎉👍
|
||||
|
||||
The following is a set of guidelines for contributing to Umbraco CMS.
|
||||
The following is a set of guidelines, for contributing to Umbraco CMS.
|
||||
|
||||
These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.
|
||||
These are mostly guidelines, not rules. Use your best judgement, and feel free to propose changes to this document in a pull request.
|
||||
|
||||
Remember, we're a friendly bunch and are happy with whatever contribution you might provide. Below are guidelines for success that we've gathered over the years. If you choose to ignore them then we still love you 💖.
|
||||
|
||||
**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](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).
|
||||
|
||||
**Table of contents**
|
||||
|
||||
@@ -38,11 +38,11 @@ This document gives you a quick overview on how to get started.
|
||||
|
||||
### Guidelines for contributions we welcome
|
||||
|
||||
Not all changes are wanted, so on occassion we might close a PR without merging it. We will give you feedback why we can't accept your changes and we'll be nice about it, thanking you for spending your valuable time.
|
||||
Not all changes are wanted, so on occasion we might close a PR without merging it. We will give you feedback why we can't accept your changes and we'll be nice about it, thanking you for spending your valuable time.
|
||||
|
||||
We have [documented what we consider small and large changes](CONTRIBUTION_GUIDELINES.md). Make sure to talk to us before making large changes.
|
||||
We have [documented what we consider small and large changes](CONTRIBUTION_GUIDELINES.md). Make sure to talk to us before making large changes, so we can ensure that you don't put all your hard work into something we would not be able to merge.
|
||||
|
||||
Remember, if an issue is in the `Up for grabs` list or you've asked for some feedback before you sent us a PR, your PR will not be closed as unwanted.
|
||||
Remember, it is always worth working on an issue from the `Up for grabs` list or even asking for some feedback before you send us a PR. This way, your PR will not be closed as unwanted.
|
||||
|
||||
### What can I start with?
|
||||
|
||||
@@ -59,37 +59,38 @@ Great question! The short version goes like this:
|
||||
* **Clone** - when GitHub has created your fork, you can clone it in your favorite Git tool
|
||||
|
||||

|
||||
|
||||
|
||||
* **Switch to the correct branch** - switch to the v8-dev branch
|
||||
* **Build** - build your fork of Umbraco locally as described in [building Umbraco from source code](BUILD.md)
|
||||
* **Change** - make your changes, experiment, have fun, explore and learn, and don't be afraid. We welcome all contributions and will [happily give feedback](#questions)
|
||||
* **Commit** - done? Yay! 🎉 **Important:** create a new branch now and name it after the issue you're fixing, we usually follow the format: `temp-12345`. This means it's a temporary branch for the particular issue you're working on, in this case `12345`. When you have a branch, commit your changes. Don't commit to `v8/dev`, create a new branch first.
|
||||
* **Push** - great, now you can push the changes up to your fork on GitHub
|
||||
* **Create pull request** - exciting! You're ready to show us your changes (or not quite ready, you just need some feedback to progress). GitHub has picked up on the new branch you've pushed and will offer to create a Pull Request. Click that green button and away you go.
|
||||
* **Create pull request** - exciting! You're ready to show us your changes (or not quite ready, you just need some feedback to progress - you can now make use of GitHub's draft pull request status, detailed [here] (https://github.blog/2019-02-14-introducing-draft-pull-requests/)). GitHub has picked up on the new branch you've pushed and will offer to create a Pull Request. Click that green button and away you go.
|
||||
|
||||

|
||||
|
||||
### Pull requests
|
||||
The most successful pull requests usually look a like this:
|
||||
|
||||
* Fill in the required template
|
||||
* Fill in the required template, linking your pull request to an issue on the [issue tracker,](https://github.com/umbraco/Umbraco-CMS/issues) if applicable.
|
||||
* Include screenshots and animated GIFs in your pull request whenever possible.
|
||||
* Unit tests, while optional are awesome, thank you!
|
||||
* New code is commented with documentation from which [the reference documentation](https://our.umbraco.com/documentation/Reference/) is generated
|
||||
* Unit tests, while optional, are awesome. Thank you!
|
||||
* New code is commented with documentation from which [the reference documentation](https://our.umbraco.com/documentation/Reference/) is generated.
|
||||
|
||||
Again, these are guidelines, not strict requirements.
|
||||
Again, these are guidelines, not strict requirements. However, the more information that you give to us, the more we have to work with when considering your contributions. Good documentation of a pull request can really speed up the time it takes to review and merge your work!
|
||||
|
||||
## Reviews
|
||||
|
||||
You've sent us your first contribution, congratulations! Now what?
|
||||
You've sent us your first contribution - congratulations! Now what?
|
||||
|
||||
The [pull request team](#the-pr-team) can now start reviewing your proposed changes and give you feedback on them. If it's not perfect, we'll either fix up what we need or we can request you to make some additional changes.
|
||||
The [pull request team](#the-pr-team) can now start reviewing your proposed changes and give you feedback on them. If it's not perfect, we'll either fix up what we need or we can request that you make some additional changes.
|
||||
|
||||
We have [a process in place which you can read all about](REVIEW_PROCESS.md). The very abbreviated version is:
|
||||
|
||||
- Your PR will get a reply within 48 hours
|
||||
- An in-depth reply will be added within at most 2 weeks
|
||||
- The PR will be either merged or rejected within at most 4 weeks
|
||||
- Sometimes it is difficult to meet these timelines and we'll talk to you
|
||||
- Sometimes it is difficult to meet these timelines and we'll talk to you if this is the case.
|
||||
|
||||
### Styleguides
|
||||
|
||||
@@ -99,21 +100,21 @@ That said, the Umbraco development team likes to follow the hints that ReSharper
|
||||
|
||||
### The PR team
|
||||
|
||||
The pull request team consists of a member of Umbraco HQ, [Sebastiaan](https://github.com/nul800sebastiaan), who gets assistance from the following community members
|
||||
The pull request team consists of one member of Umbraco HQ, [Sebastiaan](https://github.com/nul800sebastiaan), who gets assistance from the following community members who have comitted to volunteering their free time:
|
||||
|
||||
- [Anders Bjerner](https://github.com/abjerner)
|
||||
- [Dave Woestenborghs](https://github.com/dawoe)
|
||||
- [Emma Burstow](https://github.com/emmaburstow)
|
||||
- [Poornima Nayar](https://github.com/poornimanayar)
|
||||
|
||||
These wonderful volunteers will provide you with a first reply to your PR, review and test out your changes and might ask more questions. After that they'll let Umbraco HQ know if everything seems okay.
|
||||
These wonderful people aim to provide you with a first reply to your PR, review and test out your changes and on occasions, they might ask more questions. If they are happy with your work, they'll let Umbraco HQ know by approving the PR. Hq will have final sign-off and will check the work again before it is merged.
|
||||
|
||||
### Questions?
|
||||
|
||||
You can get in touch with [the PR team](#the-pr-team) in multiple ways, we love open conversations and we are a friendly bunch. No question you have is stupid. Any questions you have usually helps out multiple people with the same question. Ask away:
|
||||
You can get in touch with [the PR team](#the-pr-team) in multiple ways; we love open conversations and we are a friendly bunch. No question you have is stupid. Any question you have usually helps out multiple people with the same question. Ask away:
|
||||
|
||||
- If there's an existing issue on the issue tracker then that's a good place to leave questions and discuss how to start or move forward
|
||||
- Unsure where to start? Did something not work as expected? Try leaving a note in the ["Contributing to Umbraco"](https://our.umbraco.com/forum/contributing-to-umbraco-cms/) forum, the team monitors that one closely
|
||||
- If there's an existing issue on the issue tracker then that's a good place to leave questions and discuss how to start or move forward.
|
||||
- Unsure where to start? Did something not work as expected? Try leaving a note in the ["Contributing to Umbraco"](https://our.umbraco.com/forum/contributing-to-umbraco-cms/) forum. The team monitors that one closely, so one of us will be on hand and ready to point you in the right direction.
|
||||
|
||||
## Working with the code
|
||||
|
||||
@@ -125,19 +126,19 @@ In order to build the Umbraco source code locally, first make sure you have the
|
||||
* Node v10+
|
||||
* npm v6.4.1+
|
||||
|
||||
The easiest way to get started is to run `build.ps1` which will build both the backoffice (also known as "Belle") and the Umbraco core. You can then easily start debugging from Visual Studio, or if you need to debug Belle you can run `gulp dev` in `src\Umbraco.Web.UI.Client`. See [this page](BUILD.md) for more details.
|
||||
The easiest way to get started is to open `src\umbraco.sln` in Visual Studio 2017 (version 15.9.7 or higher, [the community edition is free](https://www.visualstudio.com/thank-you-downloading-visual-studio/?sku=Community&rel=15) for you to use to contribute to Open Source projects). In Visual Studio, find the Task Runner Explorer (in the View menu under Other Windows) and run the build task under the gulpfile.
|
||||
|
||||
Alternatively, you can open `src\umbraco.sln` in Visual Studio 2017 (version 15.9.7 or higher, [the community edition is free](https://www.visualstudio.com/thank-you-downloading-visual-studio/?sku=Community&rel=15) for you to use to contribute to Open Source projects). In Visual Studio, find the Task Runner Explorer (in the View menu under Other Windows) and run the build task under the gulpfile.
|
||||
Alternatively, you can run `build.ps1` from the Powershell command line, which will build both the backoffice (also known as "Belle") and the Umbraco core. You can then easily start debugging from Visual Studio, or if you need to debug Belle you can run `gulp dev` in `src\Umbraco.Web.UI.Client`. See [this page](BUILD.md) for more details.
|
||||
|
||||

|
||||
|
||||
After this build completes, you should be able to hit `F5` in Visual Studio to build and run the project. A IISExpress webserver will start and the Umbraco installer will pop up in your browser, follow the directions there to get a working Umbraco install up and running.
|
||||
After this build completes, you should be able to hit `F5` in Visual Studio to build and run the project. A IISExpress webserver will start and the Umbraco installer will pop up in your browser. Follow the directions there to get a working Umbraco install up and running.
|
||||
|
||||
### Working with the source code
|
||||
|
||||
Some parts of our source code are over 10 years old now. And when we say "old", we mean "mature" of course!
|
||||
|
||||
There's two big areas that you should know about:
|
||||
There are two big areas that you should know about:
|
||||
|
||||
1. The Umbraco backoffice is a extensible AngularJS app and requires you to run a `gulp dev` command while you're working with it, so changes are copied over to the appropriate directories and you can refresh your browser to view the results of your changes.
|
||||
You may need to run the following commands to set up gulp properly:
|
||||
@@ -146,30 +147,34 @@ There's two big areas that you should know about:
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
The caching for the back office has been described as 'aggressive' so we often find it's best when making back office changes to disable caching in the browser to help you to see the changes you're making.
|
||||
|
||||
2. "The rest" is a C# based codebase, which is mostly ASP.NET MVC based. You can make changes, build them in Visual Studio, and hit `F5` to see the result.
|
||||
|
||||
To find the general areas of something you're looking to fix or improve, have a look at the following two parts of the API documentation.
|
||||
To find the general areas for something you're looking to fix or improve, have a look at the following two parts of the API documentation.
|
||||
|
||||
* [The AngularJS based backoffice files](https://our.umbraco.com/apidocs/ui/#/api) (to be found in `src\Umbraco.Web.UI.Client\src`)
|
||||
* [The C# application](https://our.umbraco.com/apidocs/csharp/)
|
||||
|
||||
### Which branch should I target for my contributions?
|
||||
|
||||
We like to use [Gitflow as much as possible](https://jeffkreeftmeijer.com/git-flow/), don't worry if you are not familiar with it. The most important thing you need to know is that when you fork the Umbraco repository, the default branch is set to something, usually `v8/dev`. Whatever the default is, that's where we'd like you to target your contributions.
|
||||
We like to use [Gitflow as much as possible](https://jeffkreeftmeijer.com/git-flow/), but don't worry if you are not familiar with it. The most important thing you need to know is that when you fork the Umbraco repository, the default branch is set to something, usually `v8/dev`. If you are working on v8, this is the branch you should be targetting. For v7 contributions, please target 'v7/dev'.
|
||||
|
||||
Please note: we are no longer accepting features for v7 but will continue to merge bug fixes as and when they arise.
|
||||
|
||||

|
||||
|
||||
### Making changes after the PR was opened
|
||||
### Making changes after the PR is open
|
||||
|
||||
If you make the corrections we ask for in the same branch and push them to your fork again, the pull request automatically updates with the additional commit(s) so we can review it again. If all is well, we'll merge the code and your commits are forever part of Umbraco!
|
||||
|
||||
### Keeping your Umbraco fork in sync with the main repository
|
||||
|
||||
We recommend you sync with our repository before you submit your pull request. That way, you can fix any potential merge conflicts and make our lives a little bit easier.
|
||||
We recommend you to sync with our repository before you submit your pull request. That way, you can fix any potential merge conflicts and make our lives a little bit easier.
|
||||
|
||||
Also, if you've submitted a pull request three weeks ago and want to work on something new, you'll want to get the latest code to build against of course.
|
||||
Also, if you have submitted a pull request three weeks ago and want to work on something new, you'll want to get the latest code to build against of course.
|
||||
|
||||
To sync your fork with this original one, you'll have to add the upstream url, you only have to do this once:
|
||||
To sync your fork with this original one, you'll have to add the upstream url. You only have to do this once:
|
||||
|
||||
```
|
||||
git remote add upstream https://github.com/umbraco/Umbraco-CMS.git
|
||||
@@ -185,3 +190,7 @@ git rebase upstream/v8/dev
|
||||
In this command we're syncing with the `v8/dev` branch, but you can of course choose another one if needed.
|
||||
|
||||
(More info on how this works: [http://robots.thoughtbot.com/post/5133345960/keeping-a-git-fork-updated](http://robots.thoughtbot.com/post/5133345960/keeping-a-git-fork-updated))
|
||||
|
||||
### And finally
|
||||
|
||||
We welcome all kinds of contributions to this repository. If you don't feel you'd like to make code changes here, you can visit our [documentation repository](https://github.com/umbraco/UmbracoDocs) and use your experience to contribute to making the docs we have, even better. We also encourage community members to feel free to comment on others' pull requests and issues - the expertise we have is not limited to the PR team and HQ. So, if you see something on the issue tracker or pull requests you feel you can add to, please don't be shy.
|
||||
|
||||
@@ -13,7 +13,7 @@ We’re usually able to handle small PRs pretty quickly. A community volunteer w
|
||||
|
||||
Umbraco HQ will regularly mark newly created issues on the issue tracker with the `Up for grabs` tag. This means that the proposed changes are wanted in Umbraco but the HQ does not have the time to make them at this time. We encourage anyone to pick them up and help out.
|
||||
|
||||
If you do start working on something, make sure leave a small comment on the issue saying something like: "I'm working on this". That way other people stumbling upon the issue know they don't need to pick it up, someone already has.
|
||||
If you do start working on something, make sure to leave a small comment on the issue saying something like: "I'm working on this". That way other people stumbling upon the issue know they don't need to pick it up, someone already has.
|
||||
|
||||
## Large PRs
|
||||
New features and large refactorings - can be recognized by seeing a large number of changes, plenty of new files, updates to package manager files (NuGet’s packages.config, NPM’s packages.json, etc.).
|
||||
@@ -30,6 +30,6 @@ It is highly recommended that you speak to the HQ before making large, complex c
|
||||
|
||||
### Pull request or package?
|
||||
|
||||
If it doesn’t fit in CMS right now, we will likely encourage you to make it into a package instead. A package is a great way to check out popularity of a feature, learn how people use it, validate good usability and to fix bugs.
|
||||
If it doesn’t fit in CMS right now, we will likely encourage you to make it into a package instead. A package is a great way to check out popularity of a feature, learn how people use it, validate good usability and fix bugs.
|
||||
|
||||
Eventually, a package could "graduate" to be included in the CMS.
|
||||
|
||||
@@ -7,15 +7,15 @@ A brief description of the issue goes here.
|
||||
|
||||
<!--
|
||||
|
||||
If you haven't yet done so, please read the "contributing guidelines"
|
||||
thoroughly. Then, proceed by filling out the rest of the details in the issue
|
||||
template below. The more details you can give us, the easier it will be for us
|
||||
Please fill out the rest of the details in the issue template below.
|
||||
The more details you can give us, the easier it will be for us
|
||||
to determine the cause of a problem.
|
||||
|
||||
See: https://github.com/umbraco/Umbraco-CMS/blob/v8/dev/.github/CONTRIBUTING.md
|
||||
|
||||
-->
|
||||
|
||||
## Umbraco version
|
||||
|
||||
I am seeing this issue on Umbraco version: <!-- please note the version here -->
|
||||
|
||||
|
||||
Reproduction
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
# [Umbraco CMS](https://umbraco.com) · [](../LICENSE.md) [](https://umbraco.visualstudio.com/Umbraco%20Cms/_build?definitionId=75) [](CONTRIBUTING.md) [](https://pullreminders.com?ref=badge)
|
||||
# [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 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.
|
||||
|
||||
@@ -21,7 +21,7 @@ Please also see our [Code of Conduct](CODE_OF_CONDUCT.md).
|
||||
|
||||
[Umbraco Cloud](https://umbraco.com/cloud) is the easiest and fastest way to use Umbraco yet, with full support for all your custom .NET code and integrations. You're up and running in less than a minute, and your life will be made easier with automated upgrades and a built-in deployment engine. We offer a free 14-day trial, no credit card needed.
|
||||
|
||||
If you want to DIY, you can [download Umbraco]((https://our.umbraco.com/download)) either as a ZIP file or via NuGet. It's the same version of Umbraco CMS that powers Umbraco Cloud, but you'll need to find a place to host it yourself, and handling deployments and upgrades will be all up to you.
|
||||
If you want to DIY, then you can [download Umbraco]((https://our.umbraco.com/download)) either as a ZIP file or via NuGet. It's the same version of Umbraco CMS that powers Umbraco Cloud, but you'll need to find a place to host it yourself, and handling deployments and upgrades will be all up to you.
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -29,7 +29,7 @@ The documentation for Umbraco CMS can be found [on Our Umbraco](https://our.umbr
|
||||
|
||||
## Join the Umbraco community
|
||||
|
||||
Our friendly community is available 24/7 at the community hub we call ["Our Umbraco"](https://our.umbraco.com/). Our Umbraco features forums for questions and answers, documentation, downloadable plugins for Umbraco, and a rich collection of community resources.
|
||||
Our friendly community is available 24/7 at the community hub, we call ["Our Umbraco"](https://our.umbraco.com/). Our Umbraco features forums for questions and answers, documentation, downloadable plugins for Umbraco, and a rich collection of community resources.
|
||||
|
||||
Besides "Our", we all support each other also via Twitter: [Umbraco HQ](https://twitter.com/umbraco), [Release Updates](https://twitter.com/umbracoproject), [#umbraco](https://twitter.com/hashtag/umbraco)
|
||||
|
||||
|
||||
@@ -11,21 +11,16 @@ Y88 88Y 888 888 888 888 d88P 888 888 888 Y88b. Y88..88P
|
||||
|
||||
Don't forget to build!
|
||||
|
||||
We've done our best to transform your configuration files but in case something is not quite right: remember we
|
||||
backed up your files in App_Data\NuGetBackup so you can find the original files before they were transformed.
|
||||
|
||||
We've overwritten all the files in the Umbraco folder, these have been backed up in
|
||||
App_Data\NuGetBackup. We didn't overwrite the UI.xml file nor did we remove any files or folders that you or
|
||||
a package might have added. Only the existing files were overwritten. If you customized anything then make
|
||||
sure to do a compare and merge with the NuGetBackup folder.
|
||||
We've done our best to transform your configuration files but in case something is not quite right: we recommmend you look in source control for the previous version so you can find the original files before they were transformed.
|
||||
|
||||
This NuGet package includes build targets that extend the creation of a deploy package, which is generated by
|
||||
Publishing from Visual Studio. The targets will only work once Publishing is configured, so if you don't use
|
||||
Publish this won't affect you.
|
||||
|
||||
The following items will now be automatically included when creating a deploy package or publishing to the file
|
||||
system: umbraco, config\splashes and global.asax.
|
||||
|
||||
Please read the release notes on our.umbraco.com:
|
||||
http://our.umbraco.com/contribute/releases
|
||||
https://our.umbraco.com/contribute/releases
|
||||
|
||||
- Umbraco
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
<add name="umbracoBaseRequestModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
<add name="viewstateMoverModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
<add name=" UmbracoModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
<add name="UmbracoModule" type="Umbraco.Web.UmbracoModule,umbraco" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
|
||||
<add name="UmbracoModule" type="Umbraco.Web.UmbracoModule,Umbraco.Web" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
|
||||
</httpModules>
|
||||
|
||||
<httpHandlers xdt:Transform="InsertIfMissing" />
|
||||
@@ -76,7 +76,7 @@
|
||||
<!-- Note, we're removing the one that starts with a space here, don't correct it -->
|
||||
<!-- This to fix a quirk we for a lot of releases where we added it with the space by default -->
|
||||
<add name=" UmbracoModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
<add name="UmbracoModule" type="Umbraco.Web.UmbracoModule,umbraco" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
|
||||
<add name="UmbracoModule" type="Umbraco.Web.UmbracoModule,Umbraco.Web" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
|
||||
</modules>
|
||||
|
||||
<staticContent xdt:Transform="InsertIfMissing" />
|
||||
|
||||
+2
-2
@@ -18,5 +18,5 @@ using System.Resources;
|
||||
[assembly: AssemblyVersion("8.0.0")]
|
||||
|
||||
// these are FYI and changed automatically
|
||||
[assembly: AssemblyFileVersion("8.3.0")]
|
||||
[assembly: AssemblyInformationalVersion("8.3.0")]
|
||||
[assembly: AssemblyFileVersion("8.6.0")]
|
||||
[assembly: AssemblyInformationalVersion("8.6.0")]
|
||||
|
||||
@@ -11,5 +11,6 @@
|
||||
public const string TemplateFrontEndCacheKey = "template";
|
||||
|
||||
public const string MacroContentCacheKey = "macroContent_"; // used in MacroRenderers
|
||||
public const string MacroFromAliasCacheKey = "macroFromAlias_";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Core.Collections
|
||||
{
|
||||
@@ -26,7 +27,7 @@ namespace Umbraco.Core.Collections
|
||||
/// <param name="equalityComparer">The equality comparer to use when comparing keys, or null to use the default comparer.</param>
|
||||
public ObservableDictionary(Func<TValue, TKey> keySelector, IEqualityComparer<TKey> equalityComparer = null)
|
||||
{
|
||||
KeySelector = keySelector ?? throw new ArgumentException("keySelector");
|
||||
KeySelector = keySelector ?? throw new ArgumentException(nameof(keySelector));
|
||||
Indecies = new Dictionary<TKey, int>(equalityComparer);
|
||||
}
|
||||
|
||||
@@ -36,7 +37,7 @@ namespace Umbraco.Core.Collections
|
||||
{
|
||||
var key = KeySelector(item);
|
||||
if (Indecies.ContainsKey(key))
|
||||
throw new DuplicateKeyException(key.ToString());
|
||||
throw new ArgumentException($"An element with the same key '{key}' already exists in the dictionary.", nameof(item));
|
||||
|
||||
if (index != Count)
|
||||
{
|
||||
@@ -91,7 +92,7 @@ namespace Umbraco.Core.Collections
|
||||
{
|
||||
//confirm key matches
|
||||
if (!KeySelector(value).Equals(key))
|
||||
throw new InvalidOperationException("Key of new value does not match");
|
||||
throw new InvalidOperationException("Key of new value does not match.");
|
||||
|
||||
if (!Indecies.ContainsKey(key))
|
||||
{
|
||||
@@ -118,7 +119,7 @@ namespace Umbraco.Core.Collections
|
||||
|
||||
//confirm key matches
|
||||
if (!KeySelector(value).Equals(key))
|
||||
throw new InvalidOperationException("Key of new value does not match");
|
||||
throw new InvalidOperationException("Key of new value does not match.");
|
||||
|
||||
this[Indecies[key]] = value;
|
||||
return true;
|
||||
@@ -155,12 +156,12 @@ namespace Umbraco.Core.Collections
|
||||
{
|
||||
if (!Indecies.ContainsKey(currentKey))
|
||||
{
|
||||
throw new InvalidOperationException("No item with the key " + currentKey + "was found in the collection");
|
||||
throw new InvalidOperationException($"No item with the key '{currentKey}' was found in the dictionary.");
|
||||
}
|
||||
|
||||
if (ContainsKey(newKey))
|
||||
{
|
||||
throw new DuplicateKeyException(newKey.ToString());
|
||||
throw new ArgumentException($"An element with the same key '{newKey}' already exists in the dictionary.", nameof(newKey));
|
||||
}
|
||||
|
||||
var currentIndex = Indecies[currentKey];
|
||||
@@ -234,16 +235,5 @@ namespace Umbraco.Core.Collections
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
internal class DuplicateKeyException : Exception
|
||||
{
|
||||
public DuplicateKeyException(string key)
|
||||
: base("Attempted to insert duplicate key \"" + key + "\" in collection.")
|
||||
{
|
||||
Key = key;
|
||||
}
|
||||
|
||||
public string Key { get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
|
||||
namespace Umbraco.Core.Composing.LightInject
|
||||
@@ -6,20 +7,51 @@ namespace Umbraco.Core.Composing.LightInject
|
||||
/// <summary>
|
||||
/// Represents errors that occur due to LightInject.
|
||||
/// </summary>
|
||||
/// <seealso cref="System.Exception" />
|
||||
[Serializable]
|
||||
public class LightInjectException : Exception
|
||||
{
|
||||
public LightInjectException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
public LightInjectException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{ }
|
||||
|
||||
private const string LightInjectUnableToResolveType = "Unable to resolve type:";
|
||||
private const string LightInjectUnresolvedDependency = "Unresolved dependency ";
|
||||
private const string LightInjectRequestedDependency = "[Requested dependency:";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LightInjectException" /> class.
|
||||
/// </summary>
|
||||
public LightInjectException()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LightInjectException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public LightInjectException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LightInjectException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference (<see langword="Nothing" /> in Visual Basic) if no inner exception is specified.</param>
|
||||
public LightInjectException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LightInjectException"/> class.
|
||||
/// </summary>
|
||||
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> that holds the serialized object data about the exception being thrown.</param>
|
||||
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" /> that contains contextual information about the source or destination.</param>
|
||||
protected LightInjectException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Tries to throw the exception with additional details.
|
||||
/// </summary>
|
||||
/// <param name="e">The exception.</param>
|
||||
/// <exception cref="Umbraco.Core.Composing.LightInject.LightInjectException"></exception>
|
||||
public static void TryThrow(Exception e)
|
||||
{
|
||||
var ex = e as InvalidOperationException;
|
||||
@@ -32,6 +64,12 @@ namespace Umbraco.Core.Composing.LightInject
|
||||
throw new LightInjectException(sb.ToString(), e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to throw the exception with additional details.
|
||||
/// </summary>
|
||||
/// <param name="e">The exception.</param>
|
||||
/// <param name="implementingType">The implementing type.</param>
|
||||
/// <exception cref="Umbraco.Core.Composing.LightInject.LightInjectException"></exception>
|
||||
public static void TryThrow(Exception e, Type implementingType)
|
||||
{
|
||||
var ex = e as InvalidOperationException;
|
||||
@@ -45,6 +83,11 @@ namespace Umbraco.Core.Composing.LightInject
|
||||
throw new LightInjectException(sb.ToString(), e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the details.
|
||||
/// </summary>
|
||||
/// <param name="ex">The exception.</param>
|
||||
/// <param name="sb">The <see cref="StringBuilder" /> to write the details to.</param>
|
||||
private static void WriteDetails(InvalidOperationException ex, StringBuilder sb)
|
||||
{
|
||||
ex = ex.InnerException as InvalidOperationException;
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
@@ -813,11 +814,44 @@ namespace Umbraco.Core.Composing
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents the error that occurs when a type was not found in the cache type
|
||||
/// list with the specified TypeResolutionKind.
|
||||
/// Represents the error that occurs when a type was not found in the cache type list with the specified TypeResolutionKind.
|
||||
/// </summary>
|
||||
/// <seealso cref="System.Exception" />
|
||||
[Serializable]
|
||||
internal class CachedTypeNotFoundInFileException : Exception
|
||||
{ }
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CachedTypeNotFoundInFileException" /> class.
|
||||
/// </summary>
|
||||
public CachedTypeNotFoundInFileException()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CachedTypeNotFoundInFileException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public CachedTypeNotFoundInFileException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CachedTypeNotFoundInFileException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference (<see langword="Nothing" /> in Visual Basic) if no inner exception is specified.</param>
|
||||
public CachedTypeNotFoundInFileException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CachedTypeNotFoundInFileException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> that holds the serialized object data about the exception being thrown.</param>
|
||||
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" /> that contains contextual information about the source or destination.</param>
|
||||
protected CachedTypeNotFoundInFileException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{ }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace Umbraco.Core.Configuration.Grid
|
||||
public interface IGridEditorConfig
|
||||
{
|
||||
string Name { get; }
|
||||
string NameTemplate { get; }
|
||||
string Alias { get; }
|
||||
string View { get; }
|
||||
string Render { get; }
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
internal class ContentElement : UmbracoConfigurationElement, IContentSection
|
||||
{
|
||||
private const string DefaultPreviewBadge = @"<a id=""umbracoPreviewBadge"" style=""z-index:99999; position: absolute; top: 0; right: 0; border: 0; width: 149px; height: 149px; background: url('{0}/assets/img/preview-mode-badge.png') no-repeat;"" href=""#"" OnClick=""javascript:window.top.location.href = '{0}/preview/end?redir={1}'""><span style=""display:none;"">In Preview Mode - click to end</span></a>";
|
||||
private const string DefaultPreviewBadge = @"<div id=""umbracoPreviewBadge"" class=""umbraco-preview-badge""><span class=""umbraco-preview-badge__header"">Preview mode</span><a href=""{0}/preview/end?redir={1}"" class=""umbraco-preview-badge__end""><svg viewBox=""0 0 100 100"" xmlns=""http://www.w3.org/2000/svg""><title>Click to end</title><path d=""M5273.1 2400.1v-2c0-2.8-5-4-9.7-4s-9.7 1.3-9.7 4v2a7 7 0 002 4.9l5 4.9c.3.3.4.6.4 1v6.4c0 .4.2.7.6.8l2.9.9c.5.1 1-.2 1-.8v-7.2c0-.4.2-.7.4-1l5.1-5a7 7 0 002-4.9zm-9.7-.1c-4.8 0-7.4-1.3-7.5-1.8.1-.5 2.7-1.8 7.5-1.8s7.3 1.3 7.5 1.8c-.2.5-2.7 1.8-7.5 1.8z""/><path d=""M5268.4 2410.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1s-.4-1-1-1h-4.3zM5272.7 2413.7h-4.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1s-.4-1-1-1zM5272.7 2417h-4.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1 0-.5-.4-1-1-1z""/><path d=""M78.2 13l-8.7 11.7a32.5 32.5 0 11-51.9 25.8c0-10.3 4.7-19.7 12.9-25.8L21.8 13a47 47 0 1056.4 0z""/><path d=""M42.7 2.5h14.6v49.4H42.7z""/></svg></a></div><style type=""text/css"">.umbraco-preview-badge {{position: absolute;top: 1em;right: 1em;display: inline-flex;background: #1b264f;color: #fff;padding: 1em;font-size: 12px;z-index: 99999999;justify-content: center;align-items: center;box-shadow: 0 10px 50px rgba(0, 0, 0, .1), 0 6px 20px rgba(0, 0, 0, .16);line-height: 1;}}.umbraco-preview-badge__header {{font-weight: bold;}}.umbraco-preview-badge__end {{width: 3em;padding: 1em;margin: -1em -1em -1em 2em;display: flex;flex-shrink: 0;align-items: center;align-self: stretch;}}.umbraco-preview-badge__end:hover,.umbraco-preview-badge__end:focus {{background: #f5c1bc;}}.umbraco-preview-badge__end svg {{fill: #fff;width:1em;}}</style>";
|
||||
|
||||
[ConfigurationProperty("imaging")]
|
||||
internal ContentImagingElement Imaging => (ContentImagingElement) this["imaging"];
|
||||
|
||||
@@ -221,7 +221,8 @@ namespace Umbraco.Core
|
||||
FailedPasswordAttempts,
|
||||
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Integer, true, FailedPasswordAttempts)
|
||||
{
|
||||
Name = FailedPasswordAttemptsLabel
|
||||
Name = FailedPasswordAttemptsLabel,
|
||||
DataTypeId = Constants.DataTypes.LabelInt
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -242,35 +243,40 @@ namespace Umbraco.Core
|
||||
LastLockoutDate,
|
||||
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastLockoutDate)
|
||||
{
|
||||
Name = LastLockoutDateLabel
|
||||
Name = LastLockoutDateLabel,
|
||||
DataTypeId = Constants.DataTypes.LabelDateTime
|
||||
}
|
||||
},
|
||||
{
|
||||
LastLoginDate,
|
||||
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastLoginDate)
|
||||
{
|
||||
Name = LastLoginDateLabel
|
||||
Name = LastLoginDateLabel,
|
||||
DataTypeId = Constants.DataTypes.LabelDateTime
|
||||
}
|
||||
},
|
||||
{
|
||||
LastPasswordChangeDate,
|
||||
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastPasswordChangeDate)
|
||||
{
|
||||
Name = LastPasswordChangeDateLabel
|
||||
Name = LastPasswordChangeDateLabel,
|
||||
DataTypeId = Constants.DataTypes.LabelDateTime
|
||||
}
|
||||
},
|
||||
{
|
||||
PasswordAnswer,
|
||||
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar, true, PasswordAnswer)
|
||||
{
|
||||
Name = PasswordAnswerLabel
|
||||
Name = PasswordAnswerLabel,
|
||||
DataTypeId = Constants.DataTypes.LabelString
|
||||
}
|
||||
},
|
||||
{
|
||||
PasswordQuestion,
|
||||
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar, true, PasswordQuestion)
|
||||
{
|
||||
Name = PasswordQuestionLabel
|
||||
Name = PasswordQuestionLabel,
|
||||
DataTypeId = Constants.DataTypes.LabelString
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Core.Exceptions
|
||||
{
|
||||
/// <summary>
|
||||
/// The exception that is thrown when a null reference, or an empty argument,
|
||||
/// is passed to a method that does not accept it as a valid argument.
|
||||
/// The exception that is thrown when a null reference, or an empty argument, is passed to a method that does not accept it as a valid argument.
|
||||
/// </summary>
|
||||
/// <seealso cref="System.ArgumentNullException" />
|
||||
[Obsolete("Throw an ArgumentNullException when the parameter is null or an ArgumentException when its empty instead.")]
|
||||
[Serializable]
|
||||
public class ArgumentNullOrEmptyException : ArgumentNullException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ArgumentNullOrEmptyException"/> class
|
||||
/// with the name of the parameter that caused this exception.
|
||||
/// Initializes a new instance of the <see cref="ArgumentNullOrEmptyException" /> class.
|
||||
/// </summary>
|
||||
public ArgumentNullOrEmptyException()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ArgumentNullOrEmptyException" /> class with the name of the parameter that caused this exception.
|
||||
/// </summary>
|
||||
/// <param name="paramName">The named of the parameter that caused the exception.</param>
|
||||
public ArgumentNullOrEmptyException(string paramName)
|
||||
@@ -18,13 +26,30 @@ namespace Umbraco.Core.Exceptions
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ArgumentNullOrEmptyException"/> class
|
||||
/// with a specified error message and the name of the parameter that caused this exception.
|
||||
/// Initializes a new instance of the <see cref="ArgumentNullOrEmptyException" /> class with a specified error message and the name of the parameter that caused this exception.
|
||||
/// </summary>
|
||||
/// <param name="paramName">The named of the parameter that caused the exception.</param>
|
||||
/// <param name="message">A message that describes the error.</param>
|
||||
public ArgumentNullOrEmptyException(string paramName, string message)
|
||||
: base(paramName, message)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ArgumentNullOrEmptyException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for this exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference (<see langword="Nothing" /> in Visual Basic) if no inner exception is specified.</param>
|
||||
public ArgumentNullOrEmptyException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ArgumentNullOrEmptyException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="info">The object that holds the serialized object data.</param>
|
||||
/// <param name="context">An object that describes the source or destination of the serialized data.</param>
|
||||
protected ArgumentNullOrEmptyException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,45 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Core.Exceptions
|
||||
{
|
||||
/// <summary>
|
||||
/// The exception that is thrown when authorization failed.
|
||||
/// </summary>
|
||||
/// <seealso cref="System.Exception" />
|
||||
[Serializable]
|
||||
public class AuthorizationException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AuthorizationException" /> class.
|
||||
/// </summary>
|
||||
public AuthorizationException()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AuthorizationException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public AuthorizationException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AuthorizationException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference (<see langword="Nothing" /> in Visual Basic) if no inner exception is specified.</param>
|
||||
public AuthorizationException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AuthorizationException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> that holds the serialized object data about the exception being thrown.</param>
|
||||
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" /> that contains contextual information about the source or destination.</param>
|
||||
protected AuthorizationException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
|
||||
namespace Umbraco.Core.Exceptions
|
||||
@@ -6,6 +7,8 @@ namespace Umbraco.Core.Exceptions
|
||||
/// <summary>
|
||||
/// An exception that is thrown if the Umbraco application cannot boot.
|
||||
/// </summary>
|
||||
/// <seealso cref="System.Exception" />
|
||||
[Serializable]
|
||||
public class BootFailedException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
@@ -14,27 +17,47 @@ namespace Umbraco.Core.Exceptions
|
||||
public const string DefaultMessage = "Boot failed: Umbraco cannot run. See Umbraco's log file for more details.";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Exception"/> class with a specified error message.
|
||||
/// Initializes a new instance of the <see cref="BootFailedException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error. </param>
|
||||
public BootFailedException()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Exception" /> class with a specified error message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public BootFailedException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Exception"/> class with a specified error message
|
||||
/// Initializes a new instance of the <see cref="Exception" /> class with a specified error message
|
||||
/// and a reference to the inner exception which is the cause of this exception.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error. </param>
|
||||
/// <param name="inner">The inner exception, or null.</param>
|
||||
public BootFailedException(string message, Exception inner)
|
||||
: base(message, inner)
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
/// <param name="innerException">The inner exception, or null.</param>
|
||||
public BootFailedException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Rethrows a captured <see cref="BootFailedException"/>.
|
||||
/// Initializes a new instance of the <see cref="BootFailedException" /> class.
|
||||
/// </summary>
|
||||
/// <remarks>The exception can be null, in which case a default message is used.</remarks>
|
||||
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> that holds the serialized object data about the exception being thrown.</param>
|
||||
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" /> that contains contextual information about the source or destination.</param>
|
||||
protected BootFailedException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Rethrows a captured <see cref="BootFailedException" />.
|
||||
/// </summary>
|
||||
/// <param name="bootFailedException">The boot failed exception.</param>
|
||||
/// <exception cref="Umbraco.Core.Exceptions.BootFailedException">
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// The exception can be null, in which case a default message is used.
|
||||
/// </remarks>
|
||||
public static void Rethrow(BootFailedException bootFailedException)
|
||||
{
|
||||
if (bootFailedException == null)
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Exceptions
|
||||
{
|
||||
internal class ConnectionException : Exception
|
||||
{
|
||||
public ConnectionException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,98 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Core.Exceptions
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <seealso cref="System.Exception" />
|
||||
[Serializable]
|
||||
internal class DataOperationException<T> : Exception
|
||||
where T : Enum
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the operation.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The operation.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// This object should be serializable to prevent a <see cref="SerializationException" /> to be thrown.
|
||||
/// </remarks>
|
||||
public T Operation { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DataOperationException{T}" /> class.
|
||||
/// </summary>
|
||||
public DataOperationException()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DataOperationException{T}" /> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public DataOperationException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DataOperationException{T}" /> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference (<see langword="Nothing" /> in Visual Basic) if no inner exception is specified.</param>
|
||||
public DataOperationException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DataOperationException{T}" /> class.
|
||||
/// </summary>
|
||||
/// <param name="operation">The operation.</param>
|
||||
public DataOperationException(T operation)
|
||||
: this(operation, "Data operation exception: " + operation)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DataOperationException{T}" /> class.
|
||||
/// </summary>
|
||||
/// <param name="operation">The operation.</param>
|
||||
/// <param name="message">The message.</param>
|
||||
public DataOperationException(T operation, string message)
|
||||
: base(message)
|
||||
{
|
||||
Operation = operation;
|
||||
}
|
||||
|
||||
public DataOperationException(T operation)
|
||||
: base("Data operation exception: " + operation)
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DataOperationException{T}" /> class.
|
||||
/// </summary>
|
||||
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> that holds the serialized object data about the exception being thrown.</param>
|
||||
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" /> that contains contextual information about the source or destination.</param>
|
||||
/// <exception cref="ArgumentNullException">info</exception>
|
||||
protected DataOperationException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{
|
||||
Operation = operation;
|
||||
Operation = (T)Enum.Parse(typeof(T), info.GetString(nameof(Operation)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When overridden in a derived class, sets the <see cref="T:System.Runtime.Serialization.SerializationInfo" /> with information about the exception.
|
||||
/// </summary>
|
||||
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> that holds the serialized object data about the exception being thrown.</param>
|
||||
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" /> that contains contextual information about the source or destination.</param>
|
||||
/// <exception cref="ArgumentNullException">info</exception>
|
||||
public override void GetObjectData(SerializationInfo info, StreamingContext context)
|
||||
{
|
||||
if (info == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(info));
|
||||
}
|
||||
|
||||
info.AddValue(nameof(Operation), Enum.GetName(typeof(T), Operation));
|
||||
|
||||
base.GetObjectData(info, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +1,126 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Core.Exceptions
|
||||
{
|
||||
/// <summary>
|
||||
/// The exception that is thrown when a composition is invalid.
|
||||
/// </summary>
|
||||
/// <seealso cref="System.Exception" />
|
||||
[Serializable]
|
||||
public class InvalidCompositionException : Exception
|
||||
{
|
||||
public InvalidCompositionException(string contentTypeAlias, string addedCompositionAlias, string[] propertyTypeAliass)
|
||||
{
|
||||
ContentTypeAlias = contentTypeAlias;
|
||||
AddedCompositionAlias = addedCompositionAlias;
|
||||
PropertyTypeAliases = propertyTypeAliass;
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the content type alias.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The content type alias.
|
||||
/// </value>
|
||||
public string ContentTypeAlias { get; }
|
||||
|
||||
public InvalidCompositionException(string contentTypeAlias, string[] propertyTypeAliass)
|
||||
{
|
||||
ContentTypeAlias = contentTypeAlias;
|
||||
PropertyTypeAliases = propertyTypeAliass;
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the added composition alias.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The added composition alias.
|
||||
/// </value>
|
||||
public string AddedCompositionAlias { get; }
|
||||
|
||||
public string ContentTypeAlias { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the property type aliases.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The property type aliases.
|
||||
/// </value>
|
||||
public string[] PropertyTypeAliases { get; }
|
||||
|
||||
public string AddedCompositionAlias { get; private set; }
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InvalidCompositionException" /> class.
|
||||
/// </summary>
|
||||
public InvalidCompositionException()
|
||||
{ }
|
||||
|
||||
public string[] PropertyTypeAliases { get; private set; }
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InvalidCompositionException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="contentTypeAlias">The content type alias.</param>
|
||||
/// <param name="propertyTypeAliases">The property type aliases.</param>
|
||||
public InvalidCompositionException(string contentTypeAlias, string[] propertyTypeAliases)
|
||||
: this(contentTypeAlias, null, propertyTypeAliases)
|
||||
{ }
|
||||
|
||||
public override string Message
|
||||
{
|
||||
get
|
||||
{
|
||||
return AddedCompositionAlias.IsNullOrWhiteSpace()
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InvalidCompositionException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="contentTypeAlias">The content type alias.</param>
|
||||
/// <param name="addedCompositionAlias">The added composition alias.</param>
|
||||
/// <param name="propertyTypeAliases">The property type aliases.</param>
|
||||
public InvalidCompositionException(string contentTypeAlias, string addedCompositionAlias, string[] propertyTypeAliases)
|
||||
: this(addedCompositionAlias.IsNullOrWhiteSpace()
|
||||
? string.Format(
|
||||
"ContentType with alias '{0}' has an invalid composition " +
|
||||
"and there was a conflict on the following PropertyTypes: '{1}'. " +
|
||||
"PropertyTypes must have a unique alias across all Compositions in order to compose a valid ContentType Composition.",
|
||||
ContentTypeAlias, string.Join(", ", PropertyTypeAliases))
|
||||
contentTypeAlias, string.Join(", ", propertyTypeAliases))
|
||||
: string.Format(
|
||||
"ContentType with alias '{0}' was added as a Composition to ContentType with alias '{1}', " +
|
||||
"but there was a conflict on the following PropertyTypes: '{2}'. " +
|
||||
"PropertyTypes must have a unique alias across all Compositions in order to compose a valid ContentType Composition.",
|
||||
AddedCompositionAlias, ContentTypeAlias, string.Join(", ", PropertyTypeAliases));
|
||||
addedCompositionAlias, contentTypeAlias, string.Join(", ", propertyTypeAliases)))
|
||||
{
|
||||
ContentTypeAlias = contentTypeAlias;
|
||||
AddedCompositionAlias = addedCompositionAlias;
|
||||
PropertyTypeAliases = propertyTypeAliases;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InvalidCompositionException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public InvalidCompositionException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InvalidCompositionException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference (<see langword="Nothing" /> in Visual Basic) if no inner exception is specified.</param>
|
||||
public InvalidCompositionException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InvalidCompositionException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> that holds the serialized object data about the exception being thrown.</param>
|
||||
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" /> that contains contextual information about the source or destination.</param>
|
||||
protected InvalidCompositionException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{
|
||||
ContentTypeAlias = info.GetString(nameof(ContentTypeAlias));
|
||||
AddedCompositionAlias = info.GetString(nameof(AddedCompositionAlias));
|
||||
PropertyTypeAliases = (string[])info.GetValue(nameof(PropertyTypeAliases), typeof(string[]));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When overridden in a derived class, sets the <see cref="T:System.Runtime.Serialization.SerializationInfo" /> with information about the exception.
|
||||
/// </summary>
|
||||
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> that holds the serialized object data about the exception being thrown.</param>
|
||||
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" /> that contains contextual information about the source or destination.</param>
|
||||
/// <exception cref="ArgumentNullException">info</exception>
|
||||
public override void GetObjectData(SerializationInfo info, StreamingContext context)
|
||||
{
|
||||
if (info == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(info));
|
||||
}
|
||||
|
||||
info.AddValue(nameof(ContentTypeAlias), ContentTypeAlias);
|
||||
info.AddValue(nameof(AddedCompositionAlias), AddedCompositionAlias);
|
||||
info.AddValue(nameof(PropertyTypeAliases), PropertyTypeAliases);
|
||||
|
||||
base.GetObjectData(info, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,25 +4,42 @@ using System.Runtime.Serialization;
|
||||
namespace Umbraco.Core.Exceptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Internal exception that in theory should never ben thrown, it is only thrown in circumstances that should never happen
|
||||
/// Represents an internal exception that in theory should never been thrown, it is only thrown in circumstances that should never happen.
|
||||
/// </summary>
|
||||
/// <seealso cref="System.Exception" />
|
||||
[Serializable]
|
||||
internal class PanicException : Exception
|
||||
public class PanicException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PanicException" /> class.
|
||||
/// </summary>
|
||||
public PanicException()
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
public PanicException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PanicException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public PanicException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
public PanicException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PanicException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference (<see langword="Nothing" /> in Visual Basic) if no inner exception is specified.</param>
|
||||
public PanicException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{ }
|
||||
|
||||
protected PanicException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PanicException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> that holds the serialized object data about the exception being thrown.</param>
|
||||
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" /> that contains contextual information about the source or destination.</param>
|
||||
protected PanicException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,52 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Core.Exceptions
|
||||
{
|
||||
/// <summary>
|
||||
/// The exception that is thrown when a requested method or operation is not, and will not be, implemented.
|
||||
/// </summary>
|
||||
/// <remarks>The <see cref="NotImplementedException"/> is to be used when some code is not implemented,
|
||||
/// <remarks>
|
||||
/// The <see cref="NotImplementedException" /> is to be used when some code is not implemented,
|
||||
/// but should eventually be implemented (i.e. work in progress) and is reported by tools such as ReSharper.
|
||||
/// This exception is to be used when some code is not implemented, and is not meant to be, for whatever
|
||||
/// reason.</remarks>
|
||||
/// reason.
|
||||
/// </remarks>
|
||||
/// <seealso cref="System.NotImplementedException" />
|
||||
[Serializable]
|
||||
[Obsolete("If a method or operation is not, and will not be, implemented, it is invalid or not supported, so we should throw either an InvalidOperationException or NotSupportedException instead.")]
|
||||
public class WontImplementException : NotImplementedException
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WontImplementException"/> class.
|
||||
/// Initializes a new instance of the <see cref="WontImplementException" /> class.
|
||||
/// </summary>
|
||||
public WontImplementException()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WontImplementException"/> class with a specified reason message.
|
||||
/// Initializes a new instance of the <see cref="WontImplementException" /> class with a specified reason message.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
public WontImplementException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WontImplementException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="inner">The exception that is the cause of the current exception. If the <paramref name="inner" /> parameter is not <see langword="null" />, the current exception is raised in a <see langword="catch" /> block that handles the inner exception.</param>
|
||||
public WontImplementException(string message, Exception inner)
|
||||
: base(message, inner)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WontImplementException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> that holds the serialized object data about the exception being thrown.</param>
|
||||
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" /> that contains contextual information about the source or destination.</param>
|
||||
protected WontImplementException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,46 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Core.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// The exception that is thrown when the caller does not have the required permission to access a file.
|
||||
/// </summary>
|
||||
/// <seealso cref="System.Exception" />
|
||||
[Obsolete("Throw an UnauthorizedAccessException instead.")]
|
||||
[Serializable]
|
||||
public class FileSecurityException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FileSecurityException" /> class.
|
||||
/// </summary>
|
||||
public FileSecurityException()
|
||||
{
|
||||
{ }
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FileSecurityException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public FileSecurityException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
public FileSecurityException(string message) : base(message)
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FileSecurityException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference (<see langword="Nothing" /> in Visual Basic) if no inner exception is specified.</param>
|
||||
public FileSecurityException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{ }
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FileSecurityException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> that holds the serialized object data about the exception being thrown.</param>
|
||||
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" /> that contains contextual information about the source or destination.</param>
|
||||
protected FileSecurityException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Media;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.IO
|
||||
@@ -92,7 +87,8 @@ namespace Umbraco.Core.IO
|
||||
{
|
||||
if (content == null) throw new ArgumentNullException(nameof(content));
|
||||
if (propertyType == null) throw new ArgumentNullException(nameof(propertyType));
|
||||
if (string.IsNullOrWhiteSpace(filename)) throw new ArgumentNullOrEmptyException(nameof(filename));
|
||||
if (filename == null) throw new ArgumentNullException(nameof(filename));
|
||||
if (string.IsNullOrWhiteSpace(filename)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(filename));
|
||||
if (filestream == null) throw new ArgumentNullException(nameof(filestream));
|
||||
|
||||
// clear the old file, if any
|
||||
@@ -111,7 +107,8 @@ namespace Umbraco.Core.IO
|
||||
{
|
||||
if (content == null) throw new ArgumentNullException(nameof(content));
|
||||
if (propertyType == null) throw new ArgumentNullException(nameof(propertyType));
|
||||
if (string.IsNullOrWhiteSpace(sourcepath)) throw new ArgumentNullOrEmptyException(nameof(sourcepath));
|
||||
if (sourcepath == null) throw new ArgumentNullException(nameof(sourcepath));
|
||||
if (string.IsNullOrWhiteSpace(sourcepath)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(sourcepath));
|
||||
|
||||
// ensure we have a file to copy
|
||||
if (FileExists(sourcepath) == false) return null;
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using System.Threading;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
@@ -39,9 +38,11 @@ namespace Umbraco.Core.IO
|
||||
|
||||
public PhysicalFileSystem(string rootPath, string rootUrl)
|
||||
{
|
||||
if (string.IsNullOrEmpty(rootPath)) throw new ArgumentNullOrEmptyException(nameof(rootPath));
|
||||
if (string.IsNullOrEmpty(rootUrl)) throw new ArgumentNullOrEmptyException(nameof(rootUrl));
|
||||
if (rootPath.StartsWith("~/")) throw new ArgumentException("The rootPath argument cannot be a virtual path and cannot start with '~/'");
|
||||
if (rootPath == null) throw new ArgumentNullException(nameof(rootPath));
|
||||
if (string.IsNullOrEmpty(rootPath)) throw new ArgumentException("Value can't be empty.", nameof(rootPath));
|
||||
if (rootUrl == null) throw new ArgumentNullException(nameof(rootUrl));
|
||||
if (string.IsNullOrEmpty(rootUrl)) throw new ArgumentException("Value can't be empty.", nameof(rootUrl));
|
||||
if (rootPath.StartsWith("~/")) throw new ArgumentException("Value can't be a virtual path and start with '~/'.", nameof(rootPath));
|
||||
|
||||
// rootPath should be... rooted, as in, it's a root path!
|
||||
if (Path.IsPathRooted(rootPath) == false)
|
||||
@@ -314,7 +315,7 @@ namespace Umbraco.Core.IO
|
||||
|
||||
// nothing prevents us to reach the file, security-wise, yet it is outside
|
||||
// this filesystem's root - throw
|
||||
throw new FileSecurityException("File '" + opath + "' is outside this filesystem's root.");
|
||||
throw new UnauthorizedAccessException("File '" + opath + "' is outside this filesystem's root.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading;
|
||||
using System.Web.Hosting;
|
||||
using Umbraco.Core.Logging;
|
||||
@@ -65,7 +65,7 @@ namespace Umbraco.Core
|
||||
// a new process for the same application path
|
||||
|
||||
var appPath = HostingEnvironment.ApplicationPhysicalPath;
|
||||
var hash = (appId + ":::" + appPath).ToSHA1();
|
||||
var hash = (appId + ":::" + appPath).GenerateHash<SHA1>();
|
||||
|
||||
var lockName = "UMBRACO-" + hash + "-MAINDOM-LCK";
|
||||
_asyncLock = new AsyncLock(lockName);
|
||||
|
||||
@@ -5,7 +5,6 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
@@ -42,7 +41,8 @@ namespace Umbraco.Core.Manifest
|
||||
_cache = appCaches.RuntimeCache;
|
||||
_validators = validators ?? throw new ArgumentNullException(nameof(validators));
|
||||
_filters = filters ?? throw new ArgumentNullException(nameof(filters));
|
||||
if (string.IsNullOrWhiteSpace(path)) throw new ArgumentNullOrEmptyException(nameof(path));
|
||||
if (path == null) throw new ArgumentNullException(nameof(path));
|
||||
if (string.IsNullOrWhiteSpace(path)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(path));
|
||||
Path = path;
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
@@ -155,8 +155,8 @@ namespace Umbraco.Core.Manifest
|
||||
/// </summary>
|
||||
internal PackageManifest ParseManifest(string text)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
throw new ArgumentNullOrEmptyException(nameof(text));
|
||||
if (text == null) throw new ArgumentNullException(nameof(text));
|
||||
if (string.IsNullOrWhiteSpace(text)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(text));
|
||||
|
||||
var manifest = JsonConvert.DeserializeObject<PackageManifest>(text,
|
||||
new DataEditorConverter(_logger),
|
||||
|
||||
@@ -343,16 +343,20 @@ namespace Umbraco.Core.Mapping
|
||||
|
||||
if (ctor == null) return null;
|
||||
|
||||
if (_ctors.ContainsKey(sourceType))
|
||||
_ctors.AddOrUpdate(sourceType, sourceCtor, (k, v) =>
|
||||
{
|
||||
// Add missing constructors
|
||||
foreach (var c in sourceCtor)
|
||||
{
|
||||
if (!_ctors[sourceType].TryGetValue(c.Key, out _))
|
||||
_ctors[sourceType].Add(c.Key, c.Value);
|
||||
}
|
||||
}
|
||||
else
|
||||
_ctors[sourceType] = sourceCtor;
|
||||
if (!v.ContainsKey(c.Key))
|
||||
{
|
||||
v.Add(c.Key, c.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return v;
|
||||
});
|
||||
|
||||
|
||||
return ctor;
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Migrations
|
||||
{
|
||||
/// <summary>
|
||||
/// Used if a migration has executed but the whole process has failed and cannot be rolled back
|
||||
/// </summary>
|
||||
internal class DataLossException : Exception
|
||||
{
|
||||
public DataLossException(string msg)
|
||||
: base(msg)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public DataLossException(string msg, Exception inner)
|
||||
: base(msg, inner)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using Umbraco.Core.Exceptions;
|
||||
using System;
|
||||
using Umbraco.Core.Migrations.Expressions.Common;
|
||||
using Umbraco.Core.Migrations.Expressions.Delete.Column;
|
||||
using Umbraco.Core.Migrations.Expressions.Delete.Constraint;
|
||||
@@ -39,8 +39,9 @@ namespace Umbraco.Core.Migrations.Expressions.Delete
|
||||
/// <inheritdoc />
|
||||
public IExecutableBuilder KeysAndIndexes(string tableName, bool local = true, bool foreign = true)
|
||||
{
|
||||
if (tableName.IsNullOrWhiteSpace())
|
||||
throw new ArgumentNullOrEmptyException(nameof(tableName));
|
||||
if (tableName == null) throw new ArgumentNullException(nameof(tableName));
|
||||
if (string.IsNullOrWhiteSpace(tableName)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(tableName));
|
||||
|
||||
return new DeleteKeysAndIndexesBuilder(_context) { TableName = tableName, DeleteLocal = local, DeleteForeign = foreign };
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +1,49 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Core.Migrations
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents errors that occurs when a migration exception is not executed.
|
||||
/// The exception that is thrown when a migration expression is not executed.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Migration expression such as Alter.Table(...).Do() *must* end with Do() else they are
|
||||
/// not executed. When a non-executed expression is detected, an IncompleteMigrationExpressionException
|
||||
/// is thrown.</para>
|
||||
/// Migration expressions such as Alter.Table(...).Do() must end with Do(), else they are not executed.
|
||||
/// When a non-executed expression is detected, an IncompleteMigrationExpressionException is thrown.
|
||||
/// </remarks>
|
||||
/// <seealso cref="System.Exception" />
|
||||
[Serializable]
|
||||
public class IncompleteMigrationExpressionException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="IncompleteMigrationExpressionException"/> class.
|
||||
/// Initializes a new instance of the <see cref="IncompleteMigrationExpressionException" /> class.
|
||||
/// </summary>
|
||||
public IncompleteMigrationExpressionException()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="IncompleteMigrationExpressionException"/> class with a message.
|
||||
/// Initializes a new instance of the <see cref="IncompleteMigrationExpressionException" /> class with a message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public IncompleteMigrationExpressionException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="IncompleteMigrationExpressionException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference (<see langword="Nothing" /> in Visual Basic) if no inner exception is specified.</param>
|
||||
public IncompleteMigrationExpressionException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="IncompleteMigrationExpressionException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> that holds the serialized object data about the exception being thrown.</param>
|
||||
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" /> that contains contextual information about the source or destination.</param>
|
||||
protected IncompleteMigrationExpressionException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Migrations.Upgrade;
|
||||
@@ -278,8 +277,10 @@ namespace Umbraco.Core.Migrations.Install
|
||||
/// <param name="logger">A logger.</param>
|
||||
private static void SaveConnectionString(string connectionString, string providerName, ILogger logger)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(connectionString)) throw new ArgumentNullOrEmptyException(nameof(connectionString));
|
||||
if (string.IsNullOrWhiteSpace(providerName)) throw new ArgumentNullOrEmptyException(nameof(providerName));
|
||||
if (connectionString == null) throw new ArgumentNullException(nameof(connectionString));
|
||||
if (string.IsNullOrWhiteSpace(connectionString)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(connectionString));
|
||||
if (providerName == null) throw new ArgumentNullException(nameof(providerName));
|
||||
if (string.IsNullOrWhiteSpace(providerName)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(providerName));
|
||||
|
||||
var fileSource = "web.config";
|
||||
var fileName = IOHelper.MapPath(SystemDirectories.Root +"/" + fileSource);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Type = System.Type;
|
||||
@@ -25,7 +24,9 @@ namespace Umbraco.Core.Migrations
|
||||
/// <param name="name">The name of the plan.</param>
|
||||
public MigrationPlan(string name)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullOrEmptyException(nameof(name));
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(name));
|
||||
|
||||
Name = name;
|
||||
}
|
||||
|
||||
@@ -43,7 +44,8 @@ namespace Umbraco.Core.Migrations
|
||||
private MigrationPlan Add(string sourceState, string targetState, Type migration)
|
||||
{
|
||||
if (sourceState == null) throw new ArgumentNullException(nameof(sourceState));
|
||||
if (string.IsNullOrWhiteSpace(targetState)) throw new ArgumentNullOrEmptyException(nameof(targetState));
|
||||
if (targetState == null) throw new ArgumentNullException(nameof(targetState));
|
||||
if (string.IsNullOrWhiteSpace(targetState)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(targetState));
|
||||
if (sourceState == targetState) throw new ArgumentException("Source and target state cannot be identical.");
|
||||
if (migration == null) throw new ArgumentNullException(nameof(migration));
|
||||
if (!migration.Implements<IMigration>()) throw new ArgumentException($"Type {migration.Name} does not implement IMigration.", nameof(migration));
|
||||
@@ -135,10 +137,12 @@ namespace Umbraco.Core.Migrations
|
||||
/// </summary>
|
||||
public MigrationPlan ToWithClone(string startState, string endState, string targetState)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(startState)) throw new ArgumentNullOrEmptyException(nameof(startState));
|
||||
if (string.IsNullOrWhiteSpace(endState)) throw new ArgumentNullOrEmptyException(nameof(endState));
|
||||
if (string.IsNullOrWhiteSpace(targetState)) throw new ArgumentNullOrEmptyException(nameof(targetState));
|
||||
|
||||
if (startState == null) throw new ArgumentNullException(nameof(startState));
|
||||
if (string.IsNullOrWhiteSpace(startState)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(startState));
|
||||
if (endState == null) throw new ArgumentNullException(nameof(endState));
|
||||
if (string.IsNullOrWhiteSpace(endState)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(endState));
|
||||
if (targetState == null) throw new ArgumentNullException(nameof(targetState));
|
||||
if (string.IsNullOrWhiteSpace(targetState)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(targetState));
|
||||
if (startState == endState) throw new ArgumentException("Start and end states cannot be identical.");
|
||||
|
||||
startState = startState.Trim();
|
||||
@@ -317,7 +321,7 @@ namespace Umbraco.Core.Migrations
|
||||
// throw a raw exception here: this should never happen as the plan has
|
||||
// been validated - this is just a paranoid safety test
|
||||
if (!_transitions.TryGetValue(origState, out transition))
|
||||
throw new Exception($"Unknown state \"{origState}\".");
|
||||
throw new InvalidOperationException($"Unknown state \"{origState}\".");
|
||||
}
|
||||
|
||||
// prepare and de-duplicate post-migrations, only keeping the 1st occurence
|
||||
@@ -339,7 +343,7 @@ namespace Umbraco.Core.Migrations
|
||||
// safety check - again, this should never happen as the plan has been validated,
|
||||
// and this is just a paranoid safety test
|
||||
if (origState != _finalState)
|
||||
throw new Exception($"Internal error, reached state {origState} which is not final state {_finalState}");
|
||||
throw new InvalidOperationException($"Internal error, reached state {origState} which is not final state {_finalState}");
|
||||
|
||||
return origState;
|
||||
}
|
||||
@@ -358,7 +362,7 @@ namespace Umbraco.Core.Migrations
|
||||
var states = new List<string> { origState };
|
||||
|
||||
if (!_transitions.TryGetValue(origState, out var transition))
|
||||
throw new Exception($"Unknown state \"{origState}\".");
|
||||
throw new InvalidOperationException($"Unknown state \"{origState}\".");
|
||||
|
||||
while (transition != null)
|
||||
{
|
||||
@@ -373,12 +377,12 @@ namespace Umbraco.Core.Migrations
|
||||
}
|
||||
|
||||
if (!_transitions.TryGetValue(origState, out transition))
|
||||
throw new Exception($"Unknown state \"{origState}\".");
|
||||
throw new InvalidOperationException($"Unknown state \"{origState}\".");
|
||||
}
|
||||
|
||||
// safety check
|
||||
if (origState != (toState ?? _finalState))
|
||||
throw new Exception($"Internal error, reached state {origState} which is not state {toState ?? _finalState}");
|
||||
throw new InvalidOperationException($"Internal error, reached state {origState} which is not state {toState ?? _finalState}");
|
||||
|
||||
return states;
|
||||
}
|
||||
@@ -417,7 +421,7 @@ namespace Umbraco.Core.Migrations
|
||||
public override string ToString()
|
||||
{
|
||||
return MigrationType == typeof(NoopMigration)
|
||||
? $"{(SourceState == "" ? "<empty>" : SourceState)} --> {TargetState}"
|
||||
? $"{(SourceState == string.Empty ? "<empty>" : SourceState)} --> {TargetState}"
|
||||
: $"{SourceState} -- ({MigrationType.FullName}) --> {TargetState}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using Umbraco.Core.Migrations.Upgrade.Common;
|
||||
using Umbraco.Core.Migrations.Upgrade.V_8_0_0;
|
||||
using Umbraco.Core.Migrations.Upgrade.V_8_0_1;
|
||||
using Umbraco.Core.Migrations.Upgrade.V_8_1_0;
|
||||
using Umbraco.Core.Migrations.Upgrade.V_8_6_0;
|
||||
|
||||
namespace Umbraco.Core.Migrations.Upgrade
|
||||
{
|
||||
@@ -182,6 +183,9 @@ namespace Umbraco.Core.Migrations.Upgrade
|
||||
To<RenameUserLoginDtoDateIndex>("{0372A42B-DECF-498D-B4D1-6379E907EB94}");
|
||||
To<FixContentNuCascade>("{5B1E0D93-F5A3-449B-84BA-65366B84E2D4}");
|
||||
|
||||
// to 8.6.0
|
||||
To<AddPropertyTypeValidationMessageColumns>("{3D67D2C8-5E65-47D0-A9E1-DC2EE0779D6B}");
|
||||
|
||||
//FINAL
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,9 +74,18 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
|
||||
.From<DataTypeDto>()
|
||||
.Where<DataTypeDto>(x => x.NodeId == group.Key)).First();
|
||||
|
||||
// check for duplicate aliases
|
||||
var aliases = group.Select(x => x.Alias).Where(x => !string.IsNullOrWhiteSpace(x)).ToArray();
|
||||
if (aliases.Distinct().Count() != aliases.Length)
|
||||
throw new InvalidOperationException($"Cannot migrate prevalues for datatype id={dataType.NodeId}, editor={dataType.EditorAlias}: duplicate alias.");
|
||||
|
||||
// handle null/empty aliases
|
||||
int index = 0;
|
||||
var dictionary = group.ToDictionary(x => string.IsNullOrWhiteSpace(x.Alias) ? index++.ToString() : x.Alias);
|
||||
|
||||
// migrate the preValues to configuration
|
||||
var migrator = _preValueMigrators.GetMigrator(dataType.EditorAlias) ?? new DefaultPreValueMigrator();
|
||||
var config = migrator.GetConfiguration(dataType.NodeId, dataType.EditorAlias, group.ToDictionary(x => x.Alias, x => x));
|
||||
var config = migrator.GetConfiguration(dataType.NodeId, dataType.EditorAlias, dictionary);
|
||||
var json = JsonConvert.SerializeObject(config);
|
||||
|
||||
// validate - and kill the migration if it fails
|
||||
|
||||
@@ -24,8 +24,8 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
|
||||
}
|
||||
|
||||
// assuming we don't want to fall back to array
|
||||
if (aliases.Length != preValuesA.Count || aliases.Any(string.IsNullOrWhiteSpace))
|
||||
throw new InvalidOperationException($"Cannot migrate datatype w/ id={dataTypeId} preValues: duplicate or null/empty alias.");
|
||||
if (aliases.Any(string.IsNullOrWhiteSpace))
|
||||
throw new InvalidOperationException($"Cannot migrate prevalues for datatype id={dataTypeId}, editor={editorAlias}: null/empty alias.");
|
||||
|
||||
// dictionary-base prevalues
|
||||
return GetPreValues(preValuesA).ToDictionary(x => x.Alias, GetPreValueValue);
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
|
||||
namespace Umbraco.Core.Migrations.Upgrade.V_8_6_0
|
||||
{
|
||||
public class AddPropertyTypeValidationMessageColumns : MigrationBase
|
||||
{
|
||||
public AddPropertyTypeValidationMessageColumns(IMigrationContext context)
|
||||
: base(context)
|
||||
{ }
|
||||
|
||||
public override void Migrate()
|
||||
{
|
||||
var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToList();
|
||||
|
||||
AddColumnIfNotExists<PropertyTypeDto>(columns, "mandatoryMessage");
|
||||
AddColumnIfNotExists<PropertyTypeDto>(columns, "validationRegExpMessage");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,6 @@ using System.Collections.Specialized;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
@@ -229,8 +227,8 @@ namespace Umbraco.Core.Models
|
||||
|
||||
private void ClearCultureInfo(string culture)
|
||||
{
|
||||
if (culture.IsNullOrWhiteSpace())
|
||||
throw new ArgumentNullOrEmptyException(nameof(culture));
|
||||
if (culture == null) throw new ArgumentNullException(nameof(culture));
|
||||
if (string.IsNullOrWhiteSpace(culture)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(culture));
|
||||
|
||||
if (_cultureInfos == null) return;
|
||||
_cultureInfos.Remove(culture);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
@@ -18,7 +17,9 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
public ContentCultureInfos(string culture)
|
||||
{
|
||||
if (culture.IsNullOrWhiteSpace()) throw new ArgumentNullOrEmptyException(nameof(culture));
|
||||
if (culture == null) throw new ArgumentNullException(nameof(culture));
|
||||
if (string.IsNullOrWhiteSpace(culture)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(culture));
|
||||
|
||||
Culture = culture;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using Umbraco.Core.Collections;
|
||||
using Umbraco.Core.Exceptions;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -23,7 +21,9 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
public void AddOrUpdate(string culture, string name, DateTime date)
|
||||
{
|
||||
if (culture.IsNullOrWhiteSpace()) throw new ArgumentNullOrEmptyException(nameof(culture));
|
||||
if (culture == null) throw new ArgumentNullException(nameof(culture));
|
||||
if (string.IsNullOrWhiteSpace(culture)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(culture));
|
||||
|
||||
culture = culture.ToLowerInvariant();
|
||||
|
||||
if (TryGetValue(culture, out var item))
|
||||
|
||||
@@ -67,6 +67,12 @@ namespace Umbraco.Core.Models.ContentEditing
|
||||
/// </remarks>
|
||||
[DataMember(Name = "active")]
|
||||
public bool Active { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the content app badge.
|
||||
/// </summary>
|
||||
[DataMember(Name = "badge")]
|
||||
public ContentAppBadge Badge { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
namespace Umbraco.Core.Models.ContentEditing
|
||||
{
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
using Umbraco.Core.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a content app badge
|
||||
/// </summary>
|
||||
[DataContract(Name = "badge", Namespace = "")]
|
||||
public class ContentAppBadge
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ContentAppBadge"/> class.
|
||||
/// </summary>
|
||||
public ContentAppBadge()
|
||||
{
|
||||
this.Type = ContentAppBadgeType.Default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the number displayed in the badge
|
||||
/// </summary>
|
||||
[DataMember(Name = "count")]
|
||||
public int Count { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type of badge to display
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>This controls the background color of the badge.</para>
|
||||
/// <para>Warning will display a dark yellow badge</para>
|
||||
/// <para>Alert will display a red badge</para>
|
||||
/// <para>Default will display a turquoise badge</para>
|
||||
/// </remarks>
|
||||
[DataMember(Name = "type")]
|
||||
public ContentAppBadgeType Type { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace Umbraco.Core.Models.ContentEditing
|
||||
{
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
/// <summary>
|
||||
/// Represent the content app badge types
|
||||
/// </summary>
|
||||
[DataContract(Name = "contentAppBadgeType")]
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum ContentAppBadgeType
|
||||
{
|
||||
[EnumMember(Value = "default")]
|
||||
Default = 0,
|
||||
|
||||
[EnumMember(Value = "warning")]
|
||||
Warning = 1,
|
||||
|
||||
[EnumMember(Value = "alert")]
|
||||
Alert = 2
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Exceptions;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -103,11 +102,11 @@ namespace Umbraco.Core.Models
|
||||
|
||||
public static void SetPublishInfo(this IContent content, string culture, string name, DateTime date)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
throw new ArgumentNullOrEmptyException(nameof(name));
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(name));
|
||||
|
||||
if (culture.IsNullOrWhiteSpace())
|
||||
throw new ArgumentNullOrEmptyException(nameof(culture));
|
||||
if (culture == null) throw new ArgumentNullException(nameof(culture));
|
||||
if (string.IsNullOrWhiteSpace(culture)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(culture));
|
||||
|
||||
content.PublishCultureInfos.AddOrUpdate(culture, name, date);
|
||||
}
|
||||
@@ -153,11 +152,11 @@ namespace Umbraco.Core.Models
|
||||
|
||||
public static void SetCultureInfo(this IContentBase content, string culture, string name, DateTime date)
|
||||
{
|
||||
if (name.IsNullOrWhiteSpace())
|
||||
throw new ArgumentNullOrEmptyException(nameof(name));
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(name));
|
||||
|
||||
if (culture.IsNullOrWhiteSpace())
|
||||
throw new ArgumentNullOrEmptyException(nameof(culture));
|
||||
if (culture == null) throw new ArgumentNullException(nameof(culture));
|
||||
if (string.IsNullOrWhiteSpace(culture)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(culture));
|
||||
|
||||
content.CultureInfos.AddOrUpdate(culture, name, date);
|
||||
}
|
||||
@@ -276,8 +275,8 @@ namespace Umbraco.Core.Models
|
||||
/// <returns></returns>
|
||||
public static bool ClearPublishInfo(this IContent content, string culture)
|
||||
{
|
||||
if (culture.IsNullOrWhiteSpace())
|
||||
throw new ArgumentNullOrEmptyException(nameof(culture));
|
||||
if (culture == null) throw new ArgumentNullException(nameof(culture));
|
||||
if (string.IsNullOrWhiteSpace(culture)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(culture));
|
||||
|
||||
var removed = content.PublishCultureInfos.Remove(culture);
|
||||
if (removed)
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace Umbraco.Core.Models.Entities
|
||||
public int ParentId { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetParent(ITreeEntity parent) => throw new WontImplementException();
|
||||
public void SetParent(ITreeEntity parent) => throw new InvalidOperationException("This property won't be implemented.");
|
||||
|
||||
/// <inheritdoc />
|
||||
[DataMember]
|
||||
@@ -116,7 +116,7 @@ namespace Umbraco.Core.Models.Entities
|
||||
/// <inheritdoc />
|
||||
public object DeepClone()
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -128,47 +128,47 @@ namespace Umbraco.Core.Models.Entities
|
||||
|
||||
public bool IsDirty()
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
public bool IsPropertyDirty(string propName)
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetDirtyProperties()
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
public void ResetDirtyProperties()
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
public bool WasDirty()
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
public bool WasPropertyDirty(string propertyName)
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
public void ResetWereDirtyProperties()
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
public void ResetDirtyProperties(bool rememberDirty)
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetWereDirtyProperties()
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
@@ -43,7 +42,8 @@ namespace Umbraco.Core.Models
|
||||
public Member(string name, IMemberType contentType)
|
||||
: base(name, -1, contentType, new PropertyCollection())
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullOrEmptyException(nameof(name));
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(name));
|
||||
|
||||
IsApproved = true;
|
||||
|
||||
@@ -63,9 +63,12 @@ namespace Umbraco.Core.Models
|
||||
public Member(string name, string email, string username, IMemberType contentType, bool isApproved = true)
|
||||
: base(name, -1, contentType, new PropertyCollection())
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(email)) throw new ArgumentNullOrEmptyException(nameof(email));
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullOrEmptyException(nameof(name));
|
||||
if (string.IsNullOrWhiteSpace(username)) throw new ArgumentNullOrEmptyException(nameof(username));
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(name));
|
||||
if (email == null) throw new ArgumentNullException(nameof(email));
|
||||
if (string.IsNullOrWhiteSpace(email)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(email));
|
||||
if (username == null) throw new ArgumentNullException(nameof(username));
|
||||
if (string.IsNullOrWhiteSpace(username)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(username));
|
||||
|
||||
_email = email;
|
||||
_username = username;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
@@ -9,7 +8,7 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
[DataContract(Name = "pagedCollection", Namespace = "")]
|
||||
public class PagedResult<T>
|
||||
public abstract class PagedResult
|
||||
{
|
||||
public PagedResult(long totalItems, long pageNumber, long pageSize)
|
||||
{
|
||||
@@ -39,9 +38,6 @@ namespace Umbraco.Core.Models
|
||||
[DataMember(Name = "totalItems")]
|
||||
public long TotalItems { get; private set; }
|
||||
|
||||
[DataMember(Name = "items")]
|
||||
public IEnumerable<T> Items { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the skip size based on the paged parameters specified
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a paged result for a model collection
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
[DataContract(Name = "pagedCollection", Namespace = "")]
|
||||
public class PagedResult<T> : PagedResult
|
||||
{
|
||||
public PagedResult(long totalItems, long pageNumber, long pageSize)
|
||||
: base(totalItems, pageNumber, pageSize)
|
||||
{ }
|
||||
|
||||
[DataMember(Name = "items")]
|
||||
public IEnumerable<T> Items { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -26,8 +26,10 @@ namespace Umbraco.Core.Models
|
||||
private string _propertyEditorAlias;
|
||||
private ValueStorageType _valueStorageType;
|
||||
private bool _mandatory;
|
||||
private string _mandatoryMessage;
|
||||
private int _sortOrder;
|
||||
private string _validationRegExp;
|
||||
private string _validationRegExpMessage;
|
||||
private ContentVariation _variations;
|
||||
|
||||
/// <summary>
|
||||
@@ -183,7 +185,7 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets of sets a value indicating whether a value for this property type is required.
|
||||
/// Gets or sets a value indicating whether a value for this property type is required.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public bool Mandatory
|
||||
@@ -192,6 +194,16 @@ namespace Umbraco.Core.Models
|
||||
set => SetPropertyValueAndDetectChanges(value, ref _mandatory, nameof(Mandatory));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the custom validation message used when a value for this PropertyType is required
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string MandatoryMessage
|
||||
{
|
||||
get => _mandatoryMessage;
|
||||
set => SetPropertyValueAndDetectChanges(value, ref _mandatoryMessage, nameof(MandatoryMessage));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets of sets the sort order of the property type.
|
||||
/// </summary>
|
||||
@@ -212,6 +224,16 @@ namespace Umbraco.Core.Models
|
||||
set => SetPropertyValueAndDetectChanges(value, ref _validationRegExp, nameof(ValidationRegExp));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the custom validation message used when a pattern for this PropertyType must be matched
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string ValidationRegExpMessage
|
||||
{
|
||||
get => _validationRegExpMessage;
|
||||
set => SetPropertyValueAndDetectChanges(value, ref _validationRegExpMessage, nameof(ValidationRegExpMessage));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the content variation of the property type.
|
||||
/// </summary>
|
||||
|
||||
@@ -20,7 +20,9 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
private ModelType(string contentTypeAlias)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(contentTypeAlias)) throw new ArgumentNullOrEmptyException(nameof(contentTypeAlias));
|
||||
if (contentTypeAlias == null) throw new ArgumentNullException(nameof(contentTypeAlias));
|
||||
if (string.IsNullOrWhiteSpace(contentTypeAlias)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(contentTypeAlias));
|
||||
|
||||
ContentTypeAlias = contentTypeAlias;
|
||||
Name = "{" + ContentTypeAlias + "}";
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using Umbraco.Core.Exceptions;
|
||||
|
||||
namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
@@ -13,7 +12,8 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
/// </summary>
|
||||
public PublishedCultureInfo(string culture, string name, string urlSegment, DateTime date)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullOrEmptyException(nameof(name));
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(name));
|
||||
|
||||
Culture = culture ?? throw new ArgumentNullException(nameof(culture));
|
||||
Name = name;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using Umbraco.Core.Exceptions;
|
||||
|
||||
namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
@@ -19,7 +18,9 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
/// <param name="contentTypeAlias">The content type alias.</param>
|
||||
public PublishedModelAttribute(string contentTypeAlias)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(contentTypeAlias)) throw new ArgumentNullOrEmptyException(nameof(contentTypeAlias));
|
||||
if (contentTypeAlias == null) throw new ArgumentNullException(nameof(contentTypeAlias));
|
||||
if (string.IsNullOrWhiteSpace(contentTypeAlias)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(contentTypeAlias));
|
||||
|
||||
ContentTypeAlias = contentTypeAlias;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
@@ -20,7 +19,9 @@ namespace Umbraco.Core.Models
|
||||
|
||||
public RelationType(Guid childObjectType, Guid parentObjectType, string alias)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(alias)) throw new ArgumentNullOrEmptyException(nameof(alias));
|
||||
if (alias == null) throw new ArgumentNullException(nameof(alias));
|
||||
if (string.IsNullOrWhiteSpace(alias)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(alias));
|
||||
|
||||
_childObjectType = childObjectType;
|
||||
_parentObjectType = parentObjectType;
|
||||
_alias = alias;
|
||||
@@ -30,7 +31,9 @@ namespace Umbraco.Core.Models
|
||||
public RelationType(Guid childObjectType, Guid parentObjectType, string alias, string name)
|
||||
: this(childObjectType, parentObjectType, alias)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullOrEmptyException(nameof(name));
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(name));
|
||||
|
||||
Name = name;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace Umbraco.Core.Models
|
||||
|
||||
if (user.Avatar.IsNullOrWhiteSpace())
|
||||
{
|
||||
var gravatarHash = user.Email.ToMd5();
|
||||
var gravatarHash = user.Email.GenerateHash<MD5>();
|
||||
var gravatarUrl = "https://www.gravatar.com/avatar/" + gravatarHash + "?d=404";
|
||||
|
||||
//try Gravatar
|
||||
|
||||
@@ -542,7 +542,7 @@ namespace Umbraco.Core
|
||||
{
|
||||
return "\"{0}\"".InvariantFormat(obj);
|
||||
}
|
||||
if (obj is int || obj is Int16 || obj is Int64 || obj is float || obj is double || obj is bool || obj is int? || obj is Int16? || obj is Int64? || obj is float? || obj is double? || obj is bool?)
|
||||
if (obj is int || obj is short || obj is long || obj is float || obj is double || obj is bool || obj is int? || obj is float? || obj is double? || obj is bool?)
|
||||
{
|
||||
return "{0}".InvariantFormat(obj);
|
||||
}
|
||||
@@ -723,7 +723,7 @@ namespace Umbraco.Core
|
||||
{
|
||||
return typeConverter;
|
||||
}
|
||||
|
||||
|
||||
var converter = TypeDescriptor.GetConverter(target);
|
||||
if (converter.CanConvertFrom(source))
|
||||
{
|
||||
@@ -788,6 +788,6 @@ namespace Umbraco.Core
|
||||
return BoolConvertCache[type] = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -787,7 +787,14 @@ namespace Umbraco.Core.Packaging
|
||||
Mandatory = property.Element("Mandatory") != null
|
||||
? property.Element("Mandatory").Value.ToLowerInvariant().Equals("true")
|
||||
: false,
|
||||
MandatoryMessage = property.Element("MandatoryMessage") != null
|
||||
? (string)property.Element("MandatoryMessage")
|
||||
: string.Empty,
|
||||
|
||||
ValidationRegExp = (string)property.Element("Validation"),
|
||||
ValidationRegExpMessage = property.Element("ValidationRegExpMessage") != null
|
||||
? (string)property.Element("ValidationRegExpMessage")
|
||||
: string.Empty,
|
||||
SortOrder = sortOrder,
|
||||
Variations = property.Element("Variations") != null
|
||||
? (ContentVariation)Enum.Parse(typeof(ContentVariation), property.Element("Variations").Value)
|
||||
|
||||
@@ -470,7 +470,7 @@ namespace Umbraco.Core.Persistence
|
||||
break;
|
||||
|
||||
case SqlDbType.SmallInt:
|
||||
dataType = typeof(Int16);
|
||||
dataType = typeof(short);
|
||||
dataTypeName = "smallint";
|
||||
break;
|
||||
|
||||
@@ -688,34 +688,34 @@ namespace Umbraco.Core.Persistence
|
||||
|
||||
DataColumnCollection columns = _schemaTable.Columns;
|
||||
|
||||
columns.Add(SchemaTableColumn.ColumnName, typeof(System.String));
|
||||
columns.Add(SchemaTableColumn.ColumnOrdinal, typeof(System.Int32));
|
||||
columns.Add(SchemaTableColumn.ColumnSize, typeof(System.Int32));
|
||||
columns.Add(SchemaTableColumn.NumericPrecision, typeof(System.Int16));
|
||||
columns.Add(SchemaTableColumn.NumericScale, typeof(System.Int16));
|
||||
columns.Add(SchemaTableColumn.IsUnique, typeof(System.Boolean));
|
||||
columns.Add(SchemaTableColumn.IsKey, typeof(System.Boolean));
|
||||
columns.Add(SchemaTableOptionalColumn.BaseServerName, typeof(System.String));
|
||||
columns.Add(SchemaTableOptionalColumn.BaseCatalogName, typeof(System.String));
|
||||
columns.Add(SchemaTableColumn.BaseColumnName, typeof(System.String));
|
||||
columns.Add(SchemaTableColumn.BaseSchemaName, typeof(System.String));
|
||||
columns.Add(SchemaTableColumn.BaseTableName, typeof(System.String));
|
||||
columns.Add(SchemaTableColumn.DataType, typeof(System.Type));
|
||||
columns.Add(SchemaTableColumn.AllowDBNull, typeof(System.Boolean));
|
||||
columns.Add(SchemaTableColumn.ProviderType, typeof(System.Int32));
|
||||
columns.Add(SchemaTableColumn.IsAliased, typeof(System.Boolean));
|
||||
columns.Add(SchemaTableColumn.IsExpression, typeof(System.Boolean));
|
||||
columns.Add(BulkDataReader.IsIdentitySchemaColumn, typeof(System.Boolean));
|
||||
columns.Add(SchemaTableOptionalColumn.IsAutoIncrement, typeof(System.Boolean));
|
||||
columns.Add(SchemaTableOptionalColumn.IsRowVersion, typeof(System.Boolean));
|
||||
columns.Add(SchemaTableOptionalColumn.IsHidden, typeof(System.Boolean));
|
||||
columns.Add(SchemaTableColumn.IsLong, typeof(System.Boolean));
|
||||
columns.Add(SchemaTableOptionalColumn.IsReadOnly, typeof(System.Boolean));
|
||||
columns.Add(SchemaTableOptionalColumn.ProviderSpecificDataType, typeof(System.Type));
|
||||
columns.Add(BulkDataReader.DataTypeNameSchemaColumn, typeof(System.String));
|
||||
columns.Add(BulkDataReader.XmlSchemaCollectionDatabaseSchemaColumn, typeof(System.String));
|
||||
columns.Add(BulkDataReader.XmlSchemaCollectionOwningSchemaSchemaColumn, typeof(System.String));
|
||||
columns.Add(BulkDataReader.XmlSchemaCollectionNameSchemaColumn, typeof(System.String));
|
||||
columns.Add(SchemaTableColumn.ColumnName, typeof(string));
|
||||
columns.Add(SchemaTableColumn.ColumnOrdinal, typeof(int));
|
||||
columns.Add(SchemaTableColumn.ColumnSize, typeof(int));
|
||||
columns.Add(SchemaTableColumn.NumericPrecision, typeof(short));
|
||||
columns.Add(SchemaTableColumn.NumericScale, typeof(short));
|
||||
columns.Add(SchemaTableColumn.IsUnique, typeof(bool));
|
||||
columns.Add(SchemaTableColumn.IsKey, typeof(bool));
|
||||
columns.Add(SchemaTableOptionalColumn.BaseServerName, typeof(string));
|
||||
columns.Add(SchemaTableOptionalColumn.BaseCatalogName, typeof(string));
|
||||
columns.Add(SchemaTableColumn.BaseColumnName, typeof(string));
|
||||
columns.Add(SchemaTableColumn.BaseSchemaName, typeof(string));
|
||||
columns.Add(SchemaTableColumn.BaseTableName, typeof(string));
|
||||
columns.Add(SchemaTableColumn.DataType, typeof(Type));
|
||||
columns.Add(SchemaTableColumn.AllowDBNull, typeof(bool));
|
||||
columns.Add(SchemaTableColumn.ProviderType, typeof(int));
|
||||
columns.Add(SchemaTableColumn.IsAliased, typeof(bool));
|
||||
columns.Add(SchemaTableColumn.IsExpression, typeof(bool));
|
||||
columns.Add(BulkDataReader.IsIdentitySchemaColumn, typeof(bool));
|
||||
columns.Add(SchemaTableOptionalColumn.IsAutoIncrement, typeof(bool));
|
||||
columns.Add(SchemaTableOptionalColumn.IsRowVersion, typeof(bool));
|
||||
columns.Add(SchemaTableOptionalColumn.IsHidden, typeof(bool));
|
||||
columns.Add(SchemaTableColumn.IsLong, typeof(bool));
|
||||
columns.Add(SchemaTableOptionalColumn.IsReadOnly, typeof(bool));
|
||||
columns.Add(SchemaTableOptionalColumn.ProviderSpecificDataType, typeof(Type));
|
||||
columns.Add(BulkDataReader.DataTypeNameSchemaColumn, typeof(string));
|
||||
columns.Add(BulkDataReader.XmlSchemaCollectionDatabaseSchemaColumn, typeof(string));
|
||||
columns.Add(BulkDataReader.XmlSchemaCollectionOwningSchemaSchemaColumn, typeof(string));
|
||||
columns.Add(BulkDataReader.XmlSchemaCollectionNameSchemaColumn, typeof(string));
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -1090,7 +1090,7 @@ namespace Umbraco.Core.Persistence
|
||||
/// <seealso cref="IDataRecord.GetDecimal(Int32)"/>
|
||||
public decimal GetDecimal(int i)
|
||||
{
|
||||
return (Decimal)GetValue(i);
|
||||
return (decimal)GetValue(i);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Umbraco.Core.Persistence
|
||||
{
|
||||
internal static class DatabaseNodeLockExtensions
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void ValidateDatabase(IUmbracoDatabase database)
|
||||
{
|
||||
if (database == null)
|
||||
throw new ArgumentNullException("database");
|
||||
if (database.GetCurrentTransactionIsolationLevel() < IsolationLevel.RepeatableRead)
|
||||
throw new InvalidOperationException("A transaction with minimum RepeatableRead isolation level is required.");
|
||||
}
|
||||
|
||||
// updating a record within a repeatable-read transaction gets an exclusive lock on
|
||||
// that record which will be kept until the transaction is ended, effectively locking
|
||||
// out all other accesses to that record - thus obtaining an exclusive lock over the
|
||||
// protected resources.
|
||||
public static void AcquireLockNodeWriteLock(this IUmbracoDatabase database, int nodeId)
|
||||
{
|
||||
ValidateDatabase(database);
|
||||
|
||||
database.Execute("UPDATE umbracoLock SET value = (CASE WHEN (value=1) THEN -1 ELSE 1 END) WHERE id=@id",
|
||||
new { @id = nodeId });
|
||||
}
|
||||
|
||||
// reading a record within a repeatable-read transaction gets a shared lock on
|
||||
// that record which will be kept until the transaction is ended, effectively preventing
|
||||
// other write accesses to that record - thus obtaining a shared lock over the protected
|
||||
// resources.
|
||||
public static void AcquireLockNodeReadLock(this IUmbracoDatabase database, int nodeId)
|
||||
{
|
||||
ValidateDatabase(database);
|
||||
|
||||
database.ExecuteScalar<int>("SELECT value FROM umbracoLock WHERE id=@id",
|
||||
new { @id = nodeId });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,10 +43,20 @@ namespace Umbraco.Core.Persistence.Dtos
|
||||
[Constraint(Default = "0")]
|
||||
public bool Mandatory { get; set; }
|
||||
|
||||
[Column("mandatoryMessage")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
[Length(500)]
|
||||
public string MandatoryMessage { get; set; }
|
||||
|
||||
[Column("validationRegExp")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
public string ValidationRegExp { get; set; }
|
||||
|
||||
[Column("validationRegExpMessage")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
[Length(500)]
|
||||
public string ValidationRegExpMessage { get; set; }
|
||||
|
||||
[Column("Description")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
[Length(2000)]
|
||||
|
||||
@@ -32,9 +32,15 @@ namespace Umbraco.Core.Persistence.Dtos
|
||||
[Column("mandatory")]
|
||||
public bool Mandatory { get; set; }
|
||||
|
||||
[Column("mandatoryMessage")]
|
||||
public string MandatoryMessage { get; set; }
|
||||
|
||||
[Column("validationRegExp")]
|
||||
public string ValidationRegExp { get; set; }
|
||||
|
||||
[Column("validationRegExpMessage")]
|
||||
public string ValidationRegExpMessage { get; set; }
|
||||
|
||||
[Column("Description")]
|
||||
public string Description { get; set; }
|
||||
|
||||
|
||||
@@ -1,38 +1,96 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Core.Persistence
|
||||
{
|
||||
|
||||
// TODO: Would be good to use this exception type anytime we cannot find an entity
|
||||
|
||||
/// <summary>
|
||||
/// An exception used to indicate that an umbraco entity could not be found
|
||||
/// An exception used to indicate that an Umbraco entity could not be found.
|
||||
/// </summary>
|
||||
/// <seealso cref="System.Exception" />
|
||||
[Obsolete("Instead of throwing an exception, return null or an HTTP 404 status code instead.")]
|
||||
[Serializable]
|
||||
public class EntityNotFoundException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the identifier.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The identifier.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// This object should be serializable to prevent a <see cref="SerializationException" /> to be thrown.
|
||||
/// </remarks>
|
||||
public object Id { get; private set; }
|
||||
private readonly string _msg;
|
||||
|
||||
public EntityNotFoundException(object id, string msg)
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EntityNotFoundException" /> class.
|
||||
/// </summary>
|
||||
public EntityNotFoundException()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EntityNotFoundException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="id">The identifier.</param>
|
||||
/// <param name="message">The message.</param>
|
||||
public EntityNotFoundException(object id, string message)
|
||||
: base(message)
|
||||
{
|
||||
Id = id;
|
||||
_msg = msg;
|
||||
}
|
||||
|
||||
public EntityNotFoundException(string msg)
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EntityNotFoundException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public EntityNotFoundException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EntityNotFoundException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference (<see langword="Nothing" /> in Visual Basic) if no inner exception is specified.</param>
|
||||
public EntityNotFoundException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EntityNotFoundException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> that holds the serialized object data about the exception being thrown.</param>
|
||||
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" /> that contains contextual information about the source or destination.</param>
|
||||
protected EntityNotFoundException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{
|
||||
_msg = msg;
|
||||
Id = info.GetValue(nameof(Id), typeof(object));
|
||||
}
|
||||
|
||||
public override string Message
|
||||
/// <summary>
|
||||
/// When overridden in a derived class, sets the <see cref="T:System.Runtime.Serialization.SerializationInfo" /> with information about the exception.
|
||||
/// </summary>
|
||||
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> that holds the serialized object data about the exception being thrown.</param>
|
||||
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" /> that contains contextual information about the source or destination.</param>
|
||||
/// <exception cref="ArgumentNullException">info</exception>
|
||||
public override void GetObjectData(SerializationInfo info, StreamingContext context)
|
||||
{
|
||||
get { return _msg; }
|
||||
if (info == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(info));
|
||||
}
|
||||
|
||||
info.AddValue(nameof(Id), Id);
|
||||
|
||||
base.GetObjectData(info, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="System.String" /> that represents this instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="System.String" /> that represents this instance.
|
||||
/// </returns>
|
||||
public override string ToString()
|
||||
{
|
||||
var result = base.ToString();
|
||||
|
||||
@@ -60,8 +60,10 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
propertyType.Key = typeDto.UniqueId;
|
||||
propertyType.Name = typeDto.Name;
|
||||
propertyType.Mandatory = typeDto.Mandatory;
|
||||
propertyType.MandatoryMessage = typeDto.MandatoryMessage;
|
||||
propertyType.SortOrder = typeDto.SortOrder;
|
||||
propertyType.ValidationRegExp = typeDto.ValidationRegExp;
|
||||
propertyType.ValidationRegExpMessage = typeDto.ValidationRegExpMessage;
|
||||
propertyType.PropertyGroupId = new Lazy<int>(() => tempGroupDto.Id);
|
||||
propertyType.CreateDate = createDate;
|
||||
propertyType.UpdateDate = updateDate;
|
||||
@@ -124,9 +126,11 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
DataTypeId = propertyType.DataTypeId,
|
||||
Description = propertyType.Description,
|
||||
Mandatory = propertyType.Mandatory,
|
||||
MandatoryMessage = propertyType.MandatoryMessage,
|
||||
Name = propertyType.Name,
|
||||
SortOrder = propertyType.SortOrder,
|
||||
ValidationRegExp = propertyType.ValidationRegExp,
|
||||
ValidationRegExpMessage = propertyType.ValidationRegExpMessage,
|
||||
UniqueId = propertyType.Key,
|
||||
Variations = (byte)propertyType.Variations
|
||||
};
|
||||
|
||||
@@ -4,59 +4,51 @@ using System.Runtime.Serialization;
|
||||
namespace Umbraco.Core.Persistence.FaultHandling
|
||||
{
|
||||
/// <summary>
|
||||
/// The special type of exception that provides managed exit from a retry loop. The user code can use this
|
||||
/// exception to notify the retry policy that no further retry attempts are required.
|
||||
/// The special type of exception that provides managed exit from a retry loop. The user code can use this exception to notify the retry policy that no further retry attempts are required.
|
||||
/// </summary>
|
||||
/// <seealso cref="System.Exception" />
|
||||
[Serializable]
|
||||
public sealed class RetryLimitExceededException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RetryLimitExceededException"/> class with a default error message.
|
||||
/// Initializes a new instance of the <see cref="RetryLimitExceededException" /> class with a default error message.
|
||||
/// </summary>
|
||||
public RetryLimitExceededException()
|
||||
: this("RetryLimitExceeded")
|
||||
{
|
||||
}
|
||||
: base()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RetryLimitExceededException"/> class with a specified error message.
|
||||
/// Initializes a new instance of the <see cref="RetryLimitExceededException" /> class with a specified error message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public RetryLimitExceededException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RetryLimitExceededException"/> class with a reference to the inner exception
|
||||
/// that is the cause of this exception.
|
||||
/// Initializes a new instance of the <see cref="RetryLimitExceededException" /> class with a reference to the inner exception that is the cause of this exception.
|
||||
/// </summary>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception.</param>
|
||||
public RetryLimitExceededException(Exception innerException)
|
||||
: base(innerException != null ? innerException.Message : "RetryLimitExceeded", innerException)
|
||||
{
|
||||
}
|
||||
: base(null, innerException)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RetryLimitExceededException"/> class.
|
||||
/// Initializes a new instance of the <see cref="RetryLimitExceededException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception.</param>
|
||||
public RetryLimitExceededException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RetryLimitExceededException"/> class.
|
||||
/// Initializes a new instance of the <see cref="RetryLimitExceededException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo"/> that holds the serialized object data about the exception being thrown.</param>
|
||||
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext"/> that contains contextual information about the source or destination.</param>
|
||||
/// <exception cref="T:System.ArgumentNullException">The <paramref name="info"/> parameter is null.</exception>
|
||||
/// <exception cref="T:System.Runtime.Serialization.SerializationException">The class name is null or <see cref="P:System.Exception.HResult"/> is zero (0).</exception>
|
||||
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> that holds the serialized object data about the exception being thrown.</param>
|
||||
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" /> that contains contextual information about the source or destination.</param>
|
||||
private RetryLimitExceededException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{
|
||||
}
|
||||
{ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,9 +24,11 @@ namespace Umbraco.Core.Persistence.Mappers
|
||||
DefineMap<PropertyType, PropertyTypeDto>(nameof(PropertyType.DataTypeId), nameof(PropertyTypeDto.DataTypeId));
|
||||
DefineMap<PropertyType, PropertyTypeDto>(nameof(PropertyType.Description), nameof(PropertyTypeDto.Description));
|
||||
DefineMap<PropertyType, PropertyTypeDto>(nameof(PropertyType.Mandatory), nameof(PropertyTypeDto.Mandatory));
|
||||
DefineMap<PropertyType, PropertyTypeDto>(nameof(PropertyType.MandatoryMessage), nameof(PropertyTypeDto.MandatoryMessage));
|
||||
DefineMap<PropertyType, PropertyTypeDto>(nameof(PropertyType.Name), nameof(PropertyTypeDto.Name));
|
||||
DefineMap<PropertyType, PropertyTypeDto>(nameof(PropertyType.SortOrder), nameof(PropertyTypeDto.SortOrder));
|
||||
DefineMap<PropertyType, PropertyTypeDto>(nameof(PropertyType.ValidationRegExp), nameof(PropertyTypeDto.ValidationRegExp));
|
||||
DefineMap<PropertyType, PropertyTypeDto>(nameof(PropertyType.ValidationRegExpMessage), nameof(PropertyTypeDto.ValidationRegExpMessage));
|
||||
DefineMap<PropertyType, DataTypeDto>(nameof(PropertyType.PropertyEditorAlias), nameof(DataTypeDto.EditorAlias));
|
||||
DefineMap<PropertyType, DataTypeDto>(nameof(PropertyType.ValueStorageType), nameof(DataTypeDto.DbType));
|
||||
}
|
||||
|
||||
@@ -7,5 +7,12 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
public interface IDataTypeRepository : IReadWriteQueryRepository<int, IDataType>
|
||||
{
|
||||
IEnumerable<MoveEventInfo<IDataType>> Move(IDataType toMove, EntityContainer container);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a dictionary of content type <see cref="Udi"/>s and the property type aliases that use a <see cref="IDataType"/>
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
IReadOnlyDictionary<Udi, IEnumerable<string>> FindUsages(int id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,10 +297,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
Id = dto.Id,
|
||||
Key = dto.UniqueId,
|
||||
Mandatory = dto.Mandatory,
|
||||
MandatoryMessage = dto.MandatoryMessage,
|
||||
Name = dto.Name,
|
||||
PropertyGroupId = groupId.HasValue ? new Lazy<int>(() => groupId.Value) : null,
|
||||
SortOrder = dto.SortOrder,
|
||||
ValidationRegExp = dto.ValidationRegExp,
|
||||
ValidationRegExpMessage = dto.ValidationRegExpMessage,
|
||||
Variations = (ContentVariation)dto.Variations
|
||||
};
|
||||
}
|
||||
|
||||
+114
-124
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Globalization;
|
||||
@@ -218,6 +219,7 @@ AND umbracoNode.nodeObjectType = @objectType",
|
||||
|
||||
protected void PersistUpdatedBaseContentType(IContentTypeComposition entity)
|
||||
{
|
||||
CorrectPropertyTypeVariations(entity);
|
||||
ValidateVariations(entity);
|
||||
|
||||
var dto = ContentTypeFactory.BuildContentTypeDto(entity);
|
||||
@@ -410,26 +412,7 @@ AND umbracoNode.id <> @id",
|
||||
// note: this only deals with *local* property types, we're dealing w/compositions later below
|
||||
foreach (var propertyType in entity.PropertyTypes)
|
||||
{
|
||||
if (contentTypeVariationChanging)
|
||||
{
|
||||
// content type is changing
|
||||
switch (newContentTypeVariation)
|
||||
{
|
||||
case ContentVariation.Nothing: // changing to Nothing
|
||||
// all property types must change to Nothing
|
||||
propertyType.Variations = ContentVariation.Nothing;
|
||||
break;
|
||||
case ContentVariation.Culture: // changing to Culture
|
||||
// all property types can remain Nothing
|
||||
break;
|
||||
case ContentVariation.CultureAndSegment:
|
||||
case ContentVariation.Segment:
|
||||
default:
|
||||
throw new NotSupportedException(); // TODO: Support this
|
||||
}
|
||||
}
|
||||
|
||||
// then, track each property individually
|
||||
// track each property individually
|
||||
if (propertyType.IsPropertyDirty("Variations"))
|
||||
{
|
||||
// allocate the list only when needed
|
||||
@@ -455,23 +438,19 @@ AND umbracoNode.id <> @id",
|
||||
// via composition, with their original variations (ie not filtered by this
|
||||
// content type variations - we need this true value to make decisions.
|
||||
|
||||
foreach (var propertyType in ((ContentTypeCompositionBase)entity).RawComposedPropertyTypes)
|
||||
propertyTypeVariationChanges = propertyTypeVariationChanges ?? new Dictionary<int, (ContentVariation, ContentVariation)>();
|
||||
|
||||
foreach (var composedPropertyType in ((ContentTypeCompositionBase)entity).RawComposedPropertyTypes)
|
||||
{
|
||||
if (propertyType.VariesBySegment() || newContentTypeVariation.VariesBySegment())
|
||||
throw new NotSupportedException(); // TODO: support this
|
||||
if (composedPropertyType.Variations == ContentVariation.Nothing) continue;
|
||||
|
||||
if (propertyType.Variations == ContentVariation.Culture)
|
||||
{
|
||||
if (propertyTypeVariationChanges == null)
|
||||
propertyTypeVariationChanges = new Dictionary<int, (ContentVariation, ContentVariation)>();
|
||||
// Determine target variation of the composed property type.
|
||||
// The composed property is only considered culture variant when the base content type is also culture variant.
|
||||
// The composed property is only considered segment variant when the base content type is also segment variant.
|
||||
// Example: Culture variant content type with a Culture+Segment variant property type will become ContentVariation.Culture
|
||||
var target = newContentTypeVariation & composedPropertyType.Variations;
|
||||
|
||||
// if content type moves to Culture, property type becomes Culture here again
|
||||
// if content type moves to Nothing, property type becomes Nothing here
|
||||
if (newContentTypeVariation == ContentVariation.Culture)
|
||||
propertyTypeVariationChanges[propertyType.Id] = (ContentVariation.Nothing, ContentVariation.Culture);
|
||||
else if (newContentTypeVariation == ContentVariation.Nothing)
|
||||
propertyTypeVariationChanges[propertyType.Id] = (ContentVariation.Culture, ContentVariation.Nothing);
|
||||
}
|
||||
propertyTypeVariationChanges[composedPropertyType.Id] = (composedPropertyType.Variations, target);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -512,7 +491,7 @@ AND umbracoNode.id <> @id",
|
||||
var impacted = GetImpactedContentTypes(entity, all);
|
||||
|
||||
// if some property types have actually changed, move their variant data
|
||||
if (propertyTypeVariationChanges != null)
|
||||
if (propertyTypeVariationChanges?.Count > 0)
|
||||
MovePropertyTypeVariantData(propertyTypeVariationChanges, impacted);
|
||||
|
||||
// deal with orphan properties: those that were in a deleted tab,
|
||||
@@ -524,23 +503,40 @@ AND umbracoNode.id <> @id",
|
||||
CommonRepository.ClearCache(); // always
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Corrects the property type variations for the given entity
|
||||
/// to make sure the property type variation is compatible with the
|
||||
/// variation set on the entity itself.
|
||||
/// </summary>
|
||||
/// <param name="entity">Entity to correct properties for</param>
|
||||
private void CorrectPropertyTypeVariations(IContentTypeComposition entity)
|
||||
{
|
||||
// Update property variations based on the content type variation
|
||||
foreach (var propertyType in entity.PropertyTypes)
|
||||
{
|
||||
// Determine variation for the property type.
|
||||
// The property is only considered culture variant when the base content type is also culture variant.
|
||||
// The property is only considered segment variant when the base content type is also segment variant.
|
||||
// Example: Culture variant content type with a Culture+Segment variant property type will become ContentVariation.Culture
|
||||
propertyType.Variations = entity.Variations & propertyType.Variations;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that no property types are flagged for a variance that is not supported by the content type itself
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <param name="entity">The entity for which the property types will be validated</param>
|
||||
private void ValidateVariations(IContentTypeComposition entity)
|
||||
{
|
||||
//if the entity does not vary at all, then the property cannot have a variance value greater than it
|
||||
if (entity.Variations == ContentVariation.Nothing)
|
||||
foreach (var prop in entity.PropertyTypes)
|
||||
{
|
||||
foreach (var prop in entity.PropertyTypes)
|
||||
{
|
||||
if (prop.IsPropertyDirty(nameof(prop.Variations)) && prop.Variations > entity.Variations)
|
||||
throw new InvalidOperationException($"The property {prop.Alias} cannot have variations of {prop.Variations} with the content type variations of {entity.Variations}");
|
||||
}
|
||||
|
||||
// The variation of a property is only allowed if all its variation flags
|
||||
// are also set on the entity itself. It cannot set anything that is not also set by the content type.
|
||||
// For example, when entity.Variations is set to Culture a property cannot be set to Segment.
|
||||
var isValid = entity.Variations.HasFlag(prop.Variations);
|
||||
if (!isValid)
|
||||
throw new InvalidOperationException($"The property {prop.Alias} cannot have variations of {prop.Variations} with the content type variations of {entity.Variations}");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private IEnumerable<IContentTypeComposition> GetImpactedContentTypes(IContentTypeComposition contentType, IEnumerable<IContentTypeComposition> all)
|
||||
@@ -661,27 +657,27 @@ AND umbracoNode.id <> @id",
|
||||
var impactedL = impacted.Select(x => x.Id).ToList();
|
||||
|
||||
//Group by the "To" variation so we can bulk update in the correct batches
|
||||
foreach (var grouping in propertyTypeChanges.GroupBy(x => x.Value.ToVariation))
|
||||
foreach (var grouping in propertyTypeChanges.GroupBy(x => x.Value))
|
||||
{
|
||||
var propertyTypeIds = grouping.Select(x => x.Key).ToList();
|
||||
var toVariation = grouping.Key;
|
||||
var (FromVariation, ToVariation) = grouping.Key;
|
||||
|
||||
switch (toVariation)
|
||||
var fromCultureEnabled = FromVariation.HasFlag(ContentVariation.Culture);
|
||||
var toCultureEnabled = ToVariation.HasFlag(ContentVariation.Culture);
|
||||
|
||||
if (!fromCultureEnabled && toCultureEnabled)
|
||||
{
|
||||
case ContentVariation.Culture:
|
||||
CopyPropertyData(null, defaultLanguageId, propertyTypeIds, impactedL);
|
||||
CopyTagData(null, defaultLanguageId, propertyTypeIds, impactedL);
|
||||
RenormalizeDocumentEditedFlags(propertyTypeIds, impactedL);
|
||||
break;
|
||||
case ContentVariation.Nothing:
|
||||
CopyPropertyData(defaultLanguageId, null, propertyTypeIds, impactedL);
|
||||
CopyTagData(defaultLanguageId, null, propertyTypeIds, impactedL);
|
||||
RenormalizeDocumentEditedFlags(propertyTypeIds, impactedL);
|
||||
break;
|
||||
case ContentVariation.CultureAndSegment:
|
||||
case ContentVariation.Segment:
|
||||
default:
|
||||
throw new NotSupportedException(); // TODO: Support this
|
||||
// Culture has been enabled
|
||||
CopyPropertyData(null, defaultLanguageId, propertyTypeIds, impactedL);
|
||||
CopyTagData(null, defaultLanguageId, propertyTypeIds, impactedL);
|
||||
RenormalizeDocumentEditedFlags(propertyTypeIds, impactedL);
|
||||
}
|
||||
else if (fromCultureEnabled && !toCultureEnabled)
|
||||
{
|
||||
// Culture has been disabled
|
||||
CopyPropertyData(defaultLanguageId, null, propertyTypeIds, impactedL);
|
||||
CopyTagData(defaultLanguageId, null, propertyTypeIds, impactedL);
|
||||
RenormalizeDocumentEditedFlags(propertyTypeIds, impactedL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -693,78 +689,72 @@ AND umbracoNode.id <> @id",
|
||||
{
|
||||
var defaultLanguageId = GetDefaultLanguageId();
|
||||
|
||||
switch (toVariation)
|
||||
var cultureIsNotEnabled = !fromVariation.HasFlag(ContentVariation.Culture);
|
||||
var cultureWillBeEnabled = toVariation.HasFlag(ContentVariation.Culture);
|
||||
|
||||
if (cultureIsNotEnabled && cultureWillBeEnabled)
|
||||
{
|
||||
case ContentVariation.Culture:
|
||||
//move the names
|
||||
//first clear out any existing names that might already exists under the default lang
|
||||
//there's 2x tables to update
|
||||
|
||||
//move the names
|
||||
//first clear out any existing names that might already exists under the default lang
|
||||
//there's 2x tables to update
|
||||
//clear out the versionCultureVariation table
|
||||
var sqlSelect = Sql().Select<ContentVersionCultureVariationDto>(x => x.Id)
|
||||
.From<ContentVersionCultureVariationDto>()
|
||||
.InnerJoin<ContentVersionDto>().On<ContentVersionDto, ContentVersionCultureVariationDto>(x => x.Id, x => x.VersionId)
|
||||
.InnerJoin<ContentDto>().On<ContentDto, ContentVersionDto>(x => x.NodeId, x => x.NodeId)
|
||||
.Where<ContentDto>(x => x.ContentTypeId == contentType.Id)
|
||||
.Where<ContentVersionCultureVariationDto>(x => x.LanguageId == defaultLanguageId);
|
||||
var sqlDelete = Sql()
|
||||
.Delete<ContentVersionCultureVariationDto>()
|
||||
.WhereIn<ContentVersionCultureVariationDto>(x => x.Id, sqlSelect);
|
||||
|
||||
//clear out the versionCultureVariation table
|
||||
var sqlSelect = Sql().Select<ContentVersionCultureVariationDto>(x => x.Id)
|
||||
.From<ContentVersionCultureVariationDto>()
|
||||
.InnerJoin<ContentVersionDto>().On<ContentVersionDto, ContentVersionCultureVariationDto>(x => x.Id, x => x.VersionId)
|
||||
.InnerJoin<ContentDto>().On<ContentDto, ContentVersionDto>(x => x.NodeId, x => x.NodeId)
|
||||
.Where<ContentDto>(x => x.ContentTypeId == contentType.Id)
|
||||
.Where<ContentVersionCultureVariationDto>(x => x.LanguageId == defaultLanguageId);
|
||||
var sqlDelete = Sql()
|
||||
.Delete<ContentVersionCultureVariationDto>()
|
||||
.WhereIn<ContentVersionCultureVariationDto>(x => x.Id, sqlSelect);
|
||||
Database.Execute(sqlDelete);
|
||||
|
||||
Database.Execute(sqlDelete);
|
||||
//clear out the documentCultureVariation table
|
||||
sqlSelect = Sql().Select<DocumentCultureVariationDto>(x => x.Id)
|
||||
.From<DocumentCultureVariationDto>()
|
||||
.InnerJoin<ContentDto>().On<ContentDto, DocumentCultureVariationDto>(x => x.NodeId, x => x.NodeId)
|
||||
.Where<ContentDto>(x => x.ContentTypeId == contentType.Id)
|
||||
.Where<DocumentCultureVariationDto>(x => x.LanguageId == defaultLanguageId);
|
||||
sqlDelete = Sql()
|
||||
.Delete<DocumentCultureVariationDto>()
|
||||
.WhereIn<DocumentCultureVariationDto>(x => x.Id, sqlSelect);
|
||||
|
||||
//clear out the documentCultureVariation table
|
||||
sqlSelect = Sql().Select<DocumentCultureVariationDto>(x => x.Id)
|
||||
.From<DocumentCultureVariationDto>()
|
||||
.InnerJoin<ContentDto>().On<ContentDto, DocumentCultureVariationDto>(x => x.NodeId, x => x.NodeId)
|
||||
.Where<ContentDto>(x => x.ContentTypeId == contentType.Id)
|
||||
.Where<DocumentCultureVariationDto>(x => x.LanguageId == defaultLanguageId);
|
||||
sqlDelete = Sql()
|
||||
.Delete<DocumentCultureVariationDto>()
|
||||
.WhereIn<DocumentCultureVariationDto>(x => x.Id, sqlSelect);
|
||||
Database.Execute(sqlDelete);
|
||||
|
||||
Database.Execute(sqlDelete);
|
||||
//now we need to insert names into these 2 tables based on the invariant data
|
||||
|
||||
//now we need to insert names into these 2 tables based on the invariant data
|
||||
//insert rows into the versionCultureVariationDto table based on the data from contentVersionDto for the default lang
|
||||
var cols = Sql().Columns<ContentVersionCultureVariationDto>(x => x.VersionId, x => x.Name, x => x.UpdateUserId, x => x.UpdateDate, x => x.LanguageId);
|
||||
sqlSelect = Sql().Select<ContentVersionDto>(x => x.Id, x => x.Text, x => x.UserId, x => x.VersionDate)
|
||||
.Append($", {defaultLanguageId}") //default language ID
|
||||
.From<ContentVersionDto>()
|
||||
.InnerJoin<ContentDto>().On<ContentDto, ContentVersionDto>(x => x.NodeId, x => x.NodeId)
|
||||
.Where<ContentDto>(x => x.ContentTypeId == contentType.Id);
|
||||
var sqlInsert = Sql($"INSERT INTO {ContentVersionCultureVariationDto.TableName} ({cols})").Append(sqlSelect);
|
||||
|
||||
//insert rows into the versionCultureVariationDto table based on the data from contentVersionDto for the default lang
|
||||
var cols = Sql().Columns<ContentVersionCultureVariationDto>(x => x.VersionId, x => x.Name, x => x.UpdateUserId, x => x.UpdateDate, x => x.LanguageId);
|
||||
sqlSelect = Sql().Select<ContentVersionDto>(x => x.Id, x => x.Text, x => x.UserId, x => x.VersionDate)
|
||||
.Append($", {defaultLanguageId}") //default language ID
|
||||
.From<ContentVersionDto>()
|
||||
.InnerJoin<ContentDto>().On<ContentDto, ContentVersionDto>(x => x.NodeId, x => x.NodeId)
|
||||
.Where<ContentDto>(x => x.ContentTypeId == contentType.Id);
|
||||
var sqlInsert = Sql($"INSERT INTO {ContentVersionCultureVariationDto.TableName} ({cols})").Append(sqlSelect);
|
||||
Database.Execute(sqlInsert);
|
||||
|
||||
Database.Execute(sqlInsert);
|
||||
//insert rows into the documentCultureVariation table
|
||||
cols = Sql().Columns<DocumentCultureVariationDto>(x => x.NodeId, x => x.Edited, x => x.Published, x => x.Name, x => x.Available, x => x.LanguageId);
|
||||
sqlSelect = Sql().Select<DocumentDto>(x => x.NodeId, x => x.Edited, x => x.Published)
|
||||
.AndSelect<NodeDto>(x => x.Text)
|
||||
.Append($", 1, {defaultLanguageId}") //make Available + default language ID
|
||||
.From<DocumentDto>()
|
||||
.InnerJoin<NodeDto>().On<NodeDto, DocumentDto>(x => x.NodeId, x => x.NodeId)
|
||||
.InnerJoin<ContentDto>().On<ContentDto, NodeDto>(x => x.NodeId, x => x.NodeId)
|
||||
.Where<ContentDto>(x => x.ContentTypeId == contentType.Id);
|
||||
sqlInsert = Sql($"INSERT INTO {DocumentCultureVariationDto.TableName} ({cols})").Append(sqlSelect);
|
||||
|
||||
//insert rows into the documentCultureVariation table
|
||||
cols = Sql().Columns<DocumentCultureVariationDto>(x => x.NodeId, x => x.Edited, x => x.Published, x => x.Name, x => x.Available, x => x.LanguageId);
|
||||
sqlSelect = Sql().Select<DocumentDto>(x => x.NodeId, x => x.Edited, x => x.Published)
|
||||
.AndSelect<NodeDto>(x => x.Text)
|
||||
.Append($", 1, {defaultLanguageId}") //make Available + default language ID
|
||||
.From<DocumentDto>()
|
||||
.InnerJoin<NodeDto>().On<NodeDto, DocumentDto>(x => x.NodeId, x => x.NodeId)
|
||||
.InnerJoin<ContentDto>().On<ContentDto, NodeDto>(x => x.NodeId, x => x.NodeId)
|
||||
.Where<ContentDto>(x => x.ContentTypeId == contentType.Id);
|
||||
sqlInsert = Sql($"INSERT INTO {DocumentCultureVariationDto.TableName} ({cols})").Append(sqlSelect);
|
||||
Database.Execute(sqlInsert);
|
||||
}
|
||||
else
|
||||
{
|
||||
//we don't need to move the names! this is because we always keep the invariant names with the name of the default language.
|
||||
|
||||
Database.Execute(sqlInsert);
|
||||
|
||||
break;
|
||||
case ContentVariation.Nothing:
|
||||
|
||||
//we don't need to move the names! this is because we always keep the invariant names with the name of the default language.
|
||||
|
||||
//however, if we were to move names, we could do this: BUT this doesn't work with SQLCE, for that we'd have to update row by row :(
|
||||
// if we want these SQL statements back, look into GIT history
|
||||
|
||||
break;
|
||||
case ContentVariation.CultureAndSegment:
|
||||
case ContentVariation.Segment:
|
||||
default:
|
||||
throw new NotSupportedException(); // TODO: Support this
|
||||
//however, if we were to move names, we could do this: BUT this doesn't work with SQLCE, for that we'd have to update row by row :(
|
||||
// if we want these SQL statements back, look into GIT history
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -279,6 +279,28 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
return moveInfo;
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<Udi, IEnumerable<string>> FindUsages(int id)
|
||||
{
|
||||
if (id == default)
|
||||
return new Dictionary<Udi, IEnumerable<string>>();
|
||||
|
||||
var sql = Sql()
|
||||
.Select<ContentTypeDto>(ct => ct.Select(node => node.NodeDto))
|
||||
.AndSelect<PropertyTypeDto>(pt => Alias(pt.Alias, "ptAlias"), pt => Alias(pt.Name, "ptName"))
|
||||
.From<PropertyTypeDto>()
|
||||
.InnerJoin<ContentTypeDto>().On<ContentTypeDto, PropertyTypeDto>(ct => ct.NodeId, pt => pt.ContentTypeId)
|
||||
.InnerJoin<NodeDto>().On<NodeDto, ContentTypeDto>(n => n.NodeId, ct => ct.NodeId)
|
||||
.Where<PropertyTypeDto>(pt => pt.DataTypeId == id)
|
||||
.OrderBy<NodeDto>(node => node.NodeId)
|
||||
.AndBy<PropertyTypeDto>(pt => pt.Alias);
|
||||
|
||||
var dtos = Database.FetchOneToMany<ContentTypeReferenceDto>(ct => ct.PropertyTypes, sql);
|
||||
|
||||
return dtos.ToDictionary(
|
||||
x => (Udi)new GuidUdi(ObjectTypes.GetUdiType(x.NodeDto.NodeObjectType.Value), x.NodeDto.UniqueId).EnsureClosed(),
|
||||
x => (IEnumerable<string>)x.PropertyTypes.Select(p => p.Alias).ToList());
|
||||
}
|
||||
|
||||
private string EnsureUniqueNodeName(string nodeName, int id = 0)
|
||||
{
|
||||
var template = SqlContext.Templates.Get("Umbraco.Core.DataTypeDefinitionRepository.EnsureUniqueNodeName", tsql => tsql
|
||||
@@ -291,5 +313,24 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
return SimilarNodeName.GetUniqueName(names, id, nodeName);
|
||||
}
|
||||
|
||||
|
||||
[TableName(Constants.DatabaseSchema.Tables.ContentType)]
|
||||
private class ContentTypeReferenceDto : ContentTypeDto
|
||||
{
|
||||
[ResultColumn]
|
||||
[Reference(ReferenceType.Many)]
|
||||
public List<PropertyTypeReferenceDto> PropertyTypes { get; set; }
|
||||
}
|
||||
|
||||
[TableName(Constants.DatabaseSchema.Tables.PropertyType)]
|
||||
private class PropertyTypeReferenceDto
|
||||
{
|
||||
[Column("ptAlias")]
|
||||
public string Alias { get; set; }
|
||||
|
||||
[Column("ptName")]
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -924,32 +924,32 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override IEnumerable<IContent> PerformGetByQuery(IQuery<IContent> query)
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
protected override IEnumerable<string> GetDeleteClauses()
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
protected override void PersistNewItem(IContent entity)
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
protected override void PersistUpdatedItem(IContent entity)
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
protected override Sql<ISqlContext> GetBaseQuery(bool isCount)
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
protected override string GetBaseWhereClause()
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
@@ -129,6 +128,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override void PersistDeletedItem(EntityContainer entity)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException(nameof(entity));
|
||||
EnsureContainerType(entity);
|
||||
|
||||
var nodeDto = Database.FirstOrDefault<NodeDto>(Sql().SelectAll()
|
||||
@@ -162,9 +162,11 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override void PersistNewItem(EntityContainer entity)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException(nameof(entity));
|
||||
EnsureContainerType(entity);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(entity.Name)) throw new ArgumentNullOrEmptyException("entity.Name");
|
||||
if (entity.Name == null) throw new InvalidOperationException("Entity name can't be null.");
|
||||
if (string.IsNullOrWhiteSpace(entity.Name)) throw new InvalidOperationException("Entity name can't be empty or consist only of white-space characters.");
|
||||
entity.Name = entity.Name.Trim();
|
||||
|
||||
// guard against duplicates
|
||||
@@ -184,7 +186,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
.Where<NodeDto>(dto => dto.NodeId == entity.ParentId && dto.NodeObjectType == entity.ContainerObjectType));
|
||||
|
||||
if (parentDto == null)
|
||||
throw new NullReferenceException("Could not find parent container with id " + entity.ParentId);
|
||||
throw new InvalidOperationException("Could not find parent container with id " + entity.ParentId);
|
||||
|
||||
level = parentDto.Level;
|
||||
path = parentDto.Path;
|
||||
@@ -223,10 +225,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
//
|
||||
protected override void PersistUpdatedItem(EntityContainer entity)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException(nameof(entity));
|
||||
EnsureContainerType(entity);
|
||||
|
||||
if (entity.Name == null) throw new InvalidOperationException("Entity name can't be null.");
|
||||
if (string.IsNullOrWhiteSpace(entity.Name)) throw new InvalidOperationException("Entity name can't be empty or consist only of white-space characters.");
|
||||
entity.Name = entity.Name.Trim();
|
||||
if (string.IsNullOrWhiteSpace(entity.Name)) throw new ArgumentNullOrEmptyException("entity.Name");
|
||||
|
||||
// find container to update
|
||||
var nodeDto = Database.FirstOrDefault<NodeDto>(Sql().SelectAll()
|
||||
@@ -255,7 +259,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
.Where<NodeDto>(dto => dto.NodeId == entity.ParentId && dto.NodeObjectType == entity.ContainerObjectType));
|
||||
|
||||
if (parent == null)
|
||||
throw new NullReferenceException("Could not find parent container with id " + entity.ParentId);
|
||||
throw new InvalidOperationException("Could not find parent container with id " + entity.ParentId);
|
||||
|
||||
nodeDto.Level = Convert.ToInt16(parent.Level + 1);
|
||||
nodeDto.Path = parent.Path + "," + nodeDto.NodeId;
|
||||
|
||||
@@ -182,6 +182,19 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
throw new InvalidOperationException($"Cannot save the default language ({entity.IsoCode}) as non-default. Make another language the default language instead.");
|
||||
}
|
||||
|
||||
if (entity.IsPropertyDirty(nameof(ILanguage.IsoCode)))
|
||||
{
|
||||
//if the iso code is changing, ensure there's not another lang with the same code already assigned
|
||||
var sameCode = Sql()
|
||||
.SelectCount()
|
||||
.From<LanguageDto>()
|
||||
.Where<LanguageDto>(x => x.IsoCode == entity.IsoCode && x.Id != entity.Id);
|
||||
|
||||
var countOfSameCode = Database.ExecuteScalar<int>(sameCode);
|
||||
if (countOfSameCode > 0)
|
||||
throw new InvalidOperationException($"Cannot update the language to a new culture: {entity.IsoCode} since that culture is already assigned to another language entity.");
|
||||
}
|
||||
|
||||
// fallback cycles are detected at service level
|
||||
|
||||
// update
|
||||
|
||||
@@ -425,32 +425,32 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override IEnumerable<IMedia> PerformGetByQuery(IQuery<IMedia> query)
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
protected override IEnumerable<string> GetDeleteClauses()
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
protected override void PersistNewItem(IMedia entity)
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
protected override void PersistUpdatedItem(IMedia entity)
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
protected override Sql<ISqlContext> GetBaseQuery(bool isCount)
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
protected override string GetBaseWhereClause()
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
// joining the type so we can do a query against the member type - not sure if this adds much overhead or not?
|
||||
// the execution plan says it doesn't so we'll go with that and in that case, it might be worth joining the content
|
||||
// types by default on the document and media repo's so we can query by content type there too.
|
||||
// types by default on the document and media repos so we can query by content type there too.
|
||||
.InnerJoin<ContentTypeDto>().On<ContentDto, ContentTypeDto>(left => left.ContentTypeId, right => right.NodeId);
|
||||
|
||||
sql.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId);
|
||||
@@ -546,6 +546,15 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
if (ordering.OrderBy.InvariantEquals("userName"))
|
||||
return SqlSyntax.GetFieldName<MemberDto>(x => x.LoginName);
|
||||
|
||||
if (ordering.OrderBy.InvariantEquals("updateDate"))
|
||||
return SqlSyntax.GetFieldName<ContentVersionDto>(x => x.VersionDate);
|
||||
|
||||
if (ordering.OrderBy.InvariantEquals("createDate"))
|
||||
return SqlSyntax.GetFieldName<NodeDto>(x => x.CreateDate);
|
||||
|
||||
if (ordering.OrderBy.InvariantEquals("contentTypeAlias"))
|
||||
return SqlSyntax.GetFieldName<ContentTypeDto>(x => x.Alias);
|
||||
|
||||
return base.ApplySystemOrdering(ref sql, ordering);
|
||||
}
|
||||
|
||||
|
||||
@@ -225,8 +225,17 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
if (builtinProperties.ContainsKey(propertyType.Alias))
|
||||
{
|
||||
//this reset's its current data type reference which will be re-assigned based on the property editor assigned on the next line
|
||||
propertyType.DataTypeId = 0;
|
||||
propertyType.DataTypeKey = default;
|
||||
var propDefinition = builtinProperties[propertyType.Alias];
|
||||
if (propDefinition != null)
|
||||
{
|
||||
propertyType.DataTypeId = propDefinition.DataTypeId;
|
||||
propertyType.DataTypeKey = propDefinition.DataTypeKey;
|
||||
}
|
||||
else
|
||||
{
|
||||
propertyType.DataTypeId = 0;
|
||||
propertyType.DataTypeKey = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,27 +252,27 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override ContentPermissionSet PerformGet(int id)
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
protected override IEnumerable<ContentPermissionSet> PerformGetAll(params int[] ids)
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
protected override IEnumerable<ContentPermissionSet> PerformGetByQuery(IQuery<ContentPermissionSet> query)
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
protected override Sql<ISqlContext> GetBaseQuery(bool isCount)
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
protected override string GetBaseWhereClause()
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
protected override IEnumerable<string> GetDeleteClauses()
|
||||
@@ -280,11 +280,11 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
return new List<string>();
|
||||
}
|
||||
|
||||
protected override Guid NodeObjectTypeId => throw new WontImplementException();
|
||||
protected override Guid NodeObjectTypeId => throw new InvalidOperationException("This property won't be implemented.");
|
||||
|
||||
protected override void PersistDeletedItem(ContentPermissionSet entity)
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
@@ -105,7 +106,7 @@ JOIN umbracoNode ON umbracoRedirectUrl.contentKey=umbracoNode.uniqueID");
|
||||
CreateDateUtc = redirectUrl.CreateDateUtc,
|
||||
Url = redirectUrl.Url,
|
||||
Culture = redirectUrl.Culture,
|
||||
UrlHash = redirectUrl.Url.ToSHA1()
|
||||
UrlHash = redirectUrl.Url.GenerateHash<SHA1>()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -134,7 +135,7 @@ JOIN umbracoNode ON umbracoRedirectUrl.contentKey=umbracoNode.uniqueID");
|
||||
|
||||
public IRedirectUrl Get(string url, Guid contentKey, string culture)
|
||||
{
|
||||
var urlHash = url.ToSHA1();
|
||||
var urlHash = url.GenerateHash<SHA1>();
|
||||
var sql = GetBaseQuery(false).Where<RedirectUrlDto>(x => x.Url == url && x.UrlHash == urlHash && x.ContentKey == contentKey && x.Culture == culture);
|
||||
var dto = Database.Fetch<RedirectUrlDto>(sql).FirstOrDefault();
|
||||
return dto == null ? null : Map(dto);
|
||||
@@ -157,7 +158,7 @@ JOIN umbracoNode ON umbracoRedirectUrl.contentKey=umbracoNode.uniqueID");
|
||||
|
||||
public IRedirectUrl GetMostRecentUrl(string url)
|
||||
{
|
||||
var urlHash = url.ToSHA1();
|
||||
var urlHash = url.GenerateHash<SHA1>();
|
||||
var sql = GetBaseQuery(false)
|
||||
.Where<RedirectUrlDto>(x => x.Url == url && x.UrlHash == urlHash)
|
||||
.OrderByDescending<RedirectUrlDto>(x => x.CreateDateUtc);
|
||||
|
||||
@@ -75,19 +75,19 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected sealed override IEnumerable<string> GetDeleteClauses()
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
protected sealed override Guid NodeObjectTypeId => throw new WontImplementException();
|
||||
protected sealed override Guid NodeObjectTypeId => throw new InvalidOperationException("This property won't be implemented.");
|
||||
|
||||
protected sealed override void PersistNewItem(TEntity entity)
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
protected sealed override void PersistUpdatedItem(TEntity entity)
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -286,7 +286,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
return list;
|
||||
}
|
||||
|
||||
protected override Guid NodeObjectTypeId => throw new WontImplementException();
|
||||
protected override Guid NodeObjectTypeId => throw new InvalidOperationException("This property won't be implemented.");
|
||||
|
||||
protected override void PersistNewItem(IUserGroup entity)
|
||||
{
|
||||
@@ -370,35 +370,35 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override UserGroupWithUsers PerformGet(int id)
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
protected override IEnumerable<UserGroupWithUsers> PerformGetAll(params int[] ids)
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
protected override IEnumerable<UserGroupWithUsers> PerformGetByQuery(IQuery<UserGroupWithUsers> query)
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
protected override Sql<ISqlContext> GetBaseQuery(bool isCount)
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
protected override string GetBaseWhereClause()
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
protected override IEnumerable<string> GetDeleteClauses()
|
||||
{
|
||||
throw new WontImplementException();
|
||||
throw new InvalidOperationException("This method won't be implemented.");
|
||||
}
|
||||
|
||||
protected override Guid NodeObjectTypeId => throw new WontImplementException();
|
||||
protected override Guid NodeObjectTypeId => throw new InvalidOperationException("This property won't be implemented.");
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Text.RegularExpressions;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
@@ -76,6 +77,11 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
string ConvertIntegerToOrderableString { get; }
|
||||
string ConvertDateToOrderableString { get; }
|
||||
string ConvertDecimalToOrderableString { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the default isolation level for the database
|
||||
/// </summary>
|
||||
IsolationLevel DefaultIsolationLevel { get; }
|
||||
|
||||
IEnumerable<string> GetTablesInSchema(IDatabase db);
|
||||
IEnumerable<ColumnInfo> GetColumnsInSchema(IDatabase db);
|
||||
@@ -121,5 +127,8 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
/// unspecified.</para>
|
||||
/// </remarks>
|
||||
bool TryGetDefaultConstraint(IDatabase db, string tableName, string columnName, out string constraintName);
|
||||
|
||||
void ReadLock(IDatabase db, params int[] lockIds);
|
||||
void WriteLock(IDatabase db, params int[] lockIds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.SqlServerCe;
|
||||
using System.Linq;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
@@ -52,6 +54,8 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
return "(" + string.Join("+", args) + ")";
|
||||
}
|
||||
|
||||
public override System.Data.IsolationLevel DefaultIsolationLevel => System.Data.IsolationLevel.RepeatableRead;
|
||||
|
||||
public override string FormatColumnRename(string tableName, string oldName, string newName)
|
||||
{
|
||||
//NOTE Sql CE doesn't support renaming a column, so a new column needs to be created, then copy data and finally remove old column
|
||||
@@ -152,6 +156,39 @@ where table_name=@0 and column_name=@1", tableName, columnName).FirstOrDefault()
|
||||
return result > 0;
|
||||
}
|
||||
|
||||
public override void WriteLock(IDatabase db, params int[] lockIds)
|
||||
{
|
||||
// soon as we get Database, a transaction is started
|
||||
|
||||
if (db.Transaction.IsolationLevel < IsolationLevel.RepeatableRead)
|
||||
throw new InvalidOperationException("A transaction with minimum RepeatableRead isolation level is required.");
|
||||
|
||||
db.Execute(@"SET LOCK_TIMEOUT 1800;");
|
||||
// *not* using a unique 'WHERE IN' query here because the *order* of lockIds is important to avoid deadlocks
|
||||
foreach (var lockId in lockIds)
|
||||
{
|
||||
var i = db.Execute(@"UPDATE umbracoLock SET value = (CASE WHEN (value=1) THEN -1 ELSE 1 END) WHERE id=@id", new { id = lockId });
|
||||
if (i == 0) // ensure we are actually locking!
|
||||
throw new ArgumentException($"LockObject with id={lockId} does not exist.");
|
||||
}
|
||||
}
|
||||
|
||||
public override void ReadLock(IDatabase db, params int[] lockIds)
|
||||
{
|
||||
// soon as we get Database, a transaction is started
|
||||
|
||||
if (db.Transaction.IsolationLevel < IsolationLevel.RepeatableRead)
|
||||
throw new InvalidOperationException("A transaction with minimum RepeatableRead isolation level is required.");
|
||||
|
||||
// *not* using a unique 'WHERE IN' query here because the *order* of lockIds is important to avoid deadlocks
|
||||
foreach (var lockId in lockIds)
|
||||
{
|
||||
var i = db.ExecuteScalar<int?>("SELECT value FROM umbracoLock WHERE id=@id", new { id = lockId });
|
||||
if (i == null) // ensure we are actually locking!
|
||||
throw new ArgumentException($"LockObject with id={lockId} does not exist.");
|
||||
}
|
||||
}
|
||||
|
||||
protected override string FormatIdentity(ColumnDefinition column)
|
||||
{
|
||||
return column.IsIdentity ? GetIdentityString(column) : string.Empty;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Logging;
|
||||
@@ -179,6 +180,8 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
return items.Select(x => x.TABLE_NAME).Cast<string>().ToList();
|
||||
}
|
||||
|
||||
public override IsolationLevel DefaultIsolationLevel => IsolationLevel.ReadCommitted;
|
||||
|
||||
public override IEnumerable<ColumnInfo> GetColumnsInSchema(IDatabase db)
|
||||
{
|
||||
var items = db.Fetch<dynamic>("SELECT TABLE_NAME, COLUMN_NAME, ORDINAL_POSITION, COLUMN_DEFAULT, IS_NULLABLE, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = (SELECT SCHEMA_NAME())");
|
||||
@@ -246,6 +249,41 @@ where tbl.[name]=@0 and col.[name]=@1;", tableName, columnName)
|
||||
return result > 0;
|
||||
}
|
||||
|
||||
public override void WriteLock(IDatabase db, params int[] lockIds)
|
||||
{
|
||||
// soon as we get Database, a transaction is started
|
||||
|
||||
if (db.Transaction.IsolationLevel < IsolationLevel.ReadCommitted)
|
||||
throw new InvalidOperationException("A transaction with minimum ReadCommitted isolation level is required.");
|
||||
|
||||
|
||||
// *not* using a unique 'WHERE IN' query here because the *order* of lockIds is important to avoid deadlocks
|
||||
foreach (var lockId in lockIds)
|
||||
{
|
||||
db.Execute(@"SET LOCK_TIMEOUT 1800;");
|
||||
var i = db.Execute(@"UPDATE umbracoLock WITH (REPEATABLEREAD) SET value = (CASE WHEN (value=1) THEN -1 ELSE 1 END) WHERE id=@id", new { id = lockId });
|
||||
if (i == 0) // ensure we are actually locking!
|
||||
throw new ArgumentException($"LockObject with id={lockId} does not exist.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override void ReadLock(IDatabase db, params int[] lockIds)
|
||||
{
|
||||
// soon as we get Database, a transaction is started
|
||||
|
||||
if (db.Transaction.IsolationLevel < IsolationLevel.ReadCommitted)
|
||||
throw new InvalidOperationException("A transaction with minimum ReadCommitted isolation level is required.");
|
||||
|
||||
// *not* using a unique 'WHERE IN' query here because the *order* of lockIds is important to avoid deadlocks
|
||||
foreach (var lockId in lockIds)
|
||||
{
|
||||
var i = db.ExecuteScalar<int?>("SELECT value FROM umbracoLock WITH (REPEATABLEREAD) WHERE id=@id", new { id = lockId });
|
||||
if (i == null) // ensure we are actually locking!
|
||||
throw new ArgumentException($"LockObject with id={lockId} does not exist.", nameof(lockIds));
|
||||
}
|
||||
}
|
||||
|
||||
public override string FormatColumnRename(string tableName, string oldName, string newName)
|
||||
{
|
||||
return string.Format(RenameColumn, tableName, oldName, newName);
|
||||
|
||||
@@ -200,7 +200,9 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
|
||||
return "NVARCHAR";
|
||||
}
|
||||
|
||||
|
||||
public abstract IsolationLevel DefaultIsolationLevel { get; }
|
||||
|
||||
public virtual IEnumerable<string> GetTablesInSchema(IDatabase db)
|
||||
{
|
||||
return new List<string>();
|
||||
@@ -225,6 +227,9 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
|
||||
public abstract bool TryGetDefaultConstraint(IDatabase db, string tableName, string columnName, out string constraintName);
|
||||
|
||||
public abstract void ReadLock(IDatabase db, params int[] lockIds);
|
||||
public abstract void WriteLock(IDatabase db, params int[] lockIds);
|
||||
|
||||
public virtual bool DoesTableExist(IDatabase db, string tableName)
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -20,9 +20,6 @@ namespace Umbraco.Core.Persistence
|
||||
/// </remarks>
|
||||
public class UmbracoDatabase : Database, IUmbracoDatabase
|
||||
{
|
||||
// Umbraco's default isolation level is RepeatableRead
|
||||
private const IsolationLevel DefaultIsolationLevel = IsolationLevel.RepeatableRead;
|
||||
|
||||
private readonly ILogger _logger;
|
||||
private readonly RetryPolicy _connectionRetryPolicy;
|
||||
private readonly RetryPolicy _commandRetryPolicy;
|
||||
@@ -38,7 +35,7 @@ namespace Umbraco.Core.Persistence
|
||||
/// <para>Also used by DatabaseBuilder for creating databases and installing/upgrading.</para>
|
||||
/// </remarks>
|
||||
public UmbracoDatabase(string connectionString, ISqlContext sqlContext, DbProviderFactory provider, ILogger logger, RetryPolicy connectionRetryPolicy = null, RetryPolicy commandRetryPolicy = null)
|
||||
: base(connectionString, sqlContext.DatabaseType, provider, DefaultIsolationLevel)
|
||||
: base(connectionString, sqlContext.DatabaseType, provider, sqlContext.SqlSyntax.DefaultIsolationLevel)
|
||||
{
|
||||
SqlContext = sqlContext;
|
||||
|
||||
@@ -54,7 +51,7 @@ namespace Umbraco.Core.Persistence
|
||||
/// </summary>
|
||||
/// <remarks>Internal for unit tests only.</remarks>
|
||||
internal UmbracoDatabase(DbConnection connection, ISqlContext sqlContext, ILogger logger)
|
||||
: base(connection, sqlContext.DatabaseType, DefaultIsolationLevel)
|
||||
: base(connection, sqlContext.DatabaseType, sqlContext.SqlSyntax.DefaultIsolationLevel)
|
||||
{
|
||||
SqlContext = sqlContext;
|
||||
_logger = logger;
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.Data.Common;
|
||||
using System.Threading;
|
||||
using NPoco;
|
||||
using NPoco.FluentMappings;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence.FaultHandling;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
@@ -61,8 +60,8 @@ namespace Umbraco.Core.Persistence
|
||||
/// <remarks>Used by the other ctor and in tests.</remarks>
|
||||
public UmbracoDatabaseFactory(string connectionStringName, ILogger logger, Lazy<IMapperCollection> mappers)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(connectionStringName))
|
||||
throw new ArgumentNullOrEmptyException(nameof(connectionStringName));
|
||||
if (connectionStringName == null) throw new ArgumentNullException(nameof(connectionStringName));
|
||||
if (string.IsNullOrWhiteSpace(connectionStringName)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(connectionStringName));
|
||||
|
||||
_mappers = mappers ?? throw new ArgumentNullException(nameof(mappers));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using Umbraco.Core.Exceptions;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
@@ -28,13 +27,15 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// <param name="view">The view to use to render the field editor.</param>
|
||||
public ConfigurationFieldAttribute(string key, string name, string view)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(key)) throw new ArgumentNullOrEmptyException(nameof(key));
|
||||
if (key == null) throw new ArgumentNullException(nameof(key));
|
||||
if (string.IsNullOrWhiteSpace(key)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(key));
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(name));
|
||||
if (view == null) throw new ArgumentNullException(nameof(view));
|
||||
if (string.IsNullOrWhiteSpace(view)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(view));
|
||||
|
||||
Key = key;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullOrEmptyException(nameof(name));
|
||||
Name = name;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(view)) throw new ArgumentNullOrEmptyException(nameof(view));
|
||||
View = view;
|
||||
}
|
||||
|
||||
@@ -47,10 +48,12 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// from the name of the property marked with this attribute.</remarks>
|
||||
public ConfigurationFieldAttribute(string name, string view)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullOrEmptyException(nameof(name));
|
||||
Name = name;
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(name));
|
||||
if (view == null) throw new ArgumentNullException(nameof(view));
|
||||
if (string.IsNullOrWhiteSpace(view)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(view));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(view)) throw new ArgumentNullOrEmptyException(nameof(view));
|
||||
Name = name;
|
||||
View = view;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using Umbraco.Core.Exceptions;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
@@ -53,17 +52,17 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// </remarks>
|
||||
public DataEditorAttribute(string alias, EditorType type, string name, string view)
|
||||
{
|
||||
if ((type & ~(EditorType.PropertyValue | EditorType.MacroParameter)) > 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(type), $"Not a valid {typeof(EditorType)} value.");
|
||||
if (alias == null) throw new ArgumentNullException(nameof(alias));
|
||||
if (string.IsNullOrWhiteSpace(alias)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(alias));
|
||||
if ((type & ~(EditorType.PropertyValue | EditorType.MacroParameter)) > 0) throw new ArgumentOutOfRangeException(nameof(type), type, $"Not a valid {typeof(EditorType)} value.");
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(name));
|
||||
if (view == null) throw new ArgumentNullException(nameof(view));
|
||||
if (string.IsNullOrWhiteSpace(view)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(view));
|
||||
|
||||
Type = type;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(alias)) throw new ArgumentNullOrEmptyException(nameof(alias));
|
||||
Alias = alias;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullOrEmptyException(nameof(name));
|
||||
Name = name;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(view)) throw new ArgumentNullOrEmptyException(nameof(view));
|
||||
View = view == NullView ? null : view;
|
||||
}
|
||||
|
||||
@@ -100,8 +99,10 @@ namespace Umbraco.Core.PropertyEditors
|
||||
get => _valueType;
|
||||
set
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value)) throw new ArgumentNullOrEmptyException(nameof(value));
|
||||
if (!ValueTypes.IsValue(value)) throw new ArgumentOutOfRangeException(nameof(value), $"Not a valid {typeof(ValueTypes)} value.");
|
||||
if (value == null) throw new ArgumentNullException(nameof(value));
|
||||
if (string.IsNullOrWhiteSpace(value)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(value));
|
||||
if (!ValueTypes.IsValue(value)) throw new ArgumentOutOfRangeException(nameof(value), value, $"Not a valid {typeof(ValueTypes)} value.");
|
||||
|
||||
_valueType = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@ namespace Umbraco.Core.PropertyEditors
|
||||
[JsonProperty("name", Required = Required.Always)]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("nameTemplate")]
|
||||
public string NameTemplate { get; set; }
|
||||
|
||||
[JsonProperty("alias", Required = Required.Always)]
|
||||
public string Alias { get; set; }
|
||||
|
||||
|
||||
@@ -21,4 +21,4 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// </remarks>
|
||||
IEnumerable<ValidationResult> ValidateFormat(object value, string valueType, string format);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,4 +19,4 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// </remarks>
|
||||
IEnumerable<ValidationResult> ValidateRequired(object value, string valueType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.RegularExpressions;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors.Validators
|
||||
@@ -48,8 +47,9 @@ namespace Umbraco.Core.PropertyEditors.Validators
|
||||
get => _regex;
|
||||
set
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
throw new ArgumentNullOrEmptyException(nameof(value));
|
||||
if (value == null) throw new ArgumentNullException(nameof(value));
|
||||
if (string.IsNullOrWhiteSpace(value)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(value));
|
||||
|
||||
_regex = value;
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,9 @@ namespace Umbraco.Core.PropertyEditors.Validators
|
||||
public IEnumerable<ValidationResult> Validate(object value, string valueType, object dataTypeConfiguration)
|
||||
{
|
||||
if (_regex == null)
|
||||
{
|
||||
throw new InvalidOperationException("The validator has not been configured.");
|
||||
}
|
||||
|
||||
return ValidateFormat(value, valueType, _regex);
|
||||
}
|
||||
@@ -66,9 +68,12 @@ namespace Umbraco.Core.PropertyEditors.Validators
|
||||
/// <inheritdoc cref="IValueFormatValidator.ValidateFormat"/>
|
||||
public IEnumerable<ValidationResult> ValidateFormat(object value, string valueType, string format)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(format)) throw new ArgumentNullOrEmptyException(nameof(format));
|
||||
if (format == null) throw new ArgumentNullException(nameof(format));
|
||||
if (string.IsNullOrWhiteSpace(format)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(format));
|
||||
if (value == null || !new Regex(format).IsMatch(value.ToString()))
|
||||
{
|
||||
yield return new ValidationResult(_textService.Localize("validation", "invalidPattern"), new[] { "value" });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,14 +35,17 @@ namespace Umbraco.Core.PropertyEditors.Validators
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
yield return new ValidationResult(_textService.Localize("validation", "invalidNull"), new[] {"value"});
|
||||
yield return new ValidationResult(_textService.Localize("validation", "invalidNull"), new[] { "value" });
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (valueType.InvariantEquals(ValueTypes.Json))
|
||||
{
|
||||
if (value.ToString().DetectIsEmptyJson())
|
||||
{
|
||||
yield return new ValidationResult(_textService.Localize("validation", "invalidEmpty"), new[] { "value" });
|
||||
}
|
||||
|
||||
yield break;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using Umbraco.Core.Exceptions;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
@@ -29,10 +28,14 @@ namespace Umbraco.Core
|
||||
/// <typeparam name="TDeclaring">The declaring type.</typeparam>
|
||||
/// <typeparam name="TValue">The field type.</typeparam>
|
||||
/// <param name="fieldName">The name of the field.</param>
|
||||
/// <returns>A field getter function.</returns>
|
||||
/// <exception cref="ArgumentNullOrEmptyException">Occurs when <paramref name="fieldName"/> is null or empty.</exception>
|
||||
/// <exception cref="InvalidOperationException">Occurs when the field does not exist.</exception>
|
||||
/// <exception cref="ArgumentException">Occurs when <typeparamref name="TValue"/> does not match the type of the field.</exception>
|
||||
/// <returns>
|
||||
/// A field getter function.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">fieldName</exception>
|
||||
/// <exception cref="ArgumentException">Value can't be empty or consist only of white-space characters. - <paramref name="fieldName" />
|
||||
/// or
|
||||
/// Value type <typeparamref name="TValue" /> does not match field <typeparamref name="TDeclaring" />.<paramref name="fieldName" /> type.</exception>
|
||||
/// <exception cref="InvalidOperationException">Could not find field <typeparamref name="TDeclaring" />.<paramref name="fieldName" />.</exception>
|
||||
public static Func<TDeclaring, TValue> EmitFieldGetter<TDeclaring, TValue>(string fieldName)
|
||||
{
|
||||
var field = GetField<TDeclaring, TValue>(fieldName);
|
||||
@@ -45,10 +48,14 @@ namespace Umbraco.Core
|
||||
/// <typeparam name="TDeclaring">The declaring type.</typeparam>
|
||||
/// <typeparam name="TValue">The field type.</typeparam>
|
||||
/// <param name="fieldName">The name of the field.</param>
|
||||
/// <returns>A field setter action.</returns>
|
||||
/// <exception cref="ArgumentNullOrEmptyException">Occurs when <paramref name="fieldName"/> is null or empty.</exception>
|
||||
/// <exception cref="InvalidOperationException">Occurs when the field does not exist.</exception>
|
||||
/// <exception cref="ArgumentException">Occurs when <typeparamref name="TValue"/> does not match the type of the field.</exception>
|
||||
/// <returns>
|
||||
/// A field setter action.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">fieldName</exception>
|
||||
/// <exception cref="ArgumentException">Value can't be empty or consist only of white-space characters. - <paramref name="fieldName" />
|
||||
/// or
|
||||
/// Value type <typeparamref name="TValue" /> does not match field <typeparamref name="TDeclaring" />.<paramref name="fieldName" /> type.</exception>
|
||||
/// <exception cref="InvalidOperationException">Could not find field <typeparamref name="TDeclaring" />.<paramref name="fieldName" />.</exception>
|
||||
public static Action<TDeclaring, TValue> EmitFieldSetter<TDeclaring, TValue>(string fieldName)
|
||||
{
|
||||
var field = GetField<TDeclaring, TValue>(fieldName);
|
||||
@@ -61,19 +68,36 @@ namespace Umbraco.Core
|
||||
/// <typeparam name="TDeclaring">The declaring type.</typeparam>
|
||||
/// <typeparam name="TValue">The field type.</typeparam>
|
||||
/// <param name="fieldName">The name of the field.</param>
|
||||
/// <returns>A field getter and setter functions.</returns>
|
||||
/// <exception cref="ArgumentNullOrEmptyException">Occurs when <paramref name="fieldName"/> is null or empty.</exception>
|
||||
/// <exception cref="InvalidOperationException">Occurs when the field does not exist.</exception>
|
||||
/// <exception cref="ArgumentException">Occurs when <typeparamref name="TValue"/> does not match the type of the field.</exception>
|
||||
/// <returns>
|
||||
/// A field getter and setter functions.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">fieldName</exception>
|
||||
/// <exception cref="ArgumentException">Value can't be empty or consist only of white-space characters. - <paramref name="fieldName" />
|
||||
/// or
|
||||
/// Value type <typeparamref name="TValue" /> does not match field <typeparamref name="TDeclaring" />.<paramref name="fieldName" /> type.</exception>
|
||||
/// <exception cref="InvalidOperationException">Could not find field <typeparamref name="TDeclaring" />.<paramref name="fieldName" />.</exception>
|
||||
public static (Func<TDeclaring, TValue>, Action<TDeclaring, TValue>) EmitFieldGetterAndSetter<TDeclaring, TValue>(string fieldName)
|
||||
{
|
||||
var field = GetField<TDeclaring, TValue>(fieldName);
|
||||
return (EmitFieldGetter<TDeclaring, TValue>(field), EmitFieldSetter<TDeclaring, TValue>(field));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the field.
|
||||
/// </summary>
|
||||
/// <typeparam name="TDeclaring">The type of the declaring.</typeparam>
|
||||
/// <typeparam name="TValue">The type of the value.</typeparam>
|
||||
/// <param name="fieldName">Name of the field.</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentNullException">fieldName</exception>
|
||||
/// <exception cref="ArgumentException">Value can't be empty or consist only of white-space characters. - <paramref name="fieldName" />
|
||||
/// or
|
||||
/// Value type <typeparamref name="TValue" /> does not match field <typeparamref name="TDeclaring" />.<paramref name="fieldName" /> type.</exception>
|
||||
/// <exception cref="InvalidOperationException">Could not find field <typeparamref name="TDeclaring" />.<paramref name="fieldName" />.</exception>
|
||||
private static FieldInfo GetField<TDeclaring, TValue>(string fieldName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(fieldName)) throw new ArgumentNullOrEmptyException(nameof(fieldName));
|
||||
if (fieldName == null) throw new ArgumentNullException(nameof(fieldName));
|
||||
if (string.IsNullOrWhiteSpace(fieldName)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(fieldName));
|
||||
|
||||
// get the field
|
||||
var field = typeof(TDeclaring).GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
@@ -120,13 +144,18 @@ namespace Umbraco.Core
|
||||
/// <typeparam name="TValue">The property type.</typeparam>
|
||||
/// <param name="propertyName">The name of the property.</param>
|
||||
/// <param name="mustExist">A value indicating whether the property and its getter must exist.</param>
|
||||
/// <returns>A property getter function. If <paramref name="mustExist"/> is <c>false</c>, returns null when the property or its getter does not exist.</returns>
|
||||
/// <exception cref="ArgumentNullOrEmptyException">Occurs when <paramref name="propertyName"/> is null or empty.</exception>
|
||||
/// <exception cref="InvalidOperationException">Occurs when the property or its getter does not exist.</exception>
|
||||
/// <exception cref="ArgumentException">Occurs when <typeparamref name="TValue"/> does not match the type of the property.</exception>
|
||||
/// <returns>
|
||||
/// A property getter function. If <paramref name="mustExist" /> is <c>false</c>, returns null when the property or its getter does not exist.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">propertyName</exception>
|
||||
/// <exception cref="ArgumentException">Value can't be empty or consist only of white-space characters. - <paramref name="propertyName" />
|
||||
/// or
|
||||
/// Value type <typeparamref name="TValue" /> does not match property <typeparamref name="TDeclaring" />.<paramref name="propertyName" /> type.</exception>
|
||||
/// <exception cref="InvalidOperationException">Could not find property getter for <typeparamref name="TDeclaring" />.<paramref name="propertyName" />.</exception>
|
||||
public static Func<TDeclaring, TValue> EmitPropertyGetter<TDeclaring, TValue>(string propertyName, bool mustExist = true)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(propertyName)) throw new ArgumentNullOrEmptyException(nameof(propertyName));
|
||||
if (propertyName == null) throw new ArgumentNullException(nameof(propertyName));
|
||||
if (string.IsNullOrWhiteSpace(propertyName)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(propertyName));
|
||||
|
||||
var property = typeof(TDeclaring).GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
|
||||
@@ -146,13 +175,18 @@ namespace Umbraco.Core
|
||||
/// <typeparam name="TValue">The property type.</typeparam>
|
||||
/// <param name="propertyName">The name of the property.</param>
|
||||
/// <param name="mustExist">A value indicating whether the property and its setter must exist.</param>
|
||||
/// <returns>A property setter function. If <paramref name="mustExist"/> is <c>false</c>, returns null when the property or its setter does not exist.</returns>
|
||||
/// <exception cref="ArgumentNullOrEmptyException">Occurs when <paramref name="propertyName"/> is null or empty.</exception>
|
||||
/// <exception cref="InvalidOperationException">Occurs when the property or its setter does not exist.</exception>
|
||||
/// <exception cref="ArgumentException">Occurs when <typeparamref name="TValue"/> does not match the type of the property.</exception>
|
||||
/// <returns>
|
||||
/// A property setter function. If <paramref name="mustExist" /> is <c>false</c>, returns null when the property or its setter does not exist.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">propertyName</exception>
|
||||
/// <exception cref="ArgumentException">Value can't be empty or consist only of white-space characters. - <paramref name="propertyName" />
|
||||
/// or
|
||||
/// Value type <typeparamref name="TValue" /> does not match property <typeparamref name="TDeclaring" />.<paramref name="propertyName" /> type.</exception>
|
||||
/// <exception cref="InvalidOperationException">Could not find property setter for <typeparamref name="TDeclaring" />.<paramref name="propertyName" />.</exception>
|
||||
public static Action<TDeclaring, TValue> EmitPropertySetter<TDeclaring, TValue>(string propertyName, bool mustExist = true)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(propertyName)) throw new ArgumentNullOrEmptyException(nameof(propertyName));
|
||||
if (propertyName == null) throw new ArgumentNullException(nameof(propertyName));
|
||||
if (string.IsNullOrWhiteSpace(propertyName)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(propertyName));
|
||||
|
||||
var property = typeof(TDeclaring).GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
|
||||
@@ -172,13 +206,18 @@ namespace Umbraco.Core
|
||||
/// <typeparam name="TValue">The property type.</typeparam>
|
||||
/// <param name="propertyName">The name of the property.</param>
|
||||
/// <param name="mustExist">A value indicating whether the property and its getter and setter must exist.</param>
|
||||
/// <returns>A property getter and setter functions. If <paramref name="mustExist"/> is <c>false</c>, returns null when the property or its getter or setter does not exist.</returns>
|
||||
/// <exception cref="ArgumentNullOrEmptyException">Occurs when <paramref name="propertyName"/> is null or empty.</exception>
|
||||
/// <exception cref="InvalidOperationException">Occurs when the property or its getter or setter does not exist.</exception>
|
||||
/// <exception cref="ArgumentException">Occurs when <typeparamref name="TValue"/> does not match the type of the property.</exception>
|
||||
/// <returns>
|
||||
/// A property getter and setter functions. If <paramref name="mustExist" /> is <c>false</c>, returns null when the property or its getter or setter does not exist.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">propertyName</exception>
|
||||
/// <exception cref="ArgumentException">Value can't be empty or consist only of white-space characters. - <paramref name="propertyName" />
|
||||
/// or
|
||||
/// Value type <typeparamref name="TValue" /> does not match property <typeparamref name="TDeclaring" />.<paramref name="propertyName" /> type.</exception>
|
||||
/// <exception cref="InvalidOperationException">Could not find property getter and setter for <typeparamref name="TDeclaring" />.<paramref name="propertyName" />.</exception>
|
||||
public static (Func<TDeclaring, TValue>, Action<TDeclaring, TValue>) EmitPropertyGetterAndSetter<TDeclaring, TValue>(string propertyName, bool mustExist = true)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(propertyName)) throw new ArgumentNullOrEmptyException(nameof(propertyName));
|
||||
if (propertyName == null) throw new ArgumentNullException(nameof(propertyName));
|
||||
if (string.IsNullOrWhiteSpace(propertyName)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(propertyName));
|
||||
|
||||
var property = typeof(TDeclaring).GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
|
||||
@@ -402,13 +441,17 @@ namespace Umbraco.Core
|
||||
/// <typeparam name="TLambda">A lambda representing the method.</typeparam>
|
||||
/// <param name="methodName">The name of the method.</param>
|
||||
/// <param name="mustExist">A value indicating whether the constructor must exist.</param>
|
||||
/// <returns>The method. If <paramref name="mustExist"/> is <c>false</c>, returns null when the method does not exist.</returns>
|
||||
/// <returns>
|
||||
/// The method. If <paramref name="mustExist" /> is <c>false</c>, returns null when the method does not exist.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">methodName</exception>
|
||||
/// <exception cref="ArgumentException">Value can't be empty or consist only of white-space characters. - <paramref name="methodName" />
|
||||
/// or
|
||||
/// Occurs when <typeparamref name="TLambda" /> does not match the method signature..</exception>
|
||||
/// <exception cref="InvalidOperationException">Occurs when no proper method with name <paramref name="methodName" /> could be found.</exception>
|
||||
/// <remarks>
|
||||
/// <para>The method arguments are determined by <typeparamref name="TLambda"/> generic arguments.</para>
|
||||
/// The method arguments are determined by <typeparamref name="TLambda" /> generic arguments.
|
||||
/// </remarks>
|
||||
/// <exception cref="ArgumentNullOrEmptyException">Occurs when <paramref name="methodName"/> is null or empty.</exception>
|
||||
/// <exception cref="InvalidOperationException">Occurs when no proper method with name <paramref name="methodName"/> could be found.</exception>
|
||||
/// <exception cref="ArgumentException">Occurs when Occurs when <typeparamref name="TLambda"/> does not match the method signature.</exception>
|
||||
public static TLambda EmitMethod<TDeclaring, TLambda>(string methodName, bool mustExist = true)
|
||||
{
|
||||
return EmitMethod<TLambda>(typeof(TDeclaring), methodName, mustExist);
|
||||
@@ -421,16 +464,21 @@ namespace Umbraco.Core
|
||||
/// <param name="declaring">The declaring type.</param>
|
||||
/// <param name="methodName">The name of the method.</param>
|
||||
/// <param name="mustExist">A value indicating whether the constructor must exist.</param>
|
||||
/// <returns>The method. If <paramref name="mustExist"/> is <c>false</c>, returns null when the method does not exist.</returns>
|
||||
/// <returns>
|
||||
/// The method. If <paramref name="mustExist" /> is <c>false</c>, returns null when the method does not exist.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">methodName</exception>
|
||||
/// <exception cref="ArgumentException">Value can't be empty or consist only of white-space characters. - <paramref name="methodName" />
|
||||
/// or
|
||||
/// Occurs when <typeparamref name="TLambda" /> does not match the method signature..</exception>
|
||||
/// <exception cref="InvalidOperationException">Occurs when no proper method with name <paramref name="methodName" /> could be found.</exception>
|
||||
/// <remarks>
|
||||
/// <para>The method arguments are determined by <typeparamref name="TLambda"/> generic arguments.</para>
|
||||
/// The method arguments are determined by <typeparamref name="TLambda" /> generic arguments.
|
||||
/// </remarks>
|
||||
/// <exception cref="ArgumentNullOrEmptyException">Occurs when <paramref name="methodName"/> is null or empty.</exception>
|
||||
/// <exception cref="InvalidOperationException">Occurs when no proper method with name <paramref name="methodName"/> could be found.</exception>
|
||||
/// <exception cref="ArgumentException">Occurs when Occurs when <typeparamref name="TLambda"/> does not match the method signature.</exception>
|
||||
public static TLambda EmitMethod<TLambda>(Type declaring, string methodName, bool mustExist = true)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(methodName)) throw new ArgumentNullOrEmptyException(nameof(methodName));
|
||||
if (methodName == null) throw new ArgumentNullException(nameof(methodName));
|
||||
if (string.IsNullOrWhiteSpace(methodName)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(methodName));
|
||||
|
||||
var (lambdaDeclaring, lambdaParameters, lambdaReturned) = AnalyzeLambda<TLambda>(true, out var isFunction);
|
||||
|
||||
@@ -510,17 +558,21 @@ namespace Umbraco.Core
|
||||
/// <typeparam name="TLambda">A lambda representing the method.</typeparam>
|
||||
/// <param name="methodName">The name of the method.</param>
|
||||
/// <param name="mustExist">A value indicating whether the constructor must exist.</param>
|
||||
/// <returns>The method. If <paramref name="mustExist"/> is <c>false</c>, returns null when the method does not exist.</returns>
|
||||
/// <returns>
|
||||
/// The method. If <paramref name="mustExist" /> is <c>false</c>, returns null when the method does not exist.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">methodName</exception>
|
||||
/// <exception cref="ArgumentException">Value can't be empty or consist only of white-space characters. - <paramref name="methodName" />
|
||||
/// or
|
||||
/// Occurs when <typeparamref name="TLambda" /> does not match the method signature..</exception>
|
||||
/// <exception cref="InvalidOperationException">Occurs when no proper method with name <paramref name="methodName" /> could be found.</exception>
|
||||
/// <remarks>
|
||||
/// <para>The method arguments are determined by <typeparamref name="TLambda"/> generic arguments.</para>
|
||||
/// The method arguments are determined by <typeparamref name="TLambda" /> generic arguments.
|
||||
/// </remarks>
|
||||
/// <exception cref="ArgumentNullOrEmptyException">Occurs when <paramref name="methodName"/> is null or empty.</exception>
|
||||
/// <exception cref="InvalidOperationException">Occurs when no proper method with name <paramref name="methodName"/> could be found.</exception>
|
||||
/// <exception cref="ArgumentException">Occurs when Occurs when <typeparamref name="TLambda"/> does not match the method signature.</exception>
|
||||
public static TLambda EmitMethod<TLambda>(string methodName, bool mustExist = true)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(methodName))
|
||||
throw new ArgumentNullOrEmptyException(nameof(methodName));
|
||||
if (methodName == null) throw new ArgumentNullException(nameof(methodName));
|
||||
if (string.IsNullOrWhiteSpace(methodName)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(methodName));
|
||||
|
||||
// validate lambda type
|
||||
var (lambdaDeclaring, lambdaParameters, lambdaReturned) = AnalyzeLambda<TLambda>(false, out var isFunction);
|
||||
|
||||
@@ -33,8 +33,6 @@ namespace Umbraco.Core.Scoping
|
||||
private ICompletable _fscope;
|
||||
private IEventDispatcher _eventDispatcher;
|
||||
|
||||
private const IsolationLevel DefaultIsolationLevel = IsolationLevel.RepeatableRead;
|
||||
|
||||
// initializes a new scope
|
||||
private Scope(ScopeProvider scopeProvider,
|
||||
ILogger logger, FileSystems fileSystems, Scope parent, ScopeContext scopeContext, bool detachable,
|
||||
@@ -205,7 +203,7 @@ namespace Umbraco.Core.Scoping
|
||||
{
|
||||
if (_isolationLevel != IsolationLevel.Unspecified) return _isolationLevel;
|
||||
if (ParentScope != null) return ParentScope.IsolationLevel;
|
||||
return DefaultIsolationLevel;
|
||||
return Database.SqlContext.SqlSyntax.DefaultIsolationLevel;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -488,37 +486,9 @@ namespace Umbraco.Core.Scoping
|
||||
?? (_logUncompletedScopes = Current.Configs.CoreDebug().LogUncompletedScopes)).Value;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ReadLock(params int[] lockIds)
|
||||
{
|
||||
// soon as we get Database, a transaction is started
|
||||
|
||||
if (Database.Transaction.IsolationLevel < IsolationLevel.RepeatableRead)
|
||||
throw new InvalidOperationException("A transaction with minimum RepeatableRead isolation level is required.");
|
||||
|
||||
// *not* using a unique 'WHERE IN' query here because the *order* of lockIds is important to avoid deadlocks
|
||||
foreach (var lockId in lockIds)
|
||||
{
|
||||
var i = Database.ExecuteScalar<int?>("SELECT value FROM umbracoLock WHERE id=@id", new { id = lockId });
|
||||
if (i == null) // ensure we are actually locking!
|
||||
throw new Exception($"LockObject with id={lockId} does not exist.");
|
||||
}
|
||||
}
|
||||
public void ReadLock(params int[] lockIds) => Database.SqlContext.SqlSyntax.ReadLock(Database, lockIds);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void WriteLock(params int[] lockIds)
|
||||
{
|
||||
// soon as we get Database, a transaction is started
|
||||
|
||||
if (Database.Transaction.IsolationLevel < IsolationLevel.RepeatableRead)
|
||||
throw new InvalidOperationException("A transaction with minimum RepeatableRead isolation level is required.");
|
||||
|
||||
// *not* using a unique 'WHERE IN' query here because the *order* of lockIds is important to avoid deadlocks
|
||||
foreach (var lockId in lockIds)
|
||||
{
|
||||
var i = Database.Execute("UPDATE umbracoLock SET value = (CASE WHEN (value=1) THEN -1 ELSE 1 END) WHERE id=@id", new { id = lockId });
|
||||
if (i == 0) // ensure we are actually locking!
|
||||
throw new Exception($"LockObject with id={lockId} does not exist.");
|
||||
}
|
||||
}
|
||||
public void WriteLock(params int[] lockIds) => Database.SqlContext.SqlSyntax.WriteLock(Database, lockIds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ using System.Threading.Tasks;
|
||||
using System.Web.Security;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Mapping;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Identity;
|
||||
@@ -217,7 +216,8 @@ namespace Umbraco.Core.Security
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
if (user == null) throw new ArgumentNullException(nameof(user));
|
||||
if (string.IsNullOrEmpty(passwordHash)) throw new ArgumentNullOrEmptyException(nameof(passwordHash));
|
||||
if (passwordHash == null) throw new ArgumentNullException(nameof(passwordHash));
|
||||
if (string.IsNullOrEmpty(passwordHash)) throw new ArgumentException("Value can't be empty.", nameof(passwordHash));
|
||||
|
||||
user.PasswordHash = passwordHash;
|
||||
|
||||
@@ -329,7 +329,7 @@ namespace Umbraco.Core.Security
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
if (user == null) throw new ArgumentNullException(nameof(user));
|
||||
if (login == null) throw new ArgumentNullException("login");
|
||||
if (login == null) throw new ArgumentNullException(nameof(login));
|
||||
|
||||
var logins = user.Logins;
|
||||
var instance = new IdentityUserLogin(login.LoginProvider, login.ProviderKey, user.Id);
|
||||
@@ -348,7 +348,7 @@ namespace Umbraco.Core.Security
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
if (user == null) throw new ArgumentNullException(nameof(user));
|
||||
if (login == null) throw new ArgumentNullException("login");
|
||||
if (login == null) throw new ArgumentNullException(nameof(login));
|
||||
|
||||
var provider = login.LoginProvider;
|
||||
var key = login.ProviderKey;
|
||||
@@ -379,7 +379,7 @@ namespace Umbraco.Core.Security
|
||||
public Task<BackOfficeIdentityUser> FindAsync(UserLoginInfo login)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
if (login == null) throw new ArgumentNullException("login");
|
||||
if (login == null) throw new ArgumentNullException(nameof(login));
|
||||
|
||||
//get all logins associated with the login id
|
||||
var result = _externalLoginService.Find(login).ToArray();
|
||||
@@ -413,7 +413,8 @@ namespace Umbraco.Core.Security
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
if (user == null) throw new ArgumentNullException(nameof(user));
|
||||
if (string.IsNullOrWhiteSpace(roleName)) throw new ArgumentException("Value cannot be null or whitespace.", "roleName");
|
||||
if (roleName == null) throw new ArgumentNullException(nameof(roleName));
|
||||
if (string.IsNullOrWhiteSpace(roleName)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(roleName));
|
||||
|
||||
var userRole = user.Roles.SingleOrDefault(r => r.RoleId == roleName);
|
||||
|
||||
@@ -434,7 +435,8 @@ namespace Umbraco.Core.Security
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
if (user == null) throw new ArgumentNullException(nameof(user));
|
||||
if (string.IsNullOrWhiteSpace(roleName)) throw new ArgumentException("Value cannot be null or whitespace.", "roleName");
|
||||
if (roleName == null) throw new ArgumentNullException(nameof(roleName));
|
||||
if (string.IsNullOrWhiteSpace(roleName)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(roleName));
|
||||
|
||||
var userRole = user.Roles.SingleOrDefault(r => r.RoleId == roleName);
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Umbraco.Core.Services
|
||||
/// <summary>
|
||||
/// Gets a content type.
|
||||
/// </summary>
|
||||
TItem Get(int id);
|
||||
new TItem Get(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a content type.
|
||||
@@ -40,6 +40,7 @@ namespace Umbraco.Core.Services
|
||||
int Count();
|
||||
|
||||
IEnumerable<TItem> GetAll(params int[] ids);
|
||||
IEnumerable<TItem> GetAll(IEnumerable<Guid> ids);
|
||||
|
||||
IEnumerable<TItem> GetDescendants(int id, bool andSelf); // parent-child axis
|
||||
IEnumerable<TItem> GetComposedOf(int id); // composition axis
|
||||
|
||||
@@ -10,6 +10,13 @@ namespace Umbraco.Core.Services
|
||||
/// </summary>
|
||||
public interface IDataTypeService : IService
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a dictionary of content type <see cref="Udi"/>s and the property type aliases that use a <see cref="IDataType"/>
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
IReadOnlyDictionary<Udi, IEnumerable<string>> GetReferences(int id);
|
||||
|
||||
Attempt<OperationResult<OperationResultType, EntityContainer>> CreateContainer(int parentId, string name, int userId = Constants.Security.SuperUserId);
|
||||
Attempt<OperationResult> SaveContainer(EntityContainer container, int userId = Constants.Security.SuperUserId);
|
||||
EntityContainer GetContainer(int containerId);
|
||||
|
||||
@@ -2885,7 +2885,8 @@ namespace Umbraco.Core.Services.Implement
|
||||
|
||||
private IContentType GetContentType(IScope scope, string contentTypeAlias)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(contentTypeAlias)) throw new ArgumentNullOrEmptyException(nameof(contentTypeAlias));
|
||||
if (contentTypeAlias == null) throw new ArgumentNullException(nameof(contentTypeAlias));
|
||||
if (string.IsNullOrWhiteSpace(contentTypeAlias)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(contentTypeAlias));
|
||||
|
||||
scope.ReadLock(Constants.Locks.ContentTypes);
|
||||
|
||||
@@ -2900,7 +2901,8 @@ namespace Umbraco.Core.Services.Implement
|
||||
|
||||
private IContentType GetContentType(string contentTypeAlias)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(contentTypeAlias)) throw new ArgumentNullOrEmptyException(nameof(contentTypeAlias));
|
||||
if (contentTypeAlias == null) throw new ArgumentNullException(nameof(contentTypeAlias));
|
||||
if (string.IsNullOrWhiteSpace(contentTypeAlias)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(contentTypeAlias));
|
||||
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
@@ -3083,7 +3085,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
var version = GetVersion(versionId);
|
||||
|
||||
//Good ole null checks
|
||||
if (content == null || version == null)
|
||||
if (content == null || version == null || content.Trashed)
|
||||
{
|
||||
return new OperationResult(OperationResultType.FailedCannot, evtMsgs);
|
||||
}
|
||||
|
||||
+5
-6
@@ -252,12 +252,12 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<TItem> GetAll(params Guid[] ids)
|
||||
public IEnumerable<TItem> GetAll(IEnumerable<Guid> ids)
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
scope.ReadLock(ReadLockIds);
|
||||
return Repository.GetMany(ids);
|
||||
return Repository.GetMany(ids.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -595,10 +595,9 @@ namespace Umbraco.Core.Services.Implement
|
||||
public TItem Copy(TItem original, string alias, string name, TItem parent)
|
||||
{
|
||||
if (original == null) throw new ArgumentNullException(nameof(original));
|
||||
if (string.IsNullOrWhiteSpace(alias)) throw new ArgumentNullOrEmptyException(nameof(alias));
|
||||
|
||||
if (parent != null && parent.HasIdentity == false)
|
||||
throw new InvalidOperationException("Parent must have an identity.");
|
||||
if (alias == null) throw new ArgumentNullException(nameof(alias));
|
||||
if (string.IsNullOrWhiteSpace(alias)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(alias));
|
||||
if (parent != null && parent.HasIdentity == false) throw new InvalidOperationException("Parent must have an identity.");
|
||||
|
||||
// this is illegal
|
||||
//var originalb = (ContentTypeCompositionBase)original;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user