diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..3baa5dbe66 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,80 @@ +# Code of Conduct + +## 1. Purpose + +A primary goal of Umbraco CMS is to be inclusive to the largest number of contributors, with the most varied and diverse backgrounds possible. As such, we are committed to providing a friendly, safe and welcoming environment for all, regardless of gender, sexual orientation, ability, ethnicity, socioeconomic status, and religion (or lack thereof). + +This code of conduct outlines our expectations for all those who participate in our community, as well as the consequences for unacceptable behavior. + +We invite all those who participate in Umbraco CMS to help us create safe and positive experiences for everyone. + +## 2. Open Source Citizenship + +A supplemental goal of this Code of Conduct is to increase open source citizenship by encouraging participants to recognize and strengthen the relationships between our actions and their effects on our community. + +Communities mirror the societies in which they exist and positive action is essential to counteract the many forms of inequality and abuses of power that exist in society. + +If you see someone who is making an extra effort to ensure our community is welcoming, friendly, and encourages all participants to contribute to the fullest extent, we want to know. + +## 3. Expected Behavior + +The following behaviors are expected and requested of all community members: + +* Participate in an authentic and active way. In doing so, you contribute to the health and longevity of this community. +* Exercise consideration and respect in your speech and actions. +* Attempt collaboration before conflict. +* Refrain from demeaning, discriminatory, or harassing behavior and speech. +* Be mindful of your surroundings and of your fellow participants. Alert community leaders if you notice a dangerous situation, someone in distress, or violations of this Code of Conduct, even if they seem inconsequential. +* Remember that community event venues may be shared with members of the public; please be respectful to all patrons of these locations. + +## 4. Unacceptable Behavior + +The following behaviors are considered harassment and are unacceptable within our community: + +* Violence, threats of violence or violent language directed against another person. +* Sexist, racist, homophobic, transphobic, ableist or otherwise discriminatory jokes and language. +* Posting or displaying sexually explicit or violent material. +* Posting or threatening to post other people’s personally identifying information ("doxing"). +* Personal insults, particularly those related to gender, sexual orientation, race, religion, or disability. +* Inappropriate photography or recording. +* Inappropriate physical contact. You should have someone’s consent before touching them. +* Unwelcome sexual attention. This includes, sexualized comments or jokes; inappropriate touching, groping, and unwelcomed sexual advances. +* Deliberate intimidation, stalking or following (online or in person). +* Advocating for, or encouraging, any of the above behavior. +* Sustained disruption of community events, including talks and presentations. + +## 5. Consequences of Unacceptable Behavior + +Unacceptable behavior from any community member, including sponsors and those with decision-making authority, will not be tolerated. + +Anyone asked to stop unacceptable behavior is expected to comply immediately. + +If a community member engages in unacceptable behavior, the community organizers may take any action they deem appropriate, up to and including a temporary ban or permanent expulsion from the community without warning (and without refund in the case of a paid event). + +## 6. Reporting Guidelines + +If you are subject to or witness unacceptable behavior, or have any other concerns, please notify a community organizer as soon as possible. Please contact Sebastiaan Janssen - [sj@umbraco.dk](mailto:sj@umbraco.dk). + +Additionally, community organizers are available to help community members engage with local law enforcement or to otherwise help those experiencing unacceptable behavior feel safe. In the context of in-person events, organizers will also provide escorts as desired by the person experiencing distress. + +## 7. Addressing Grievances + +If you feel you have been falsely or unfairly accused of violating this Code of Conduct, you should notify Umbraco with a concise description of your grievance. Your grievance will be handled in accordance with our existing governing policies. + +## 8. Scope + +We expect all community participants (contributors, paid or otherwise; sponsors; and other guests) to abide by this Code of Conduct in all community venues–online and in-person–as well as in all one-on-one communications pertaining to community business. + +This code of conduct and its related procedures also applies to unacceptable behavior occurring outside the scope of community activities when such behavior has the potential to adversely affect the safety and well-being of community members. + +## 9. Contact info + +Sebastiaan Janssen - [sj@umbraco.dk](mailto:sj@umbraco.dk) + +## 10. License and attribution + +This Code of Conduct is distributed under a [Creative Commons Attribution-ShareAlike license](http://creativecommons.org/licenses/by-sa/3.0/). + +Portions of text derived from the [Django Code of Conduct](https://www.djangoproject.com/conduct/) and the [Geek Feminism Anti-Harassment Policy](http://geekfeminism.wikia.com/wiki/Conference_anti-harassment/Policy). + +Retrieved on November 22, 2016 from [http://citizencodeofconduct.org/](http://citizencodeofconduct.org/) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..0e87f9824d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,207 @@ +# Contributing to Umbraco CMS + +👍🎉 First off, thanks for taking the time to contribute! 🎉👍 + +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. + +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 💖. + +#### Table Of Contents + +[Code of Conduct](#code-of-conduct) + +[How Can I Contribute?](#how-can-i-contribute) + * [Reporting Bugs](#reporting-bugs) + * [Suggesting Enhancements](#suggesting-enhancements) + * [Your First Code Contribution](#your-first-code-contribution) + * [Pull Requests](#pull-requests) + +[Styleguides](#styleguides) + +[What should I know before I get started?](#what-should-i-know-before-i-get-started) + * [Working with the source code](#working-with-the-source-code) + * [What branch should I target for my contributions?](#what-branch-should-i-target-for-my-contributions) + * [Building Umbraco from source code](#building-umbraco-from-source-code) + * [Keeping your Umbraco fork in sync with the main repository](#keeping-your-umbraco-fork-in-sync-with-the-main-repository) + +[How do I even begin?](#how-do-i-even-begin) + +[Problems?](#problems) + +[Credits](#credits) + +## 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). + +## How Can I Contribute? + +### Reporting Bugs +This section guides you through submitting a bug report for Umbraco CMS. Following these guidelines helps maintainers and the community understand your report 📝, reproduce the behavior 💻 💻, and find related reports 🔎. + +Before creating bug reports, please check [this list](#before-submitting-a-bug-report) as you might find out that you don't need to create one. When you are creating a bug report, please [include as many details as possible](#how-do-i-submit-a-good-bug-report). Fill out [the required template](ISSUE_TEMPLATE.md), the information it asks for helps us resolve issues faster. + +> **Note:** If you find a **Closed** issue that seems like it is the same thing that you're experiencing, open a new issue and include a link to the original issue in the body of your new one. + +##### Before Submitting A Bug Report + + * Most importantly, check **if you can reproduce the problem** in the [latest version of Umbraco](https://our.umbraco.org/download/). We might have already fixed your particular problem. + * It also helps tremendously to check if the issue you're experiencing is present in **a clean install** of the Umbraco version you're currently using. Custom code can have side-effects that don't occur in a clean install. + * **Use the Google**. Whatever you're experiencing, Google it plus "Umbraco" - usually you can get some pretty good hints from the search results, including open issues and further troubleshooting hints. + * If you do find and existing issue has **and the issue is still open**, add a comment to the existing issue if you have additional information. If you have the same problem and no new info to add, just "star" the issue. + +Explain the problem and include additional details to help maintainers reproduce the problem. The following is a long description which we've boiled down into a few very simple question in the issue tracker when you create a new issue. We're listing the following hints to indicate that the most successful reports usually have a lot of this ground covered: + + * **Use a clear and descriptive title** for the issue to identify the problem. + * **Describe the exact steps which reproduce the problem** in as many details as possible. For example, start by explaining which steps you took in the backoffice to get to a certain undesireable result, e.g. you created a document type, inherting 3 levels deep, added a certain datatype, tried to save it and you got an error. + * **Provide specific examples to demonstrate the steps**. If you wrote some code, try to provide a code sample as specific as possible to be able to reproduce the behavior. + * **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that behavior. + * **Explain which behavior you expected to see instead and why.** + +Provide more context by answering these questions: + + * **Can you reproduce the problem** when `debug="false"` in your `web.config` file? + * **Did the problem start happening recently** (e.g. after updating to a new version of Umbraco) or was this always a problem? + * **Can you reliably reproduce the issue?** If not, provide details about how often the problem happens and under which conditions it normally happens. + +Include details about your configuration and environment: + + * **Which version of Umbraco are you using?** + * **What is the environment you're using Umbraco in?** Is this a problem on your local machine or on a server. Tell us about your configuration: Windows version, IIS/IISExpress, database type, etc. + * **Which packages do you have installed?** + +### Suggesting Enhancements + +This section guides you through submitting an enhancement suggestion for Atom, including completely new features and minor improvements to existing functionality. Following these guidelines helps maintainers and the community understand your suggestion 📝 and find related suggestions 🔎. + +Most of the suggestions in the [reporting bugs](#reporting-bugs) section also count for suggesting enhancements. + +Some additional hints that may be helpful: + + * **Include screenshots and animated GIFs** which help you demonstrate the steps or point out the part of Umbraco which the suggestion is related to. + * **Explain why this enhancement would be useful to most Umbraco users** and isn't something that can or should be implemented as a [community package](https://our.umbraco.org/projects/). + +### Your First Code Contribution + +Unsure where to begin contributing to Umbraco? You can start by looking through [these `Up for grabs` and issues](http://issues.umbraco.org/issues/U4?q=%28project%3A+%7BU4%7D+Difficulty%3A+%7BVery+Easy%7D+%23Easy+%23Unresolved+Priority%3A+Normal+%23Major+%23Show-stopper+State%3A+-%7BIn+Progress%7D+sort+by%3A+votes+Affected+versions%3A+-6.*+Affected+versions%3A+-4.*%29+OR+%28tag%3A+%7BUp+For+Grabs%7D+%23Unresolved+%29). + +The issue list is sorted by total number of upvotes. While not perfect, number of upvotes is a reasonable proxy for impact a given change will have. + +### Pull Requests + +The most successful pull requests usually look a like this: + + * Fill in the required template + * 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.org/documentation/Reference/) is generated + +Again, these are guidelines, not strict requirements. + +## Styleguides + +To be honest, we don't like rules very much. We trust you have the best of intentions and we encourage you to create working code. If it doesn't look perfect then we'll happily help clean it up. + +That said, the Umbraco development team likes to follow the hints that ReSharper gives us (no problem if you don't have this installed) and we've added a `.editorconfig` file so that Visual Studio knows what to do with whitespace, line endings, etc. + +## What should I know before I get started? + +### Working with the source code + +Some parts of our source code is 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: + + 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: + ``` + npm cache clean + npm install -g bower + npm install -g gulp + npm install -g gulp-cli + npm install + gulp build + ``` + 2. "The rest" is a C# based codebase, with some traces of our WebForms past but mostly ASP.NET MVC based these days. 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. + + * [The AngularJS based backoffice files](https://our.umbraco.org/apidocs/ui/#/api) (to be found in `src\Umbraco.Web.UI.Client\src`) + * [The rest](https://our.umbraco.org/apidocs/csharp/) + +### What 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 `dev-v7`. Whatever the default is, that's where we'd like you to target your contributions. + +![What branch do you want me to target?](tools/contributing/defaultbranch.png) + +### Building Umbraco from source code + +The easiest way to get started is to run `build.bat` 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. + +Alternatively, you can open `src\umbraco.sln` in Visual Studio 2017 ([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. + +![Gulp build in Visual Studio](tools/contributing/gulpbuild.png) + +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. + +### 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. + +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. + +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 +``` + +Then when you want to get the changes from the main repository: + +``` +git fetch upstream +git rebase upstream/dev-v7 +``` + +In this command we're syncing with the `dev-v7` 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)) + +## How do I even begin? + +Great question! The short version goes like this: + + * **Fork** - create a fork of [`Umbraco-CMS` on GitHub](https://github.com/umbraco/Umbraco-CMS) + + ![Fork the repository](tools/contributing/forkrepository.png) + + * **Clone** - when GitHub has created your fork, you can clone it in your favorite Git tool + + ![Clone the fork](tools/contributing/clonefork.png) + + * **Build** - build your fork of Umbraco locally as described in [building Umbraco from source code](#building-umbraco-from-source-code) + * **Change** - make your changes, experiment, have fun, explore and learn, and don't be afraid. We welcome all contributions and will happily give feedback + * **Commit** - done? Yay! 🎉 It is recommended to create a new branch now and name it after the issue you're fixing, we usually follow the format: `temp-U4-12345`. This means it's a temporary branch for the particular issue you're working on, in this case `U4-12345` + * **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 a pull request](tools/contributing/createpullrequest.png) + +The Umbraco development 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. + +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! + +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 at this and we'll be nice about it, thanking you for spending your valueable time. + +Remember, if an issue is in the `Up for grabs` list or you've asked for some feedback before you send us a PR, your PR will not be closed as unwanted. + +## Problems? + +Did something not work as expected? Try leaving a note in the ["Contributing to Umbraco"](https://our.umbraco.org/forum/contributing-to-umbraco-cms/) forum, the team monitors that one closely! + +## Credits + +This contribution guide borrows heavily from the excellent work on [the Atom contribution guide](https://github.com/atom/atom/blob/master/CONTRIBUTING.md). A big [#h5yr](http://h5yr.com/) to them! diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..db1e5c88bd --- /dev/null +++ b/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,11 @@ +### Prerequisites + +- [ ] I have written a descriptive pull-request title +- [ ] I have linked this PR to an issue on the tracker at http://issues.umbraco.org + +### Description + + + + + diff --git a/README.md b/README.md index 80fed871e2..afedc5f5a7 100644 --- a/README.md +++ b/README.md @@ -6,21 +6,14 @@ The friendliest, most flexible and fastest growing ASP.NET CMS used by more than [![ScreenShot](vimeo.png)](https://vimeo.com/172382998/) -## Umbraco CMS ## +## Umbraco CMS Umbraco is a free open source Content Management System built on the ASP.NET platform. Our mission is to help you deliver delightful digital experiences by making Umbraco friendly, simpler and social. - -## Building Umbraco from source ## - -The easiest way to get started is to run `build.bat` 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. - -Note that you can always [download a nightly build](http://nightly.umbraco.org/?container=umbraco-750) so you don't have to build the code yourself. - -## Watch an introduction video ## +## Watch an introduction video [![ScreenShot](http://umbraco.com/images/whatisumbraco.png)](https://umbraco.tv/videos/umbraco-v7/content-editor/basics/introduction/cms-explanation/) -## Umbraco - The Friendly CMS ## +## Umbraco - The Friendly CMS For the first time on the Microsoft platform, there is a free user and developer friendly CMS that makes it quick and easy to create websites - or a breeze to build complex web applications. Umbraco has award-winning integration capabilities and supports ASP.NET MVC or Web Forms, including User and Custom Controls, out of the box. @@ -30,22 +23,24 @@ Used by more than 443,000 active websites including Carlsberg, Segway, Amazon an To view more examples, please visit [https://umbraco.com/why-umbraco/#caseStudies](https://umbraco.com/why-umbraco/#caseStudies) -## Why Open Source? ## +## Why Open Source? As an Open Source platform, Umbraco is more than just a CMS. We are transparent with our roadmap for future versions, our incremental sprint planning notes are publicly accessible and community contributions and packages are available for all to use. -## Downloading ## +## Trying out Umbraco CMS -The downloadable Umbraco releases live at [https://our.umbraco.org/download](https://our.umbraco.org/download). +[Umbraco Cloud](https://umbraco.com) is the easiest and fastest way to use Umbraco yet with full support for all your custom .NET code and intergrations. 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. -## Forums ## +If you want to DIY you can [download Umbraco](https://our.umbraco.org/download) either as a ZIP file or via NuGet. It's the same version of Umbraco CMS that powers Umbraco Xloud, but you'll need to find a place to host yourself and handling deployments and upgrades is all down to you. -Peer-to-peer support is available 24/7 at the community forum on [https://our.umbraco.org](https://our.umbraco.org). +## Community -## Contribute to Umbraco ## +Our friendly community is available 24/7 at the community hub we call ["Our Umbraco"](https://our.umbraco.org). Our Umbraco feature forums for questions and answers, documentation, downloadable plugins for Umbraco and a rich collection of community resources. -Umbraco is contribution focused and community driven. If you want to contribute back to Umbraco please check out our [guide to contributing](https://our.umbraco.org/contribute). +## Contribute to Umbraco -## Found a bug? ## +Umbraco is contribution focused and community driven. If you want to contribute back to Umbraco please check out our [guide to contributing](CONTRIBUTING.md). + +## Found a bug? Another way you can contribute to Umbraco is by providing issue reports. For information on how to submit an issue report refer to our [online guide for reporting issues](https://our.umbraco.org/contribute/report-an-issue-or-request-a-feature). diff --git a/build/Modules/Umbraco.Build/Get-UmbracoBuildEnv.ps1 b/build/Modules/Umbraco.Build/Get-UmbracoBuildEnv.ps1 index 2df42e5fd8..9b465fd78d 100644 --- a/build/Modules/Umbraco.Build/Get-UmbracoBuildEnv.ps1 +++ b/build/Modules/Umbraco.Build/Get-UmbracoBuildEnv.ps1 @@ -8,6 +8,7 @@ function Get-UmbracoBuildEnv # store tools in the module's directory # and cache them for two days $path = "$PSScriptRoot\temp" + $src = "$PSScriptRoot\..\..\..\src" $cache = 2 if (-not (test-path $path)) @@ -37,7 +38,7 @@ function Get-UmbracoBuildEnv if (-not (test-path $sevenZip)) { Write-Host "Download 7-Zip..." - &$nuget install 7-Zip.CommandLine -OutputDirectory $path -Verbosity quiet + &$nuget install 7-Zip.CommandLine -configFile "$src\NuGet.config" -OutputDirectory $path -Verbosity quiet $dir = ls "$path\7-Zip.CommandLine.*" | sort -property Name -descending | select -first 1 $file = ls -path "$dir" -name 7za.exe -recurse $file = ls -path "$dir" -name 7za.exe -recurse | select -first 1 #A select is because there is tools\7za.exe & tools\x64\7za.exe @@ -54,7 +55,7 @@ function Get-UmbracoBuildEnv if (-not (test-path $vswhere)) { Write-Host "Download VsWhere..." - &$nuget install vswhere -OutputDirectory $path -Verbosity quiet + &$nuget install vswhere -configFile "$src\NuGet.config" -OutputDirectory $path -Verbosity quiet $dir = ls "$path\vswhere.*" | sort -property Name -descending | select -first 1 $file = ls -path "$dir" -name vswhere.exe -recurse mv "$dir\$file" $vswhere @@ -70,7 +71,7 @@ function Get-UmbracoBuildEnv if (-not (test-path $semver)) { Write-Host "Download Semver..." - &$nuget install semver -OutputDirectory $path -Verbosity quiet + &$nuget install semver -configFile "$src\NuGet.config" -OutputDirectory $path -Verbosity quiet $dir = ls "$path\semver.*" | sort -property Name -descending | select -first 1 $file = "$dir\lib\net452\Semver.dll" if (-not (test-path $file)) diff --git a/build/Modules/Umbraco.Build/Umbraco.Build.psm1 b/build/Modules/Umbraco.Build/Umbraco.Build.psm1 index dde1ef6467..61cc0abe3f 100644 --- a/build/Modules/Umbraco.Build/Umbraco.Build.psm1 +++ b/build/Modules/Umbraco.Build/Umbraco.Build.psm1 @@ -445,7 +445,7 @@ function Restore-NuGet Write-Host ">> Restore NuGet" Write-Host "Logging to $tmp\nuget.restore.log" - &$uenv.NuGet restore "$src\Umbraco.sln" > "$tmp\nuget.restore.log" + &$uenv.NuGet restore "$src\Umbraco.sln" -configfile "$src\NuGet.config" > "$tmp\nuget.restore.log" } # diff --git a/build/NuSpecs/tools/ReadmeUpgrade.txt b/build/NuSpecs/tools/ReadmeUpgrade.txt index e85b22a902..2b6da733a1 100644 --- a/build/NuSpecs/tools/ReadmeUpgrade.txt +++ b/build/NuSpecs/tools/ReadmeUpgrade.txt @@ -8,7 +8,7 @@ ---------------------------------------------------- -*** IMPORTANT NOTICE FOR 7.7 UPGRADES *** +*** IMPORTANT NOTICE FOR UPGRADES FROM VERSIONS BELOW 7.7.0 *** Be sure to read the version specific upgrade information before proceeding: https://our.umbraco.org/documentation/Getting-Started/Setup/Upgrading/version-specific#version-7-7-0 diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs index ace98f2139..279cc645e2 100644 --- a/src/SolutionInfo.cs +++ b/src/SolutionInfo.cs @@ -11,5 +11,5 @@ using System.Resources; [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("7.9.0")] -[assembly: AssemblyInformationalVersion("7.9.0")] \ No newline at end of file +[assembly: AssemblyFileVersion("7.9.2")] +[assembly: AssemblyInformationalVersion("7.9.2")] \ No newline at end of file diff --git a/src/Umbraco.Core/Configuration/UmbracoVersion.cs b/src/Umbraco.Core/Configuration/UmbracoVersion.cs index 1e5da5f0b3..e3ecd4c5b0 100644 --- a/src/Umbraco.Core/Configuration/UmbracoVersion.cs +++ b/src/Umbraco.Core/Configuration/UmbracoVersion.cs @@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration { public class UmbracoVersion { - private static readonly Version Version = new Version("7.9.0"); + private static readonly Version Version = new Version("7.9.2"); /// /// Gets the current version of Umbraco. diff --git a/src/Umbraco.Core/Security/UmbracoBackOfficeIdentity.cs b/src/Umbraco.Core/Security/UmbracoBackOfficeIdentity.cs index 022b15c8be..fcb5547027 100644 --- a/src/Umbraco.Core/Security/UmbracoBackOfficeIdentity.cs +++ b/src/Umbraco.Core/Security/UmbracoBackOfficeIdentity.cs @@ -37,15 +37,15 @@ namespace Umbraco.Core.Security var username = identity.GetUserName(); var session = identity.FindFirstValue(Constants.Security.SessionIdClaimType); var securityStamp = identity.FindFirstValue(Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType); - var startContentId = identity.FindFirstValue(Constants.Security.StartContentNodeIdClaimType); + var startContentId = identity.FindFirstValue(Constants.Security.StartContentNodeIdClaimType); var startMediaId = identity.FindFirstValue(Constants.Security.StartMediaNodeIdClaimType); var culture = identity.FindFirstValue(ClaimTypes.Locality); - var id = identity.FindFirstValue(ClaimTypes.NameIdentifier); + var id = identity.FindFirstValue(ClaimTypes.NameIdentifier); var realName = identity.FindFirstValue(ClaimTypes.GivenName); - if (username == null || startContentId == null || startMediaId == null - || culture == null || id == null + if (username == null || startContentId == null || startMediaId == null + || culture == null || id == null || realName == null || session == null) throw new InvalidOperationException("Cannot create a " + typeof(UmbracoBackOfficeIdentity) + " from " + typeof(ClaimsIdentity) + " since there are missing required claims"); @@ -62,7 +62,7 @@ namespace Umbraco.Core.Security catch (Exception e) { throw new InvalidOperationException("Cannot create a " + typeof(UmbracoBackOfficeIdentity) + " from " + typeof(ClaimsIdentity) + " since the data is not formatted correctly - either content or media start Ids could not be parsed as JSON", e); - } + } var roles = identity.FindAll(x => x.Type == DefaultRoleClaimType).Select(role => role.Value).ToList(); var allowedApps = identity.FindAll(x => x.Type == Constants.Security.AllowedApplicationsClaimType).Select(app => app.Value).ToList(); @@ -165,7 +165,7 @@ namespace Umbraco.Core.Security { foreach (var claim in claimsIdentity.Claims) { - //In one special case we will replace a claim if it exists already and that is the + //In one special case we will replace a claim if it exists already and that is the // Forms auth claim for name which automatically gets added TryRemoveClaim(FindFirst(x => x.Type == claim.Type && x.Issuer == "Forms")); @@ -187,15 +187,15 @@ namespace Umbraco.Core.Security { ClaimTypes.NameIdentifier, //id ClaimTypes.Name, //username - ClaimTypes.GivenName, + ClaimTypes.GivenName, Constants.Security.StartContentNodeIdClaimType, - Constants.Security.StartMediaNodeIdClaimType, - ClaimTypes.Locality, + Constants.Security.StartMediaNodeIdClaimType, + ClaimTypes.Locality, Constants.Security.SessionIdClaimType, Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType }; } - } + } /// /// Adds claims based on the UserData data @@ -222,23 +222,19 @@ namespace Umbraco.Core.Security AddClaim(new Claim(ClaimTypes.Locality, Culture, ClaimValueTypes.String, Issuer, Issuer, this)); if (HasClaim(x => x.Type == Constants.Security.SessionIdClaimType) == false && SessionId.IsNullOrWhiteSpace() == false) - { AddClaim(new Claim(Constants.Security.SessionIdClaimType, SessionId, ClaimValueTypes.String, Issuer, Issuer, this)); - //The security stamp claim is also required... this is because this claim type is hard coded - // by the SecurityStampValidator, see: https://katanaproject.codeplex.com/workitem/444 - if (HasClaim(x => x.Type == Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType) == false) - { - AddClaim(new Claim(Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType, SecurityStamp, ClaimValueTypes.String, Issuer, Issuer, this)); - } - } + //The security stamp claim is also required... this is because this claim type is hard coded + // by the SecurityStampValidator, see: https://katanaproject.codeplex.com/workitem/444 + if (HasClaim(x => x.Type == Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType) == false) + AddClaim(new Claim(Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType, SecurityStamp, ClaimValueTypes.String, Issuer, Issuer, this)); //Add each app as a separate claim if (HasClaim(x => x.Type == Constants.Security.AllowedApplicationsClaimType) == false) { foreach (var application in AllowedApplications) { - AddClaim(new Claim(Constants.Security.AllowedApplicationsClaimType, application, ClaimValueTypes.String, Issuer, Issuer, this)); + AddClaim(new Claim(Constants.Security.AllowedApplicationsClaimType, application, ClaimValueTypes.String, Issuer, Issuer, this)); } } @@ -253,8 +249,8 @@ namespace Umbraco.Core.Security } } - - + + } protected internal UserData UserData { get; private set; } @@ -332,4 +328,4 @@ namespace Umbraco.Core.Security } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Core/UriExtensions.cs b/src/Umbraco.Core/UriExtensions.cs index cddd4ef83f..dd3ae8c10c 100644 --- a/src/Umbraco.Core/UriExtensions.cs +++ b/src/Umbraco.Core/UriExtensions.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; using Umbraco.Core.Configuration; using Umbraco.Core.IO; +using Umbraco.Core.Logging; namespace Umbraco.Core { @@ -142,10 +143,18 @@ namespace Umbraco.Core /// internal static bool IsClientSideRequest(this Uri url) { - var ext = Path.GetExtension(url.LocalPath); - if (ext.IsNullOrWhiteSpace()) return false; - var toInclude = new[] { ".aspx", ".ashx", ".asmx", ".axd", ".svc" }; - return toInclude.Any(ext.InvariantEquals) == false; + try + { + var ext = Path.GetExtension(url.LocalPath); + if (ext.IsNullOrWhiteSpace()) return false; + var toInclude = new[] {".aspx", ".ashx", ".asmx", ".axd", ".svc"}; + return toInclude.Any(ext.InvariantEquals) == false; + } + catch (ArgumentException ex) + { + LogHelper.Error(typeof(UriExtensions), "Failed to determine if request was client side", ex); + return false; + } } /// @@ -311,4 +320,4 @@ namespace Umbraco.Core return new Uri(uri.GetComponents(UriComponents.AbsoluteUri & ~UriComponents.Port, UriFormat.UriEscaped)); } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs b/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs index a976c8ad8c..741a2106cd 100644 --- a/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs +++ b/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs @@ -494,18 +494,18 @@ namespace Umbraco.Tests.Models.Mapping //TODO: Now we need to assert all of the more complicated parts - Assert.AreEqual(contentType.PropertyGroups.Count(), result.Groups.Count()); - for (var i = 0; i < contentType.PropertyGroups.Count(); i++) + Assert.AreEqual(contentType.PropertyGroups.Count, result.Groups.Count()); + for (var i = 0; i < contentType.PropertyGroups.Count; i++) { - Assert.AreEqual(contentType.PropertyGroups.ElementAt(i).Id, result.Groups.ElementAt(i).Id); - Assert.AreEqual(contentType.PropertyGroups.ElementAt(i).Name, result.Groups.ElementAt(i).Name); - var propTypes = contentType.PropertyGroups.ElementAt(i).PropertyTypes; + Assert.AreEqual(contentType.PropertyGroups[i].Id, result.Groups.ElementAt(i).Id); + Assert.AreEqual(contentType.PropertyGroups[i].Name, result.Groups.ElementAt(i).Name); + var propTypes = contentType.PropertyGroups[i].PropertyTypes; - Assert.AreEqual(propTypes.Count(), result.Groups.ElementAt(i).Properties.Count()); - for (var j = 0; j < propTypes.Count(); j++) + Assert.AreEqual(propTypes.Count, result.Groups.ElementAt(i).Properties.Count()); + for (var j = 0; j < propTypes.Count; j++) { - Assert.AreEqual(propTypes.ElementAt(j).Id, result.Groups.ElementAt(i).Properties.ElementAt(j).Id); - Assert.AreEqual(propTypes.ElementAt(j).DataTypeDefinitionId, result.Groups.ElementAt(i).Properties.ElementAt(j).DataTypeId); + Assert.AreEqual(propTypes[j].Id, result.Groups.ElementAt(i).Properties.ElementAt(j).Id); + Assert.AreEqual(propTypes[j].DataTypeDefinitionId, result.Groups.ElementAt(i).Properties.ElementAt(j).DataTypeId); } } diff --git a/src/Umbraco.Tests/Models/Mapping/ContentWebModelMappingTests.cs b/src/Umbraco.Tests/Models/Mapping/ContentWebModelMappingTests.cs index b7fa65131f..cbda2162ee 100644 --- a/src/Umbraco.Tests/Models/Mapping/ContentWebModelMappingTests.cs +++ b/src/Umbraco.Tests/Models/Mapping/ContentWebModelMappingTests.cs @@ -126,6 +126,23 @@ namespace Umbraco.Tests.Models.Mapping Assert.IsTrue(result.Tabs.Except(new[] {result.Tabs.First()}).All(x => x.IsActive == false)); } + [Test] + public void To_Display_Model_No_Tabs() + { + var contentType = MockedContentTypes.CreateSimpleContentType(); + contentType.PropertyGroups.Clear(); + var content = new Content("Home", -1, contentType) { Level = 1, SortOrder = 1, CreatorId = 0, WriterId = 0 }; + + var result = Mapper.Map(content); + + AssertBasics(result, content); + foreach (var p in content.Properties) + { + AssertDisplayProperty(result, p, ApplicationContext); + } + Assert.AreEqual(content.PropertyGroups.Count(), result.Tabs.Count()); + } + [Test] public void To_Display_Model_With_Non_Grouped_Properties() { diff --git a/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs b/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs index 3c3686aded..db7b399f33 100644 --- a/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs +++ b/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs @@ -93,53 +93,59 @@ namespace Umbraco.Tests.Routing var result = uri.IsClientSideRequest(); Assert.AreEqual(assert, result); } + + [Test] + public void Is_Client_Side_Request_InvalidPath_ReturnFalse() + { + //This url is invalid. Default to false when the extension cannot be determined + var uri = new Uri("http://test.com/installing-modules+foobar+\"yipee\""); + var result = uri.IsClientSideRequest(); + Assert.AreEqual(false, result); + } + //NOTE: This test shows how we can test most of the HttpModule, it however is testing a method that no longer exists and is testing too much, + // we need to write unit tests for each of the components: NiceUrlProvider, all of the Lookup classes, etc... + // to ensure that each one is individually tested. + //[TestCase("/", 1046)] + //[TestCase("/home.aspx", 1046)] + //[TestCase("/home/sub1.aspx", 1173)] + //[TestCase("/home.aspx?altTemplate=blah", 1046)] + //public void Process_Front_End_Document_Request_Match_Node(string url, int nodeId) + //{ + // var httpContextFactory = new FakeHttpContextFactory(url); + // var httpContext = httpContextFactory.HttpContext; + // var umbracoContext = new UmbracoContext(httpContext, ApplicationContext.Current, new NullRoutesCache()); + // var contentStore = new ContentStore(umbracoContext); + // var niceUrls = new NiceUrlProvider(contentStore, umbracoContext); + // umbracoContext.RoutingContext = new RoutingContext( + // new IPublishedContentLookup[] {new LookupByNiceUrl()}, + // new DefaultLastChanceLookup(), + // contentStore, + // niceUrls); + // StateHelper.HttpContext = httpContext; - //NOTE: This test shows how we can test most of the HttpModule, it however is testing a method that no longer exists and is testing too much, - // we need to write unit tests for each of the components: NiceUrlProvider, all of the Lookup classes, etc... - // to ensure that each one is individually tested. + // //because of so much dependency on the db, we need to create som stuff here, i originally abstracted out stuff but + // //was turning out to be quite a deep hole because ultimately we'd have to abstract the old 'Domain' and 'Language' classes + // Domain.MakeNew("Test.com", 1000, Language.GetByCultureCode("en-US").id); - //[TestCase("/", 1046)] - //[TestCase("/home.aspx", 1046)] - //[TestCase("/home/sub1.aspx", 1173)] - //[TestCase("/home.aspx?altTemplate=blah", 1046)] - //public void Process_Front_End_Document_Request_Match_Node(string url, int nodeId) - //{ - // var httpContextFactory = new FakeHttpContextFactory(url); - // var httpContext = httpContextFactory.HttpContext; - // var umbracoContext = new UmbracoContext(httpContext, ApplicationContext.Current, new NullRoutesCache()); - // var contentStore = new ContentStore(umbracoContext); - // var niceUrls = new NiceUrlProvider(contentStore, umbracoContext); - // umbracoContext.RoutingContext = new RoutingContext( - // new IPublishedContentLookup[] {new LookupByNiceUrl()}, - // new DefaultLastChanceLookup(), - // contentStore, - // niceUrls); + // //need to create a template with id 1045 + // var template = Template.MakeNew("test", new User(0)); - // StateHelper.HttpContext = httpContext; + // SetupUmbracoContextForTest(umbracoContext, template); - // //because of so much dependency on the db, we need to create som stuff here, i originally abstracted out stuff but - // //was turning out to be quite a deep hole because ultimately we'd have to abstract the old 'Domain' and 'Language' classes - // Domain.MakeNew("Test.com", 1000, Language.GetByCultureCode("en-US").id); + // _module.AssignDocumentRequest(httpContext, umbracoContext, httpContext.Request.Url); - // //need to create a template with id 1045 - // var template = Template.MakeNew("test", new User(0)); + // Assert.IsNotNull(umbracoContext.PublishedContentRequest); + // Assert.IsNotNull(umbracoContext.PublishedContentRequest.XmlNode); + // Assert.IsFalse(umbracoContext.PublishedContentRequest.IsRedirect); + // Assert.IsFalse(umbracoContext.PublishedContentRequest.Is404); + // Assert.AreEqual(umbracoContext.PublishedContentRequest.Culture, Thread.CurrentThread.CurrentCulture); + // Assert.AreEqual(umbracoContext.PublishedContentRequest.Culture, Thread.CurrentThread.CurrentUICulture); + // Assert.AreEqual(nodeId, umbracoContext.PublishedContentRequest.NodeId); - // SetupUmbracoContextForTest(umbracoContext, template); + //} - // _module.AssignDocumentRequest(httpContext, umbracoContext, httpContext.Request.Url); - - // Assert.IsNotNull(umbracoContext.PublishedContentRequest); - // Assert.IsNotNull(umbracoContext.PublishedContentRequest.XmlNode); - // Assert.IsFalse(umbracoContext.PublishedContentRequest.IsRedirect); - // Assert.IsFalse(umbracoContext.PublishedContentRequest.Is404); - // Assert.AreEqual(umbracoContext.PublishedContentRequest.Culture, Thread.CurrentThread.CurrentCulture); - // Assert.AreEqual(umbracoContext.PublishedContentRequest.Culture, Thread.CurrentThread.CurrentUICulture); - // Assert.AreEqual(nodeId, umbracoContext.PublishedContentRequest.NodeId); - - //} - - } -} \ No newline at end of file + } +} diff --git a/src/Umbraco.Web.UI.Client/src/assets/img/installer.jpg b/src/Umbraco.Web.UI.Client/src/assets/img/installer.jpg index d7800af062..bca6553dbb 100644 Binary files a/src/Umbraco.Web.UI.Client/src/assets/img/installer.jpg and b/src/Umbraco.Web.UI.Client/src/assets/img/installer.jpg differ diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js index fbd66ca032..b2bbd9006a 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js @@ -8,6 +8,8 @@ var evts = []; var isInfoTab = false; scope.publishStatus = {}; + + scope.disableTemplates = Umbraco.Sys.ServerVariables.features.disabledFeatures.disableTemplates; function onInit() { @@ -50,7 +52,7 @@ scope.openDocumentType = function (documentType) { var url = "/settings/documenttypes/edit/" + documentType.id; - $location.path(url); + $location.url(url); }; scope.updateTemplate = function (templateAlias) { diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/validation/nodirtycheck.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/nodirtycheck.directive.js index e15f62e8df..104736530f 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/validation/nodirtycheck.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/nodirtycheck.directive.js @@ -10,12 +10,12 @@ function noDirtyCheck() { require: 'ngModel', link: function (scope, elm, attrs, ctrl) { - elm.focus(function () { - scope.$watch(function() { - ctrl.$pristine = false; - }); - }); - + var alwaysFalse = { + get: function () { return false; }, + set: function () { } + }; + Object.defineProperty(ctrl, '$pristine', alwaysFalse); + Object.defineProperty(ctrl, '$dirty', alwaysFalse); } }; diff --git a/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js b/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js index dddf99b84f..78dec2f065 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js @@ -267,10 +267,10 @@ // by looking at the key switch (foundAlias[0]) { case "umbracoMemberLockedOut": - saveModel.isLockedOut = prop.value.toString() === "1" ? true : false; + saveModel.isLockedOut = prop.value ? (prop.value.toString() === "1" ? true : false) : false; break; case "umbracoMemberApproved": - saveModel.isApproved = prop.value.toString() === "1" ? true : false; + saveModel.isApproved = prop.value ? (prop.value.toString() === "1" ? true : false) : true; break; case "umbracoMemberComments": saveModel.comments = prop.value; diff --git a/src/Umbraco.Web.UI.Client/src/less/property-editors.less b/src/Umbraco.Web.UI.Client/src/less/property-editors.less index 9bc287fdd9..b5300a0f67 100644 --- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less +++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less @@ -40,6 +40,16 @@ padding: 10px; } +.umb-contentpicker__min-max-help { + font-size: 13px; + margin-top: 5px; + color: @gray-4; +} + +.show-validation .umb-contentpicker__min-max-help { + display: none; +} + .umb-contentpicker small { &:not(:last-child) { @@ -109,22 +119,22 @@ ul.color-picker li a { } /* pre-value editor */ -/*.control-group.color-picker-preval:before { - content: ""; - display: inline-block; - vertical-align: middle; - height: 100%; -}*/ - -/*.control-group.color-picker-preval div.thumbnail { - display: inline-block; +/*.control-group.color-picker-preval:before { + content: ""; + display: inline-block; vertical-align: middle; -}*/ -.control-group.color-picker-preval div.color-picker-prediv { - display: inline-block; + height: 100%; +}*/ + +/*.control-group.color-picker-preval div.thumbnail { + display: inline-block; + vertical-align: middle; +}*/ +.control-group.color-picker-preval div.color-picker-prediv { + display: inline-block; width: 60%; -} - +} + .control-group.color-picker-preval pre { display: inline; margin-right: 20px; @@ -136,18 +146,18 @@ ul.color-picker li a { vertical-align: middle; } -.control-group.color-picker-preval btn { +.control-group.color-picker-preval btn { //vertical-align: middle; -} +} -.control-group.color-picker-preval input[type="text"] { - min-width: 40%; - width: 40%; - display: inline-block; - margin-right: 20px; +.control-group.color-picker-preval input[type="text"] { + min-width: 40%; + width: 40%; + display: inline-block; + margin-right: 20px; margin-top: 1px; -} - +} + .control-group.color-picker-preval label { border: solid @white 1px; padding: 6px; diff --git a/src/Umbraco.Web.UI.Client/src/views/components/application/umb-sections.html b/src/Umbraco.Web.UI.Client/src/views/components/application/umb-sections.html index befda0f8c9..9fa8fa6891 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/application/umb-sections.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/application/umb-sections.html @@ -14,7 +14,6 @@
  • @@ -42,8 +41,6 @@
  • public bool DevicePreview { get; set; } + + /// + /// If true, all references to templates will be removed in the back office and routing + /// + public bool DisableTemplates { get; set; } + } } diff --git a/src/Umbraco.Web/Features/UmbracoFeatures.cs b/src/Umbraco.Web/Features/UmbracoFeatures.cs index 8f65d6efb8..abe9a76d06 100644 --- a/src/Umbraco.Web/Features/UmbracoFeatures.cs +++ b/src/Umbraco.Web/Features/UmbracoFeatures.cs @@ -14,7 +14,6 @@ namespace Umbraco.Web.Features public UmbracoFeatures() { Disabled = new DisabledFeatures(); - Enabled = new EnabledFeatures(); } // note @@ -28,16 +27,11 @@ namespace Umbraco.Web.Features /// Gets the disabled features. ///
    public DisabledFeatures Disabled { get; set; } - + /// - /// Gets the enabled features. + /// Determines whether a controller is enabled. /// - public EnabledFeatures Enabled { get; set; } - - /// - /// Determines whether a feature is enabled. - /// - public bool IsEnabled(Type feature) + public bool IsControllerEnabled(Type feature) { if (typeof(UmbracoApiControllerBase).IsAssignableFrom(feature)) return Disabled.Controllers.Contains(feature) == false; diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentPropertyBasic.cs b/src/Umbraco.Web/Models/ContentEditing/ContentPropertyBasic.cs index f317771333..4ed46de135 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentPropertyBasic.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentPropertyBasic.cs @@ -30,6 +30,11 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "editor", IsRequired = false)] public string Editor { get; set; } + /// + /// Flags the property to denote that it can contain sensitive data + /// + [DataMember(Name = "isSensitive", IsRequired = false)] + public bool IsSensitive { get; set; } /// /// Used internally during model mapping @@ -38,4 +43,4 @@ namespace Umbraco.Web.Models.ContentEditing internal PropertyEditor PropertyEditor { get; set; } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs b/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs index 21cf4d1ec1..5b53f1ef8d 100644 --- a/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs @@ -80,17 +80,21 @@ namespace Umbraco.Web.Models.Mapping //FROM IMember TO MemberBasic config.CreateMap() - .ForMember(display => display.Udi, expression => expression.MapFrom(content => Udi.Create(Constants.UdiEntityType.Member, content.Key))) + .ForMember(display => display.Udi, + expression => + expression.MapFrom(content => Udi.Create(Constants.UdiEntityType.Member, content.Key))) .ForMember(dto => dto.Owner, expression => expression.ResolveUsing(new OwnerResolver())) .ForMember(dto => dto.Icon, expression => expression.MapFrom(content => content.ContentType.Icon)) - .ForMember(dto => dto.ContentTypeAlias, expression => expression.MapFrom(content => content.ContentType.Alias)) + .ForMember(dto => dto.ContentTypeAlias, + expression => expression.MapFrom(content => content.ContentType.Alias)) .ForMember(dto => dto.Email, expression => expression.MapFrom(content => content.Email)) .ForMember(dto => dto.Username, expression => expression.MapFrom(content => content.Username)) .ForMember(dto => dto.Trashed, expression => expression.Ignore()) .ForMember(dto => dto.Published, expression => expression.Ignore()) .ForMember(dto => dto.Updater, expression => expression.Ignore()) .ForMember(dto => dto.Alias, expression => expression.Ignore()) - .ForMember(dto => dto.HasPublishedVersion, expression => expression.Ignore()); + .ForMember(dto => dto.HasPublishedVersion, expression => expression.Ignore()) + .ForMember(dto => dto.Properties, expression => expression.ResolveUsing(new MemberBasicPropertiesResolver())); //FROM MembershipUser TO MemberBasic config.CreateMap() @@ -260,7 +264,7 @@ namespace Umbraco.Web.Models.Mapping { //it's a generic provider so update the locked out property based on our known constant alias var isLockedOutProperty = result.SelectMany(x => x.Properties).FirstOrDefault(x => x.Alias == Constants.Conventions.Member.IsLockedOut); - if (isLockedOutProperty != null && isLockedOutProperty.Value.ToString() != "1") + if (isLockedOutProperty?.Value != null && isLockedOutProperty.Value.ToString() != "1") { isLockedOutProperty.View = "readonlyvalue"; isLockedOutProperty.Value = _localizedTextService.Localize("general/no"); @@ -274,7 +278,7 @@ namespace Umbraco.Web.Models.Mapping // if we just had all of the membeship provider fields on the member table :( // TODO: But is there a way to map the IMember.IsLockedOut to the property ? i dunno. var isLockedOutProperty = result.SelectMany(x => x.Properties).FirstOrDefault(x => x.Alias == umbracoProvider.LockPropertyTypeAlias); - if (isLockedOutProperty != null && isLockedOutProperty.Value.ToString() != "1") + if (isLockedOutProperty?.Value != null && isLockedOutProperty.Value.ToString() != "1") { isLockedOutProperty.View = "readonlyvalue"; isLockedOutProperty.Value = _localizedTextService.Localize("general/no"); @@ -395,6 +399,8 @@ namespace Umbraco.Web.Models.Mapping //check permissions for viewing sensitive data if (isSensitiveProperty && umbracoContext.Security.CurrentUser.HasAccessToSensitiveData() == false) { + //mark this property as sensitive + prop.IsSensitive = true; //mark this property as readonly so that it does not post any data prop.Readonly = true; //replace this editor with a sensitivevalue @@ -477,8 +483,51 @@ namespace Umbraco.Web.Models.Mapping return AutoMapperExtensions.MapWithUmbracoContext(member, context.GetUmbracoContext()); } } + + /// + /// A resolver to map properties to a collection of + /// + internal class MemberBasicPropertiesResolver : IValueResolver + { + public ResolutionResult Resolve(ResolutionResult source) + { + if (source.Value != null && (source.Value is IMember) == false) + throw new AutoMapperMappingException(string.Format("Value supplied is of type {0} but expected {1}.\nChange the value resolver source type, or redirect the source value supplied to the value resolver using FromMember.", new object[] + { + source.Value.GetType(), + typeof (IMember) + })); + return source.New( + //perform the mapping with the current umbraco context + ResolveCore(source.Context.GetUmbracoContext(), (IMember)source.Value), typeof(IEnumerable)); + } + + private IEnumerable ResolveCore(UmbracoContext umbracoContext, IMember content) + { + var result = Mapper.Map, IEnumerable>( + // Sort properties so items from different compositions appear in correct order (see U4-9298). Map sorted properties. + content.Properties.OrderBy(prop => prop.PropertyType.SortOrder)) + .ToList(); + + var member = (IMember)content; + var memberType = member.ContentType; + + //now update the IsSensitive value + foreach (var prop in result) + { + //check if this property is flagged as sensitive + var isSensitiveProperty = memberType.IsSensitiveProperty(prop.Alias); + //check permissions for viewing sensitive data + if (isSensitiveProperty && umbracoContext.Security.CurrentUser.HasAccessToSensitiveData() == false) + { + //mark this property as sensitive + prop.IsSensitive = true; + //clear the value + prop.Value = null; + } + } + return result; + } + } } } - - - diff --git a/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs b/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs index 3792ba39ec..82d4855f32 100644 --- a/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs +++ b/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs @@ -1,7 +1,5 @@ using System; using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Globalization; using System.Linq; using AutoMapper; using Umbraco.Core; @@ -9,7 +7,6 @@ using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Web.Models.ContentEditing; -using umbraco; namespace Umbraco.Web.Models.Mapping { @@ -53,7 +50,7 @@ namespace Umbraco.Web.Models.Mapping //perform the mapping with the current umbraco context ResolveCore(source.Context.GetUmbracoContext(), (TSource)source.Value), typeof(List>)); } - + /// /// Adds the container (listview) tab to the document /// @@ -217,7 +214,8 @@ namespace Umbraco.Web.Models.Mapping MapGenericProperties(umbracoContext, content, tabs); // activate the first tab - tabs[0].IsActive = true; + if (tabs.Count > 0) + tabs[0].IsActive = true; return tabs; } @@ -274,7 +272,7 @@ namespace Umbraco.Web.Models.Mapping //now add the user props contentProps.AddRange(currProps); - + //re-assign genericProps.Properties = contentProps; @@ -307,6 +305,6 @@ namespace Umbraco.Web.Models.Mapping return result; } - + } } diff --git a/src/Umbraco.Web/Mvc/RenderRouteHandler.cs b/src/Umbraco.Web/Mvc/RenderRouteHandler.cs index 3dd52d9bfb..bacdd2ffa9 100644 --- a/src/Umbraco.Web/Mvc/RenderRouteHandler.cs +++ b/src/Umbraco.Web/Mvc/RenderRouteHandler.cs @@ -393,12 +393,12 @@ namespace Umbraco.Web.Mvc return GetWebFormsHandler(); } - //here we need to check if there is no hijacked route and no template assigned, if this is the case - //we want to return a blank page, but we'll leave that up to the NoTemplateHandler. - //we also check if we're allowed to render even though there's no template (json render in headless). - if (publishedContentRequest.HasTemplate == false && - routeDef.HasHijackedRoute == false && - FeaturesResolver.Current.Features.Enabled.RenderNoTemplate == false) + //Here we need to check if there is no hijacked route and no template assigned, + //if this is the case we want to return a blank page, but we'll leave that up to the NoTemplateHandler. + //We also check if templates have been disabled since if they are then we're allowed to render even though there's no template, + //for example for json rendering in headless. + if ((publishedContentRequest.HasTemplate == false && FeaturesResolver.Current.Features.Disabled.DisableTemplates == false) + && routeDef.HasHijackedRoute == false) { publishedContentRequest.UpdateOnMissingTemplate(); // will go 404 diff --git a/src/Umbraco.Web/Scheduling/ScheduledTasks.cs b/src/Umbraco.Web/Scheduling/ScheduledTasks.cs index c69d42bd27..ad7fef5fd9 100644 --- a/src/Umbraco.Web/Scheduling/ScheduledTasks.cs +++ b/src/Umbraco.Web/Scheduling/ScheduledTasks.cs @@ -63,6 +63,10 @@ namespace Umbraco.Web.Scheduling { using (var wc = new HttpClient()) { + if (Uri.TryCreate(_appContext.UmbracoApplicationUrl, UriKind.Absolute, out var baseUri)) + { + wc.BaseAddress = baseUri; + } var request = new HttpRequestMessage(HttpMethod.Get, url); //TODO: pass custom the authorization header, currently these aren't really secured! @@ -122,4 +126,4 @@ namespace Umbraco.Web.Scheduling get { return true; } } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Web/Search/UmbracoTreeSearcher.cs b/src/Umbraco.Web/Search/UmbracoTreeSearcher.cs index 0dac79590f..38347de9ed 100644 --- a/src/Umbraco.Web/Search/UmbracoTreeSearcher.cs +++ b/src/Umbraco.Web/Search/UmbracoTreeSearcher.cs @@ -208,6 +208,10 @@ namespace Umbraco.Web.Search if (sb == null) throw new ArgumentNullException("sb"); if (entityService == null) throw new ArgumentNullException("entityService"); + Udi udi; + Udi.TryParse(searchFrom, true, out udi); + searchFrom = udi == null ? searchFrom : entityService.GetIdForUdi(udi).Result.ToString(); + int searchFromId; var entityPath = int.TryParse(searchFrom, out searchFromId) && searchFromId > 0 ? entityService.GetAllPaths(objectType, searchFromId).FirstOrDefault() @@ -332,4 +336,4 @@ namespace Umbraco.Web.Search } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index a505fb477a..04f74fd62e 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -332,7 +332,6 @@ - diff --git a/src/Umbraco.Web/WebApi/Filters/FeatureAuthorizeAttribute.cs b/src/Umbraco.Web/WebApi/Filters/FeatureAuthorizeAttribute.cs index dd1954663f..098db125c9 100644 --- a/src/Umbraco.Web/WebApi/Filters/FeatureAuthorizeAttribute.cs +++ b/src/Umbraco.Web/WebApi/Filters/FeatureAuthorizeAttribute.cs @@ -17,7 +17,7 @@ namespace Umbraco.Web.WebApi.Filters if (FeaturesResolver.HasCurrent == false) return true; var controllerType = actionContext.ControllerContext.ControllerDescriptor.ControllerType; - return FeaturesResolver.Current.Features.IsEnabled(controllerType); + return FeaturesResolver.Current.Features.IsControllerEnabled(controllerType); } } } \ No newline at end of file diff --git a/tools/contributing/clonefork.png b/tools/contributing/clonefork.png new file mode 100644 index 0000000000..ef4e4f801d Binary files /dev/null and b/tools/contributing/clonefork.png differ diff --git a/tools/contributing/createpullrequest.png b/tools/contributing/createpullrequest.png new file mode 100644 index 0000000000..dd8fdaf478 Binary files /dev/null and b/tools/contributing/createpullrequest.png differ diff --git a/tools/contributing/defaultbranch.png b/tools/contributing/defaultbranch.png new file mode 100644 index 0000000000..0595e0b4ea Binary files /dev/null and b/tools/contributing/defaultbranch.png differ diff --git a/tools/contributing/forkrepository.png b/tools/contributing/forkrepository.png new file mode 100644 index 0000000000..30195ec247 Binary files /dev/null and b/tools/contributing/forkrepository.png differ diff --git a/tools/contributing/gulpbuild.png b/tools/contributing/gulpbuild.png new file mode 100644 index 0000000000..333bfe2349 Binary files /dev/null and b/tools/contributing/gulpbuild.png differ