Merge remote-tracking branch 'origin/dev-v7' into temp8

# Conflicts:
#	.editorconfig
#	.gitignore
#	src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs
#	src/Umbraco.Core/Persistence/Repositories/UserRepository.cs
#	src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js
#	src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-era-button.less
#	src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.html
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/contenttypeeditor/compositions/compositions.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/contenttypeeditor/compositions/compositions.html
#	src/Umbraco.Web.UI.Client/src/views/content/content.delete.controller.js
#	src/Umbraco.Web.UI.Client/src/views/content/content.restore.controller.js
#	src/Umbraco.Web.UI.Client/src/views/content/restore.html
#	src/Umbraco.Web.UI.Client/src/views/dashboard/developer/healthcheck.html
#	src/Umbraco.Web.UI.Client/src/views/media/media.move.controller.js
#	src/Umbraco.Web.UI.Client/src/views/media/move.html
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/layoutconfig.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowconfig.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html
#	src/Umbraco.Web.UI/Umbraco/config/lang/da.xml
#	src/Umbraco.Web.UI/config/umbracoSettings.Release.config
#	src/Umbraco.Web.UI/umbraco/config/lang/en.xml
#	src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml
#	src/Umbraco.Web/Controllers/UmbLoginController.cs
#	src/Umbraco.Web/Controllers/UmbLoginStatusController.cs
#	src/Umbraco.Web/Controllers/UmbProfileController.cs
#	src/Umbraco.Web/Controllers/UmbRegisterController.cs
#	src/Umbraco.Web/Editors/ContentController.cs
#	src/Umbraco.Web/Editors/ContentTypeControllerBase.cs
#	src/Umbraco.Web/HtmlHelperRenderExtensions.cs
#	src/Umbraco.Web/Trees/ContentTreeController.cs
#	src/Umbraco.Web/Trees/MediaTreeController.cs
#	src/Umbraco.Web/umbraco.presentation/umbraco/create/XsltTasks.cs
#	src/Umbraco.Web/umbraco.presentation/umbraco/create/xslt.ascx.cs
#	src/Umbraco.Web/umbraco.presentation/umbraco/developer/Xslt/editXslt.aspx.cs
#	src/Umbraco.Web/umbraco.presentation/umbraco/webservices/codeEditorSave.asmx.cs
This commit is contained in:
Shannon
2018-12-20 16:58:01 +11:00
25 changed files with 123 additions and 51 deletions

View File

@@ -34,3 +34,4 @@ dotnet_naming_style.prefix_underscore.required_prefix = _
csharp_style_var_for_built_in_types = true:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
csharp_style_var_elsewhere = true:suggestion
csharp_prefer_braces = false : none

View File

@@ -82,7 +82,6 @@ You can get in touch with [the PR team](#the-pr-team) in multiple ways, we love
- 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
- We're also [active in the Gitter chatroom](https://gitter.im/umbraco/Umbraco-CMS)
## Code of Conduct

1
.gitignore vendored
View File

@@ -107,6 +107,7 @@ src/Umbraco.Web.UI.Client/[Bb]uild/[Bb]elle/
src/Umbraco.Web.UI/[Uu]ser[Cc]ontrols/
src/Umbraco.Web.UI.Client/src/[Ll]ess/*.css
src/Umbraco.Web.UI.Client/vwd.webinfo
src/Umbraco.Web.UI/App_Plugins/*
src/*.psess

View File

@@ -262,7 +262,7 @@ Use this directive to construct a header inside the main editor window.
icon: "=",
hideIcon: "@",
alias: "=",
hideAlias: "@",
hideAlias: "=",
description: "=",
hideDescription: "@",
descriptionLocked: "@",

View File

@@ -242,4 +242,5 @@
.umb-healthcheck-group__details-status-action-description {
margin-top: 5px;
font-size: 12px;
padding-left: 165px;
}

View File

@@ -15,10 +15,11 @@
<div class="alert alert-success">
<localize key="notify_notificationsSavedFor"></localize><strong> {{currentNode.name}}</strong>
</div>
<button class="btn btn-primary" ng-click="vm.cancel()"><localize key="general_ok">Ok</localize></button>
</div>
<div ng-cloak>
<div ng-hide="vm.saveSuccces || vm.saveError" ng-cloak>
<div class="block-form" ng-show="!vm.loading">
<h5><localize key="notify_notifySet">Set your notification for</localize> {{ currentNode.name }}</h5>
<localize key="notify_notifySet">Set your notification for</localize> <strong>{{ currentNode.name }}</strong>
<umb-control-group>
<umb-permission ng-repeat="option in vm.notifyOptions"
name="option.name"
@@ -31,7 +32,7 @@
</form>
</div>
</div>
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar">
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar" ng-hide="vm.saveSuccces || vm.saveError">
<umb-button label-key="general_cancel"
action="vm.cancel()"
type="button"
@@ -40,6 +41,7 @@
<umb-button label-key="buttons_save"
type="button"
action="vm.save(vm.notifyOptions)"
state="vm.saveState"
button-style="success">
</umb-button>
</div>

View File

@@ -25,16 +25,35 @@
<div ng-hide="success">
<div ng-hide="miniListView">
<umb-tree
section="media"
hideheader="{{treeModel.hideHeader}}"
hideoptions="true"
isdialog="true"
<umb-tree-search-box
hide-search-callback="hideSearch"
search-callback="onSearchResults"
search-from-id="{{searchInfo.searchFromId}}"
search-from-name="{{searchInfo.searchFromName}}"
show-search="{{searchInfo.showSearch}}"
section="media">
</umb-tree-search-box>
<br />
<umb-tree-search-results
ng-if="searchInfo.showSearch"
results="searchInfo.results"
select-result-callback="selectResult">
</umb-tree-search-results>
<div ng-hide="searchInfo.showSearch">
<umb-tree
section="media"
hideheader="{{treeModel.hideHeader}}"
hideoptions="true"
isdialog="true"
api="dialogTreeApi"
on-init="onTreeInit()"
enablelistviewexpand="true"
enablecheckboxes="true">
</umb-tree>
enablelistviewexpand="true"
enablecheckboxes="true">
</umb-tree>
</div>
</div>
<umb-mini-list-view

View File

@@ -24,16 +24,6 @@ angular.module("umbraco")
return ((spans / $scope.columns) * 100).toFixed(8);
};
$scope.toggleCollection = function(collection, toggle){
if(toggle){
collection = [];
}else{
collection = null;
}
};
/****************
Section
*****************/
@@ -47,8 +37,18 @@ angular.module("umbraco")
}
$scope.currentSection = section;
$scope.currentSection.allowAll = section.allowAll || !section.allowed || !section.allowed.length;
};
$scope.toggleAllowed = function (section) {
if (section.allowed) {
delete section.allowed;
}
else {
section.allowed = [];
}
}
$scope.deleteSection = function(section, template) {
if ($scope.currentSection === section) {
$scope.currentSection = undefined;

View File

@@ -61,8 +61,7 @@
<input type="checkbox"
ng-model="currentSection.allowAll"
style="float: left; margin-right: 10px;"
ng-checked="currentSection.allowed === undefined"
ng-change="toggleCollection(currentSection.allowed, currentSection.allowAll)" />
ng-change="toggleAllowed(currentSection)" />
<localize key="grid_allowAllRowConfigurations"/>
</label>
</li>

View File

@@ -22,16 +22,6 @@ function RowConfigController($scope) {
return ((spans / $scope.columns) * 100).toFixed(8);
};
$scope.toggleCollection = function(collection, toggle) {
if (toggle) {
collection = [];
}
else {
collection = null;
}
};
/****************
area
*****************/
@@ -55,9 +45,19 @@ function RowConfigController($scope) {
row.areas.push(cell);
}
$scope.currentCell = cell;
$scope.currentCell.allowAll = cell.allowAll || !cell.allowed || !cell.allowed.length;
}
};
$scope.toggleAllowed = function (cell) {
if (cell.allowed) {
delete cell.allowed;
}
else {
cell.allowed = [];
}
}
$scope.deleteArea = function (cell, row) {
if ($scope.currentCell === cell) {
$scope.currentCell = undefined;

View File

@@ -72,8 +72,7 @@
<label>
<input type="checkbox"
ng-model="currentCell.allowAll"
ng-checked="currentCell.allowed === undefined"
ng-change="toggleCollection(currentCell.allowed, currentCell.allowAll)" />
ng-change="toggleAllowed(currentCell)" />
<localize key="grid_allowAllEditors"/>
</label>
</li>

View File

@@ -701,13 +701,17 @@ function listViewController($scope, $routeParams, $injector, $timeout, currentUs
}
getContentTypesCallback(id).then(function (listViewAllowedTypes) {
var blueprints = false;
$scope.listViewAllowedTypes = listViewAllowedTypes;
angular.forEach(listViewAllowedTypes, function (allowedType) {
angular.forEach(allowedType.blueprints, function (value, key) {
var blueprints = false;
_.each(listViewAllowedTypes, function (allowedType) {
if (_.isEmpty(allowedType.blueprints)) {
// this helps the view understand that there are no blueprints available
allowedType.blueprints = null;
}
else {
blueprints = true;
});
}
});
if (listViewAllowedTypes.length === 1 && blueprints === false) {

View File

@@ -46,7 +46,7 @@
<umb-dropdown-item ng-repeat="contentType in listViewAllowedTypes track by contentType.key | orderBy:'name':false">
<a ng-click="createBlank(entityType,contentType.alias)" prevent-default ng-href="">
<i class="{{::contentType.icon}}"></i>
{{::contentType.name}} <span ng-show="contentType.blueprints && contentType.blueprints.length != 0" style="text-transform: lowercase;">(<localize key="blueprints_blankBlueprint">blank</localize>)</span>
{{::contentType.name}} <span ng-show="contentType.blueprints" style="text-transform: lowercase;">(<localize key="blueprints_blankBlueprint">blank</localize>)</span>
</a>
<a href="" ng-repeat="(key, value) in contentType.blueprints track by key" ng-click="createFromBlueprint(entityType,contentType.alias , key)" prevent-default>
&nbsp;&nbsp;<i class="{{::contentType.icon}}"></i>

View File

@@ -1379,7 +1379,7 @@ Mange hilsner fra Umbraco robotten
<key alias="userInvited">er blevet inviteret</key>
<key alias="userInvitedSuccessHelp">En invitation er blevet sendt til den nye bruger med oplysninger om, hvordan man logger ind i Umbraco.</key>
<key alias="userinviteWelcomeMessage">Hej og velkommen til Umbraco! På bare 1 minut vil du være klar til at komme i gang, vi skal bare have dig til at oprette en adgangskode og tilføje et billede til din avatar.</key>
<key alias="userinviteAvatarMessage">Upload et billede for at gøre det nemt for andre brugere at genkende dig.</key>
<key alias="userinviteAvatarMessage">Hvis du uploader et billede af dig selv, gør du det nemt for andre brugere at genkende dig. Klik på cirklen ovenfor for at uploade et billede.</key>
<key alias="writer">Forfatter</key>
<key alias="change">Skift</key>
<key alias="yourProfile">Din profil</key>
@@ -1434,8 +1434,8 @@ Mange hilsner fra Umbraco robotten
<area alias="recycleBin">
<key alias="contentTrashed">Slettet indhold med Id: {0} Relateret til original "parent" med id: {1}</key>
<key alias="mediaTrashed">Slettet medie med Id: {0} relateret til original "parent" / mappe med id: {1}</key>
<key alias="itemCannotBeRestored">Kan ikke automatisk genoprette dette dokument/medie</key>
<key alias="noRestoreRelation">Der findes ikke nogen "Genopret" relation for dette dokument/medie. Brug "Flyt" muligheden fra menuen for at flytte det manuelt.</key>
<key alias="restoreUnderRecycled">Det dokument/medie du ønsker at genoprette under ('%0%') er i skraldespanden. Brug "Flyt" muligheden fra menuen for at flytte det manuelt.</key>
<key alias="itemCannotBeRestored">Kan ikke automatisk genoprette dette element</key>
<key alias="itemCannotBeRestoredHelpText">Der er ikke nogen placering hvor dette element automatisk kan genoprettes. Du kan flytte elementet manuelt i træet nedenfor.</key>
<key alias="wasRestored">blev genoprettet under</key>
</area>
</language>

View File

@@ -32,6 +32,7 @@
<notifications>
<!-- the email that should be used as from mail when umbraco sends a notification -->
<!-- you can add a display name to the email like thist: <email>Your display name here &lt;your@email.here&gt;</email> -->
<email>your@email.here</email>
</notifications>

View File

@@ -48,6 +48,7 @@
</errors>
<notifications>
<!-- the email that should be used as from mail when umbraco sends a notification -->
<!-- you can add a display name to the email like this: <email>Your display name here &lt;your@email.here&gt;</email> -->
<email>your@email.here</email>
</notifications>

View File

@@ -8,6 +8,7 @@ namespace Umbraco.Web.Controllers
public class UmbLoginController : SurfaceController
{
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult HandleLogin([Bind(Prefix = "loginModel")]LoginModel model)
{
if (ModelState.IsValid == false)

View File

@@ -10,6 +10,7 @@ namespace Umbraco.Web.Controllers
public class UmbLoginStatusController : SurfaceController
{
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult HandleLogout([Bind(Prefix = "logoutModel")]PostRedirectModel model)
{
if (ModelState.IsValid == false)

View File

@@ -11,6 +11,7 @@ namespace Umbraco.Web.Controllers
public class UmbProfileController : SurfaceController
{
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult HandleUpdateProfile([Bind(Prefix = "profileModel")] ProfileModel model)
{
var provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider();

View File

@@ -10,6 +10,7 @@ namespace Umbraco.Web.Controllers
public class UmbRegisterController : SurfaceController
{
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult HandleRegisterMember([Bind(Prefix = "registerModel")]RegisterModel model)
{
if (ModelState.IsValid == false)

View File

@@ -354,6 +354,9 @@ namespace Umbraco.Web.Editors
var emptyContent = Services.ContentService.Create("", parentId, contentType.Alias, Security.GetUserId().ResultOr(0));
var mapped = MapToDisplay(emptyContent);
// translate the content type name if applicable
mapped.ContentTypeName = Services.TextService.UmbracoDictionaryTranslate(mapped.ContentTypeName);
mapped.DocumentType.Name = Services.TextService.UmbracoDictionaryTranslate(mapped.DocumentType.Name);
//remove the listview app if it exists
mapped.ContentApps = mapped.ContentApps.Where(x => x.Alias != "umbListView").ToList();

View File

@@ -89,6 +89,25 @@ namespace Umbraco.Web.Editors
var availableCompositions = Services.ContentTypeService.GetAvailableCompositeContentTypes(source, allContentTypes, filterContentTypes, filterPropertyTypes);
Func<IContentTypeComposition, IEnumerable<EntityContainer>> getEntityContainers = contentType =>
{
if (contentType == null)
{
return null;
}
switch (type)
{
case UmbracoObjectTypes.DocumentType:
return Services.ContentTypeService.GetContentTypeContainers(contentType as IContentType);
case UmbracoObjectTypes.MediaType:
return Services.ContentTypeService.GetMediaTypeContainers(contentType as IMediaType);
case UmbracoObjectTypes.MemberType:
return new EntityContainer[0];
default:
throw new ArgumentOutOfRangeException("The entity type was not a content type");
}
};
var currCompositions = source == null ? new IContentTypeComposition[] { } : source.ContentTypeComposition.ToArray();
var compAliases = currCompositions.Select(x => x.Alias).ToArray();
var ancestors = availableCompositions.Ancestors.Select(x => x.Alias);
@@ -97,9 +116,6 @@ namespace Umbraco.Web.Editors
.Select(x => new Tuple<EntityBasic, bool>(Mapper.Map<IContentTypeComposition, EntityBasic>(x.Composition), x.Allowed))
.Select(x =>
{
//translate the name
x.Item1.Name = TranslateItem(x.Item1.Name);
//we need to ensure that the item is enabled if it is already selected
// but do not allow it if it is any of the ancestors
if (compAliases.Contains(x.Item1.Alias) && ancestors.Contains(x.Item1.Alias) == false)
@@ -108,6 +124,14 @@ namespace Umbraco.Web.Editors
x = new Tuple<EntityBasic, bool>(x.Item1, true);
}
//translate the name
x.Item1.Name = TranslateItem(x.Item1.Name);
var contentType = allContentTypes.FirstOrDefault(c => c.Key == x.Item1.Key);
var containers = getEntityContainers(contentType)?.ToArray();
var containerPath = $"/{(containers != null && containers.Any() ? $"{string.Join("/", containers.Select(c => c.Name))}/" : null)}";
x.Item1.AdditionalData["containerPath"] = containerPath;
return x;
})
.ToList();

View File

@@ -4,6 +4,7 @@ using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Helpers;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.Routing;
@@ -222,6 +223,7 @@ namespace Umbraco.Web
{
_viewContext = viewContext;
_method = method;
_controllerName = controllerName;
_encryptedString = UmbracoHelper.CreateEncryptedRouteString(controllerName, controllerAction, area, additionalRouteVals);
}
@@ -229,6 +231,7 @@ namespace Umbraco.Web
private readonly FormMethod _method;
private bool _disposed;
private readonly string _encryptedString;
private readonly string _controllerName;
protected override void Dispose(bool disposing)
{
@@ -236,6 +239,16 @@ namespace Umbraco.Web
return;
this._disposed = true;
//Detect if the call is targeting UmbRegisterController/UmbProfileController/UmbLoginStatusController/UmbLoginController and if it is we automatically output a AntiForgeryToken()
// We have a controllerName and area so we can match
if (_controllerName == "UmbRegister"
|| _controllerName == "UmbProfile"
|| _controllerName == "UmbLoginStatus"
|| _controllerName == "UmbLogin")
{
_viewContext.Writer.Write(AntiForgery.GetHtml().ToString());
}
//write out the hidden surface form routes
_viewContext.Writer.Write("<input name='ufprt' type='hidden' value='" + _encryptedString + "' />");

View File

@@ -263,6 +263,7 @@ namespace Umbraco.Web.Trees
{
var menu = new MenuItemCollection();
menu.Items.Add<ActionRestore>(Services.TextService, opensDialog: true);
menu.Items.Add<ActionMove>(Services.TextService, opensDialog: true);
menu.Items.Add<ActionDelete>(Services.TextService, opensDialog: true);
menu.Items.Add(new RefreshNode(Services.TextService, true));